776 lines
24 KiB
Java
776 lines
24 KiB
Java
/*
|
|
* Copyright (C) 2011 The Guava Authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.google.common.math;
|
|
|
|
import static com.google.common.math.MathTesting.ALL_INTEGER_CANDIDATES;
|
|
import static com.google.common.math.MathTesting.ALL_ROUNDING_MODES;
|
|
import static com.google.common.math.MathTesting.ALL_SAFE_ROUNDING_MODES;
|
|
import static com.google.common.math.MathTesting.EXPONENTS;
|
|
import static com.google.common.math.MathTesting.NEGATIVE_INTEGER_CANDIDATES;
|
|
import static com.google.common.math.MathTesting.NONZERO_INTEGER_CANDIDATES;
|
|
import static com.google.common.math.MathTesting.POSITIVE_INTEGER_CANDIDATES;
|
|
import static com.google.common.math.TestPlatform.intsCanGoOutOfRange;
|
|
import static java.math.BigInteger.valueOf;
|
|
import static java.math.RoundingMode.FLOOR;
|
|
import static java.math.RoundingMode.UNNECESSARY;
|
|
|
|
import com.google.common.annotations.GwtCompatible;
|
|
import com.google.common.annotations.GwtIncompatible;
|
|
import com.google.common.testing.NullPointerTester;
|
|
import java.math.BigDecimal;
|
|
import java.math.BigInteger;
|
|
import java.math.RoundingMode;
|
|
import java.util.Random;
|
|
import junit.framework.TestCase;
|
|
|
|
/**
|
|
* Tests for {@link IntMath}.
|
|
*
|
|
* @author Louis Wasserman
|
|
*/
|
|
@GwtCompatible(emulated = true)
|
|
public class IntMathTest extends TestCase {
|
|
public void testMaxSignedPowerOfTwo() {
|
|
assertTrue(IntMath.isPowerOfTwo(IntMath.MAX_SIGNED_POWER_OF_TWO));
|
|
|
|
// Extra work required to make GWT happy.
|
|
long value = IntMath.MAX_SIGNED_POWER_OF_TWO * 2L;
|
|
assertFalse(IntMath.isPowerOfTwo((int) value));
|
|
}
|
|
|
|
public void testCeilingPowerOfTwo() {
|
|
for (int x : POSITIVE_INTEGER_CANDIDATES) {
|
|
BigInteger expectedResult = BigIntegerMath.ceilingPowerOfTwo(BigInteger.valueOf(x));
|
|
if (fitsInInt(expectedResult)) {
|
|
assertEquals(expectedResult.intValue(), IntMath.ceilingPowerOfTwo(x));
|
|
} else {
|
|
try {
|
|
IntMath.ceilingPowerOfTwo(x);
|
|
fail("Expected ArithmeticException");
|
|
} catch (ArithmeticException expected) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void testFloorPowerOfTwo() {
|
|
for (int x : POSITIVE_INTEGER_CANDIDATES) {
|
|
BigInteger expectedResult = BigIntegerMath.floorPowerOfTwo(BigInteger.valueOf(x));
|
|
assertEquals(expectedResult.intValue(), IntMath.floorPowerOfTwo(x));
|
|
}
|
|
}
|
|
|
|
public void testCeilingPowerOfTwoNegative() {
|
|
for (int x : NEGATIVE_INTEGER_CANDIDATES) {
|
|
try {
|
|
IntMath.ceilingPowerOfTwo(x);
|
|
fail("Expected IllegalArgumentException");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
}
|
|
}
|
|
|
|
public void testFloorPowerOfTwoNegative() {
|
|
for (int x : NEGATIVE_INTEGER_CANDIDATES) {
|
|
try {
|
|
IntMath.floorPowerOfTwo(x);
|
|
fail("Expected IllegalArgumentException");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
}
|
|
}
|
|
|
|
public void testCeilingPowerOfTwoZero() {
|
|
try {
|
|
IntMath.ceilingPowerOfTwo(0);
|
|
fail("Expected IllegalArgumentException");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
}
|
|
|
|
public void testFloorPowerOfTwoZero() {
|
|
try {
|
|
IntMath.floorPowerOfTwo(0);
|
|
fail("Expected IllegalArgumentException");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
}
|
|
|
|
@GwtIncompatible // BigIntegerMath // TODO(cpovirk): GWT-enable BigIntegerMath
|
|
public void testConstantMaxPowerOfSqrt2Unsigned() {
|
|
assertEquals(
|
|
/*expected=*/ BigIntegerMath.sqrt(BigInteger.ZERO.setBit(2 * Integer.SIZE - 1), FLOOR)
|
|
.intValue(),
|
|
/*actual=*/ IntMath.MAX_POWER_OF_SQRT2_UNSIGNED);
|
|
}
|
|
|
|
@GwtIncompatible // pow()
|
|
public void testConstantsPowersOf10() {
|
|
for (int i = 0; i < IntMath.powersOf10.length - 1; i++) {
|
|
assertEquals(IntMath.pow(10, i), IntMath.powersOf10[i]);
|
|
}
|
|
}
|
|
|
|
@GwtIncompatible // BigIntegerMath // TODO(cpovirk): GWT-enable BigIntegerMath
|
|
public void testMaxLog10ForLeadingZeros() {
|
|
for (int i = 0; i < Integer.SIZE; i++) {
|
|
assertEquals(
|
|
BigIntegerMath.log10(BigInteger.ONE.shiftLeft(Integer.SIZE - i), FLOOR),
|
|
IntMath.maxLog10ForLeadingZeros[i]);
|
|
}
|
|
}
|
|
|
|
@GwtIncompatible // BigIntegerMath // TODO(cpovirk): GWT-enable BigIntegerMath
|
|
public void testConstantsHalfPowersOf10() {
|
|
for (int i = 0; i < IntMath.halfPowersOf10.length; i++) {
|
|
assert IntMath.halfPowersOf10[i]
|
|
== Math.min(
|
|
Integer.MAX_VALUE,
|
|
BigIntegerMath.sqrt(BigInteger.TEN.pow(2 * i + 1), FLOOR).longValue());
|
|
}
|
|
}
|
|
|
|
public void testConstantsBiggestBinomials() {
|
|
for (int k = 0; k < IntMath.biggestBinomials.length; k++) {
|
|
assertTrue(fitsInInt(BigIntegerMath.binomial(IntMath.biggestBinomials[k], k)));
|
|
assertTrue(
|
|
IntMath.biggestBinomials[k] == Integer.MAX_VALUE
|
|
|| !fitsInInt(BigIntegerMath.binomial(IntMath.biggestBinomials[k] + 1, k)));
|
|
// In the first case, any int is valid; in the second, we want to test that the next-bigger
|
|
// int overflows.
|
|
}
|
|
assertFalse(
|
|
fitsInInt(
|
|
BigIntegerMath.binomial(
|
|
2 * IntMath.biggestBinomials.length, IntMath.biggestBinomials.length)));
|
|
}
|
|
|
|
@GwtIncompatible // sqrt
|
|
public void testPowersSqrtMaxInt() {
|
|
assertEquals(
|
|
/*expected=*/ IntMath.sqrt(Integer.MAX_VALUE, FLOOR),
|
|
/*actual=*/ IntMath.FLOOR_SQRT_MAX_INT);
|
|
}
|
|
|
|
@AndroidIncompatible // presumably slow
|
|
public void testLessThanBranchFree() {
|
|
for (int x : ALL_INTEGER_CANDIDATES) {
|
|
for (int y : ALL_INTEGER_CANDIDATES) {
|
|
if (LongMath.fitsInInt((long) x - y)) {
|
|
int expected = (x < y) ? 1 : 0;
|
|
int actual = IntMath.lessThanBranchFree(x, y);
|
|
assertEquals(expected, actual);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@GwtIncompatible // java.math.BigInteger
|
|
public void testIsPowerOfTwo() {
|
|
for (int x : ALL_INTEGER_CANDIDATES) {
|
|
// Checks for a single bit set.
|
|
BigInteger bigX = BigInteger.valueOf(x);
|
|
boolean expected = (bigX.signum() > 0) && (bigX.bitCount() == 1);
|
|
assertEquals(expected, IntMath.isPowerOfTwo(x));
|
|
}
|
|
}
|
|
|
|
public void testLog2ZeroAlwaysThrows() {
|
|
for (RoundingMode mode : ALL_ROUNDING_MODES) {
|
|
try {
|
|
IntMath.log2(0, mode);
|
|
fail("Expected IllegalArgumentException");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
}
|
|
}
|
|
|
|
public void testLog2NegativeAlwaysThrows() {
|
|
for (int x : NEGATIVE_INTEGER_CANDIDATES) {
|
|
for (RoundingMode mode : ALL_ROUNDING_MODES) {
|
|
try {
|
|
IntMath.log2(x, mode);
|
|
fail("Expected IllegalArgumentException");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Relies on the correctness of BigIntegrerMath.log2 for all modes except UNNECESSARY.
|
|
public void testLog2MatchesBigInteger() {
|
|
for (int x : POSITIVE_INTEGER_CANDIDATES) {
|
|
for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
|
|
assertEquals(BigIntegerMath.log2(valueOf(x), mode), IntMath.log2(x, mode));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Relies on the correctness of isPowerOfTwo(int).
|
|
public void testLog2Exact() {
|
|
for (int x : POSITIVE_INTEGER_CANDIDATES) {
|
|
// We only expect an exception if x was not a power of 2.
|
|
boolean isPowerOf2 = IntMath.isPowerOfTwo(x);
|
|
try {
|
|
assertEquals(x, 1 << IntMath.log2(x, UNNECESSARY));
|
|
assertTrue(isPowerOf2);
|
|
} catch (ArithmeticException e) {
|
|
assertFalse(isPowerOf2);
|
|
}
|
|
}
|
|
}
|
|
|
|
@GwtIncompatible // log10
|
|
public void testLog10ZeroAlwaysThrows() {
|
|
for (RoundingMode mode : ALL_ROUNDING_MODES) {
|
|
try {
|
|
IntMath.log10(0, mode);
|
|
fail("Expected IllegalArgumentException");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
}
|
|
}
|
|
|
|
@GwtIncompatible // log10
|
|
public void testLog10NegativeAlwaysThrows() {
|
|
for (int x : NEGATIVE_INTEGER_CANDIDATES) {
|
|
for (RoundingMode mode : ALL_ROUNDING_MODES) {
|
|
try {
|
|
IntMath.log10(x, mode);
|
|
fail("Expected IllegalArgumentException");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Relies on the correctness of BigIntegerMath.log10 for all modes except UNNECESSARY.
|
|
@GwtIncompatible // BigIntegerMath // TODO(cpovirk): GWT-enable BigIntegerMath
|
|
public void testLog10MatchesBigInteger() {
|
|
for (int x : POSITIVE_INTEGER_CANDIDATES) {
|
|
for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
|
|
// The BigInteger implementation is tested separately, use it as the reference.
|
|
assertEquals(BigIntegerMath.log10(valueOf(x), mode), IntMath.log10(x, mode));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Relies on the correctness of log10(int, FLOOR) and of pow(int, int).
|
|
@GwtIncompatible // pow()
|
|
public void testLog10Exact() {
|
|
for (int x : POSITIVE_INTEGER_CANDIDATES) {
|
|
int floor = IntMath.log10(x, FLOOR);
|
|
boolean expectSuccess = IntMath.pow(10, floor) == x;
|
|
try {
|
|
assertEquals(floor, IntMath.log10(x, UNNECESSARY));
|
|
assertTrue(expectSuccess);
|
|
} catch (ArithmeticException e) {
|
|
assertFalse(expectSuccess);
|
|
}
|
|
}
|
|
}
|
|
|
|
@GwtIncompatible // log10
|
|
public void testLog10TrivialOnPowerOfTen() {
|
|
int x = 1000000;
|
|
for (RoundingMode mode : ALL_ROUNDING_MODES) {
|
|
assertEquals(6, IntMath.log10(x, mode));
|
|
}
|
|
}
|
|
|
|
// Simple test to cover sqrt(0) for all types and all modes.
|
|
@GwtIncompatible // sqrt
|
|
public void testSqrtZeroAlwaysZero() {
|
|
for (RoundingMode mode : ALL_ROUNDING_MODES) {
|
|
assertEquals(0, IntMath.sqrt(0, mode));
|
|
}
|
|
}
|
|
|
|
@GwtIncompatible // sqrt
|
|
public void testSqrtNegativeAlwaysThrows() {
|
|
for (int x : NEGATIVE_INTEGER_CANDIDATES) {
|
|
for (RoundingMode mode : RoundingMode.values()) {
|
|
try {
|
|
IntMath.sqrt(x, mode);
|
|
fail("Expected IllegalArgumentException");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Relies on the correctness of BigIntegerMath.sqrt for all modes except UNNECESSARY. */
|
|
@GwtIncompatible // BigIntegerMath // TODO(cpovirk): GWT-enable BigIntegerMath
|
|
public void testSqrtMatchesBigInteger() {
|
|
for (int x : POSITIVE_INTEGER_CANDIDATES) {
|
|
for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
|
|
// The BigInteger implementation is tested separately, use it as the reference.
|
|
// Promote the int value (rather than using intValue() on the expected value) to avoid
|
|
// any risk of truncation which could lead to a false positive.
|
|
assertEquals(BigIntegerMath.sqrt(valueOf(x), mode), valueOf(IntMath.sqrt(x, mode)));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Relies on the correctness of sqrt(int, FLOOR). */
|
|
@GwtIncompatible // sqrt
|
|
public void testSqrtExactMatchesFloorOrThrows() {
|
|
for (int x : POSITIVE_INTEGER_CANDIDATES) {
|
|
int floor = IntMath.sqrt(x, FLOOR);
|
|
// We only expect an exception if x was not a perfect square.
|
|
boolean isPerfectSquare = (floor * floor == x);
|
|
try {
|
|
assertEquals(floor, IntMath.sqrt(x, UNNECESSARY));
|
|
assertTrue(isPerfectSquare);
|
|
} catch (ArithmeticException e) {
|
|
assertFalse(isPerfectSquare);
|
|
}
|
|
}
|
|
}
|
|
|
|
@GwtIncompatible // 2147483646^2 expected=4
|
|
public void testPow() {
|
|
for (int i : ALL_INTEGER_CANDIDATES) {
|
|
for (int pow : EXPONENTS) {
|
|
assertEquals(i + "^" + pow, BigInteger.valueOf(i).pow(pow).intValue(), IntMath.pow(i, pow));
|
|
}
|
|
}
|
|
}
|
|
|
|
@AndroidIncompatible // slow
|
|
public void testDivNonZero() {
|
|
for (int p : NONZERO_INTEGER_CANDIDATES) {
|
|
for (int q : NONZERO_INTEGER_CANDIDATES) {
|
|
for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
|
|
// Skip some tests that fail due to GWT's non-compliant int implementation.
|
|
// TODO(cpovirk): does this test fail for only some rounding modes or for all?
|
|
if (p == -2147483648 && q == -1 && intsCanGoOutOfRange()) {
|
|
continue;
|
|
}
|
|
int expected =
|
|
new BigDecimal(valueOf(p)).divide(new BigDecimal(valueOf(q)), 0, mode).intValue();
|
|
assertEquals(p + "/" + q, force32(expected), IntMath.divide(p, q, mode));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@AndroidIncompatible // presumably slow
|
|
public void testDivNonZeroExact() {
|
|
for (int p : NONZERO_INTEGER_CANDIDATES) {
|
|
for (int q : NONZERO_INTEGER_CANDIDATES) {
|
|
// Skip some tests that fail due to GWT's non-compliant int implementation.
|
|
if (p == -2147483648 && q == -1 && intsCanGoOutOfRange()) {
|
|
continue;
|
|
}
|
|
boolean dividesEvenly = (p % q) == 0;
|
|
try {
|
|
assertEquals(p + "/" + q, p, IntMath.divide(p, q, UNNECESSARY) * q);
|
|
assertTrue(p + "/" + q + " not expected to divide evenly", dividesEvenly);
|
|
} catch (ArithmeticException e) {
|
|
assertFalse(p + "/" + q + " expected to divide evenly", dividesEvenly);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void testZeroDivIsAlwaysZero() {
|
|
for (int q : NONZERO_INTEGER_CANDIDATES) {
|
|
for (RoundingMode mode : ALL_ROUNDING_MODES) {
|
|
assertEquals(0, IntMath.divide(0, q, mode));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void testDivByZeroAlwaysFails() {
|
|
for (int p : ALL_INTEGER_CANDIDATES) {
|
|
for (RoundingMode mode : ALL_ROUNDING_MODES) {
|
|
try {
|
|
IntMath.divide(p, 0, mode);
|
|
fail("Expected ArithmeticException");
|
|
} catch (ArithmeticException expected) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void testMod() {
|
|
for (int x : ALL_INTEGER_CANDIDATES) {
|
|
for (int m : POSITIVE_INTEGER_CANDIDATES) {
|
|
assertEquals(valueOf(x).mod(valueOf(m)).intValue(), IntMath.mod(x, m));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void testModNegativeModulusFails() {
|
|
for (int x : POSITIVE_INTEGER_CANDIDATES) {
|
|
for (int m : NEGATIVE_INTEGER_CANDIDATES) {
|
|
try {
|
|
IntMath.mod(x, m);
|
|
fail("Expected ArithmeticException");
|
|
} catch (ArithmeticException expected) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void testModZeroModulusFails() {
|
|
for (int x : ALL_INTEGER_CANDIDATES) {
|
|
try {
|
|
IntMath.mod(x, 0);
|
|
fail("Expected ArithmeticException");
|
|
} catch (ArithmeticException expected) {
|
|
}
|
|
}
|
|
}
|
|
|
|
public void testGCD() {
|
|
for (int a : POSITIVE_INTEGER_CANDIDATES) {
|
|
for (int b : POSITIVE_INTEGER_CANDIDATES) {
|
|
assertEquals(valueOf(a).gcd(valueOf(b)), valueOf(IntMath.gcd(a, b)));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void testGCDZero() {
|
|
for (int a : POSITIVE_INTEGER_CANDIDATES) {
|
|
assertEquals(a, IntMath.gcd(a, 0));
|
|
assertEquals(a, IntMath.gcd(0, a));
|
|
}
|
|
assertEquals(0, IntMath.gcd(0, 0));
|
|
}
|
|
|
|
public void testGCDNegativePositiveThrows() {
|
|
for (int a : NEGATIVE_INTEGER_CANDIDATES) {
|
|
try {
|
|
IntMath.gcd(a, 3);
|
|
fail("Expected IllegalArgumentException");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
try {
|
|
IntMath.gcd(3, a);
|
|
fail("Expected IllegalArgumentException");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
}
|
|
}
|
|
|
|
public void testGCDNegativeZeroThrows() {
|
|
for (int a : NEGATIVE_INTEGER_CANDIDATES) {
|
|
try {
|
|
IntMath.gcd(a, 0);
|
|
fail("Expected IllegalArgumentException");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
try {
|
|
IntMath.gcd(0, a);
|
|
fail("Expected IllegalArgumentException");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
}
|
|
}
|
|
|
|
@AndroidIncompatible // slow
|
|
public void testCheckedAdd() {
|
|
for (int a : ALL_INTEGER_CANDIDATES) {
|
|
for (int b : ALL_INTEGER_CANDIDATES) {
|
|
BigInteger expectedResult = valueOf(a).add(valueOf(b));
|
|
boolean expectedSuccess = fitsInInt(expectedResult);
|
|
try {
|
|
assertEquals(a + b, IntMath.checkedAdd(a, b));
|
|
assertTrue(expectedSuccess);
|
|
} catch (ArithmeticException e) {
|
|
assertFalse(expectedSuccess);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@AndroidIncompatible // slow
|
|
public void testCheckedSubtract() {
|
|
for (int a : ALL_INTEGER_CANDIDATES) {
|
|
for (int b : ALL_INTEGER_CANDIDATES) {
|
|
BigInteger expectedResult = valueOf(a).subtract(valueOf(b));
|
|
boolean expectedSuccess = fitsInInt(expectedResult);
|
|
try {
|
|
assertEquals(a - b, IntMath.checkedSubtract(a, b));
|
|
assertTrue(expectedSuccess);
|
|
} catch (ArithmeticException e) {
|
|
assertFalse(expectedSuccess);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@AndroidIncompatible // presumably slow
|
|
public void testCheckedMultiply() {
|
|
for (int a : ALL_INTEGER_CANDIDATES) {
|
|
for (int b : ALL_INTEGER_CANDIDATES) {
|
|
BigInteger expectedResult = valueOf(a).multiply(valueOf(b));
|
|
boolean expectedSuccess = fitsInInt(expectedResult);
|
|
try {
|
|
assertEquals(a * b, IntMath.checkedMultiply(a, b));
|
|
assertTrue(expectedSuccess);
|
|
} catch (ArithmeticException e) {
|
|
assertFalse(expectedSuccess);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void testCheckedPow() {
|
|
for (int b : ALL_INTEGER_CANDIDATES) {
|
|
for (int k : EXPONENTS) {
|
|
BigInteger expectedResult = valueOf(b).pow(k);
|
|
boolean expectedSuccess = fitsInInt(expectedResult);
|
|
try {
|
|
assertEquals(b + "^" + k, force32(expectedResult.intValue()), IntMath.checkedPow(b, k));
|
|
assertTrue(b + "^" + k + " should have succeeded", expectedSuccess);
|
|
} catch (ArithmeticException e) {
|
|
assertFalse(b + "^" + k + " should have failed", expectedSuccess);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@AndroidIncompatible // slow
|
|
@GwtIncompatible // TODO
|
|
public void testSaturatedAdd() {
|
|
for (int a : ALL_INTEGER_CANDIDATES) {
|
|
for (int b : ALL_INTEGER_CANDIDATES) {
|
|
assertOperationEquals(
|
|
a, b, "s+", saturatedCast(valueOf(a).add(valueOf(b))), IntMath.saturatedAdd(a, b));
|
|
}
|
|
}
|
|
}
|
|
|
|
@AndroidIncompatible // slow
|
|
@GwtIncompatible // TODO
|
|
public void testSaturatedSubtract() {
|
|
for (int a : ALL_INTEGER_CANDIDATES) {
|
|
for (int b : ALL_INTEGER_CANDIDATES) {
|
|
assertOperationEquals(
|
|
a,
|
|
b,
|
|
"s-",
|
|
saturatedCast(valueOf(a).subtract(valueOf(b))),
|
|
IntMath.saturatedSubtract(a, b));
|
|
}
|
|
}
|
|
}
|
|
|
|
@AndroidIncompatible // slow
|
|
@GwtIncompatible // TODO
|
|
public void testSaturatedMultiply() {
|
|
for (int a : ALL_INTEGER_CANDIDATES) {
|
|
for (int b : ALL_INTEGER_CANDIDATES) {
|
|
assertOperationEquals(
|
|
a,
|
|
b,
|
|
"s*",
|
|
saturatedCast(valueOf(a).multiply(valueOf(b))),
|
|
IntMath.saturatedMultiply(a, b));
|
|
}
|
|
}
|
|
}
|
|
|
|
@GwtIncompatible // TODO
|
|
public void testSaturatedPow() {
|
|
for (int a : ALL_INTEGER_CANDIDATES) {
|
|
for (int b : EXPONENTS) {
|
|
assertOperationEquals(
|
|
a, b, "s^", saturatedCast(valueOf(a).pow(b)), IntMath.saturatedPow(a, b));
|
|
}
|
|
}
|
|
}
|
|
|
|
private static final BigInteger MAX_INT = BigInteger.valueOf(Integer.MAX_VALUE);
|
|
private static final BigInteger MIN_INT = BigInteger.valueOf(Integer.MIN_VALUE);
|
|
|
|
private static int saturatedCast(BigInteger big) {
|
|
if (big.compareTo(MAX_INT) > 0) {
|
|
return Integer.MAX_VALUE;
|
|
}
|
|
if (big.compareTo(MIN_INT) < 0) {
|
|
return Integer.MIN_VALUE;
|
|
}
|
|
return big.intValue();
|
|
}
|
|
|
|
private void assertOperationEquals(int a, int b, String op, int expected, int actual) {
|
|
if (expected != actual) {
|
|
fail("Expected for " + a + " " + op + " " + b + " = " + expected + ", but got " + actual);
|
|
}
|
|
}
|
|
|
|
// Depends on the correctness of BigIntegerMath.factorial.
|
|
public void testFactorial() {
|
|
for (int n = 0; n <= 50; n++) {
|
|
BigInteger expectedBig = BigIntegerMath.factorial(n);
|
|
int expectedInt = fitsInInt(expectedBig) ? expectedBig.intValue() : Integer.MAX_VALUE;
|
|
assertEquals(expectedInt, IntMath.factorial(n));
|
|
}
|
|
}
|
|
|
|
public void testFactorialNegative() {
|
|
for (int n : NEGATIVE_INTEGER_CANDIDATES) {
|
|
try {
|
|
IntMath.factorial(n);
|
|
fail("Expected IllegalArgumentException");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
}
|
|
}
|
|
|
|
// Depends on the correctness of BigIntegerMath.binomial.
|
|
public void testBinomial() {
|
|
for (int n = 0; n <= 50; n++) {
|
|
for (int k = 0; k <= n; k++) {
|
|
BigInteger expectedBig = BigIntegerMath.binomial(n, k);
|
|
int expectedInt = fitsInInt(expectedBig) ? expectedBig.intValue() : Integer.MAX_VALUE;
|
|
assertEquals(expectedInt, IntMath.binomial(n, k));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void testBinomialOutside() {
|
|
for (int n = 0; n <= 50; n++) {
|
|
try {
|
|
IntMath.binomial(n, -1);
|
|
fail("Expected IllegalArgumentException");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
try {
|
|
IntMath.binomial(n, n + 1);
|
|
fail("Expected IllegalArgumentException");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
}
|
|
}
|
|
|
|
public void testBinomialNegative() {
|
|
for (int n : NEGATIVE_INTEGER_CANDIDATES) {
|
|
try {
|
|
IntMath.binomial(n, 0);
|
|
fail("Expected IllegalArgumentException");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
}
|
|
}
|
|
|
|
@AndroidIncompatible // slow
|
|
@GwtIncompatible // java.math.BigInteger
|
|
public void testMean() {
|
|
// Odd-sized ranges have an obvious mean
|
|
assertMean(2, 1, 3);
|
|
|
|
assertMean(-2, -3, -1);
|
|
assertMean(0, -1, 1);
|
|
assertMean(1, -1, 3);
|
|
assertMean((1 << 30) - 1, -1, Integer.MAX_VALUE);
|
|
|
|
// Even-sized ranges should prefer the lower mean
|
|
assertMean(2, 1, 4);
|
|
assertMean(-3, -4, -1);
|
|
assertMean(0, -1, 2);
|
|
assertMean(0, Integer.MIN_VALUE + 2, Integer.MAX_VALUE);
|
|
assertMean(0, 0, 1);
|
|
assertMean(-1, -1, 0);
|
|
assertMean(-1, Integer.MIN_VALUE, Integer.MAX_VALUE);
|
|
|
|
// x == y == mean
|
|
assertMean(1, 1, 1);
|
|
assertMean(0, 0, 0);
|
|
assertMean(-1, -1, -1);
|
|
assertMean(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE);
|
|
assertMean(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
|
|
|
|
// Exhaustive checks
|
|
for (int x : ALL_INTEGER_CANDIDATES) {
|
|
for (int y : ALL_INTEGER_CANDIDATES) {
|
|
assertMean(x, y);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Helper method that asserts the arithmetic mean of x and y is equal to the expectedMean. */
|
|
private static void assertMean(int expectedMean, int x, int y) {
|
|
assertEquals(
|
|
"The expectedMean should be the same as computeMeanSafely",
|
|
expectedMean,
|
|
computeMeanSafely(x, y));
|
|
assertMean(x, y);
|
|
}
|
|
|
|
/**
|
|
* Helper method that asserts the arithmetic mean of x and y is equal to the result of
|
|
* computeMeanSafely.
|
|
*/
|
|
private static void assertMean(int x, int y) {
|
|
int expectedMean = computeMeanSafely(x, y);
|
|
assertEquals(expectedMean, IntMath.mean(x, y));
|
|
assertEquals(
|
|
"The mean of x and y should equal the mean of y and x", expectedMean, IntMath.mean(y, x));
|
|
}
|
|
|
|
/**
|
|
* Computes the mean in a way that is obvious and resilient to overflow by using BigInteger
|
|
* arithmetic.
|
|
*/
|
|
private static int computeMeanSafely(int x, int y) {
|
|
BigInteger bigX = BigInteger.valueOf(x);
|
|
BigInteger bigY = BigInteger.valueOf(y);
|
|
BigDecimal bigMean =
|
|
new BigDecimal(bigX.add(bigY)).divide(BigDecimal.valueOf(2), BigDecimal.ROUND_FLOOR);
|
|
// parseInt blows up on overflow as opposed to intValue() which does not.
|
|
return Integer.parseInt(bigMean.toString());
|
|
}
|
|
|
|
private static boolean fitsInInt(BigInteger big) {
|
|
return big.bitLength() <= 31;
|
|
}
|
|
|
|
@GwtIncompatible // NullPointerTester
|
|
public void testNullPointers() {
|
|
NullPointerTester tester = new NullPointerTester();
|
|
tester.setDefault(int.class, 1);
|
|
tester.testAllPublicStaticMethods(IntMath.class);
|
|
}
|
|
|
|
@GwtIncompatible // isPrime is GWT-incompatible
|
|
public void testIsPrime() {
|
|
// Defer correctness tests to Long.isPrime
|
|
|
|
// Check the first 100,000 integers
|
|
for (int i = 0; i < 100000; i++) {
|
|
assertEquals(LongMath.isPrime(i), IntMath.isPrime(i));
|
|
}
|
|
|
|
// Then check 1000 deterministic pseudo-random int values.
|
|
Random rand = new Random(1);
|
|
for (int i = 0; i < 1000; i++) {
|
|
int n = rand.nextInt(Integer.MAX_VALUE);
|
|
assertEquals(LongMath.isPrime(n), IntMath.isPrime(n));
|
|
}
|
|
}
|
|
|
|
private static int force32(int value) {
|
|
// GWT doesn't consistently overflow values to make them 32-bit, so we need to force it.
|
|
return value & 0xffffffff;
|
|
}
|
|
}
|