1 /* 2 * Copyright (C) 2011 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.math; 18 19 import static com.google.common.math.MathTesting.ALL_INTEGER_CANDIDATES; 20 import static com.google.common.math.MathTesting.ALL_ROUNDING_MODES; 21 import static com.google.common.math.MathTesting.ALL_SAFE_ROUNDING_MODES; 22 import static com.google.common.math.MathTesting.EXPONENTS; 23 import static com.google.common.math.MathTesting.NEGATIVE_INTEGER_CANDIDATES; 24 import static com.google.common.math.MathTesting.NONZERO_INTEGER_CANDIDATES; 25 import static com.google.common.math.MathTesting.POSITIVE_INTEGER_CANDIDATES; 26 import static java.math.BigInteger.valueOf; 27 import static java.math.RoundingMode.FLOOR; 28 import static java.math.RoundingMode.UNNECESSARY; 29 30 import com.google.common.annotations.GwtCompatible; 31 import com.google.common.annotations.GwtIncompatible; 32 import com.google.common.testing.NullPointerTester; 33 34 import junit.framework.TestCase; 35 36 import java.math.BigDecimal; 37 import java.math.BigInteger; 38 import java.math.RoundingMode; 39 40 /** 41 * Tests for {@link IntMath}. 42 * 43 * @author Louis Wasserman 44 */ 45 @GwtCompatible(emulated = true) 46 public class IntMathTest extends TestCase { 47 @GwtIncompatible("BigIntegerMath") // TODO(cpovirk): GWT-enable BigIntegerMath testConstantMaxPowerOfSqrt2Unsigned()48 public void testConstantMaxPowerOfSqrt2Unsigned() { 49 assertEquals( 50 BigIntegerMath.sqrt(BigInteger.ZERO.setBit(2 * Integer.SIZE - 1), FLOOR).intValue(), 51 IntMath.MAX_POWER_OF_SQRT2_UNSIGNED); 52 } 53 54 @GwtIncompatible("pow()") testConstantsPowersOf10()55 public void testConstantsPowersOf10() { 56 for (int i = 0; i < IntMath.POWERS_OF_10.length; i++) { 57 assertEquals(IntMath.pow(10, i), IntMath.POWERS_OF_10[i]); 58 } 59 } 60 61 @GwtIncompatible("BigIntegerMath") // TODO(cpovirk): GWT-enable BigIntegerMath testConstantsHalfPowersOf10()62 public void testConstantsHalfPowersOf10() { 63 for (int i = 0; i < IntMath.HALF_POWERS_OF_10.length; i++) { 64 assert IntMath.HALF_POWERS_OF_10[i] 65 == Math.min(Integer.MAX_VALUE, 66 BigIntegerMath.sqrt(BigInteger.TEN.pow(2 * i + 1), FLOOR).longValue()); 67 } 68 } 69 70 @GwtIncompatible("BigIntegerMath") // TODO(cpovirk): GWT-enable BigIntegerMath testConstantsBiggestBinomials()71 public void testConstantsBiggestBinomials(){ 72 for (int k = 0; k < IntMath.BIGGEST_BINOMIALS.length; k++) { 73 assertTrue(fitsInInt(BigIntegerMath.binomial(IntMath.BIGGEST_BINOMIALS[k], k))); 74 assertTrue(IntMath.BIGGEST_BINOMIALS[k] == Integer.MAX_VALUE 75 || !fitsInInt(BigIntegerMath.binomial(IntMath.BIGGEST_BINOMIALS[k] + 1, k))); 76 // In the first case, any int is valid; in the second, we want to test that the next-bigger 77 // int overflows. 78 } 79 assertFalse( 80 fitsInInt(BigIntegerMath.binomial( 81 2 * IntMath.BIGGEST_BINOMIALS.length, IntMath.BIGGEST_BINOMIALS.length))); 82 } 83 84 @GwtIncompatible("sqrt") testPowersSqrtMaxInt()85 public void testPowersSqrtMaxInt() { 86 assertEquals(IntMath.sqrt(Integer.MAX_VALUE, FLOOR), IntMath.FLOOR_SQRT_MAX_INT); 87 } 88 testIsPowerOfTwo()89 public void testIsPowerOfTwo() { 90 for (int x : ALL_INTEGER_CANDIDATES) { 91 // Checks for a single bit set. 92 boolean expected = x > 0 & (x & (x - 1)) == 0; 93 assertEquals(expected, IntMath.isPowerOfTwo(x)); 94 } 95 } 96 97 @GwtIncompatible("log2") testLog2ZeroAlwaysThrows()98 public void testLog2ZeroAlwaysThrows() { 99 for (RoundingMode mode : ALL_ROUNDING_MODES) { 100 try { 101 IntMath.log2(0, mode); 102 fail("Expected IllegalArgumentException"); 103 } catch (IllegalArgumentException expected) {} 104 } 105 } 106 107 @GwtIncompatible("log2") testLog2NegativeAlwaysThrows()108 public void testLog2NegativeAlwaysThrows() { 109 for (int x : NEGATIVE_INTEGER_CANDIDATES) { 110 for (RoundingMode mode : ALL_ROUNDING_MODES) { 111 try { 112 IntMath.log2(x, mode); 113 fail("Expected IllegalArgumentException"); 114 } catch (IllegalArgumentException expected) {} 115 } 116 } 117 } 118 119 // Relies on the correctness of BigIntegrerMath.log2 for all modes except UNNECESSARY. 120 @GwtIncompatible("BigIntegerMath") // TODO(cpovirk): GWT-enable BigIntegerMath testLog2MatchesBigInteger()121 public void testLog2MatchesBigInteger() { 122 for (int x : POSITIVE_INTEGER_CANDIDATES) { 123 for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) { 124 assertEquals(BigIntegerMath.log2(valueOf(x), mode), IntMath.log2(x, mode)); 125 } 126 } 127 } 128 129 // Relies on the correctness of isPowerOfTwo(int). 130 @GwtIncompatible("log2") testLog2Exact()131 public void testLog2Exact() { 132 for (int x : POSITIVE_INTEGER_CANDIDATES) { 133 // We only expect an exception if x was not a power of 2. 134 boolean isPowerOf2 = IntMath.isPowerOfTwo(x); 135 try { 136 assertEquals(x, 1 << IntMath.log2(x, UNNECESSARY)); 137 assertTrue(isPowerOf2); 138 } catch (ArithmeticException e) { 139 assertFalse(isPowerOf2); 140 } 141 } 142 } 143 144 @GwtIncompatible("log10") testLog10ZeroAlwaysThrows()145 public void testLog10ZeroAlwaysThrows() { 146 for (RoundingMode mode : ALL_ROUNDING_MODES) { 147 try { 148 IntMath.log10(0, mode); 149 fail("Expected IllegalArgumentException"); 150 } catch (IllegalArgumentException expected) {} 151 } 152 } 153 154 @GwtIncompatible("log10") testLog10NegativeAlwaysThrows()155 public void testLog10NegativeAlwaysThrows() { 156 for (int x : NEGATIVE_INTEGER_CANDIDATES) { 157 for (RoundingMode mode : ALL_ROUNDING_MODES) { 158 try { 159 IntMath.log10(x, mode); 160 fail("Expected IllegalArgumentException"); 161 } catch (IllegalArgumentException expected) {} 162 } 163 } 164 } 165 166 // Relies on the correctness of BigIntegerMath.log10 for all modes except UNNECESSARY. 167 @GwtIncompatible("BigIntegerMath") // TODO(cpovirk): GWT-enable BigIntegerMath testLog10MatchesBigInteger()168 public void testLog10MatchesBigInteger() { 169 for (int x : POSITIVE_INTEGER_CANDIDATES) { 170 for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) { 171 // The BigInteger implementation is tested separately, use it as the reference. 172 assertEquals(BigIntegerMath.log10(valueOf(x), mode), IntMath.log10(x, mode)); 173 } 174 } 175 } 176 177 // Relies on the correctness of log10(int, FLOOR) and of pow(int, int). 178 @GwtIncompatible("pow()") testLog10Exact()179 public void testLog10Exact() { 180 for (int x : POSITIVE_INTEGER_CANDIDATES) { 181 int floor = IntMath.log10(x, FLOOR); 182 boolean expectSuccess = IntMath.pow(10, floor) == x; 183 try { 184 assertEquals(floor, IntMath.log10(x, UNNECESSARY)); 185 assertTrue(expectSuccess); 186 } catch (ArithmeticException e) { 187 assertFalse(expectSuccess); 188 } 189 } 190 } 191 192 @GwtIncompatible("log10") testLog10TrivialOnPowerOfTen()193 public void testLog10TrivialOnPowerOfTen() { 194 int x = 1000000; 195 for (RoundingMode mode : ALL_ROUNDING_MODES) { 196 assertEquals(6, IntMath.log10(x, mode)); 197 } 198 } 199 200 // Simple test to cover sqrt(0) for all types and all modes. 201 @GwtIncompatible("sqrt") testSqrtZeroAlwaysZero()202 public void testSqrtZeroAlwaysZero() { 203 for (RoundingMode mode : ALL_ROUNDING_MODES) { 204 assertEquals(0, IntMath.sqrt(0, mode)); 205 } 206 } 207 208 @GwtIncompatible("sqrt") testSqrtNegativeAlwaysThrows()209 public void testSqrtNegativeAlwaysThrows() { 210 for (int x : NEGATIVE_INTEGER_CANDIDATES) { 211 for (RoundingMode mode : RoundingMode.values()) { 212 try { 213 IntMath.sqrt(x, mode); 214 fail("Expected IllegalArgumentException"); 215 } catch (IllegalArgumentException expected) {} 216 } 217 } 218 } 219 220 /* Relies on the correctness of BigIntegerMath.sqrt for all modes except UNNECESSARY. */ 221 @GwtIncompatible("BigIntegerMath") // TODO(cpovirk): GWT-enable BigIntegerMath testSqrtMatchesBigInteger()222 public void testSqrtMatchesBigInteger() { 223 for (int x : POSITIVE_INTEGER_CANDIDATES) { 224 for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) { 225 // The BigInteger implementation is tested separately, use it as the reference. 226 // Promote the int value (rather than using intValue() on the expected value) to avoid 227 // any risk of truncation which could lead to a false positive. 228 assertEquals(BigIntegerMath.sqrt(valueOf(x), mode), valueOf(IntMath.sqrt(x, mode))); 229 } 230 } 231 } 232 233 /* Relies on the correctness of sqrt(int, FLOOR). */ 234 @GwtIncompatible("sqrt") testSqrtExactMatchesFloorOrThrows()235 public void testSqrtExactMatchesFloorOrThrows() { 236 for (int x : POSITIVE_INTEGER_CANDIDATES) { 237 int floor = IntMath.sqrt(x, FLOOR); 238 // We only expect an exception if x was not a perfect square. 239 boolean isPerfectSquare = (floor * floor == x); 240 try { 241 assertEquals(floor, IntMath.sqrt(x, UNNECESSARY)); 242 assertTrue(isPerfectSquare); 243 } catch (ArithmeticException e) { 244 assertFalse(isPerfectSquare); 245 } 246 } 247 } 248 249 @GwtIncompatible("2147483646^2 expected=4") testPow()250 public void testPow() { 251 for (int i : ALL_INTEGER_CANDIDATES) { 252 for (int pow : EXPONENTS) { 253 assertEquals(i + "^" + pow, BigInteger.valueOf(i).pow(pow).intValue(), IntMath.pow(i, pow)); 254 } 255 } 256 } 257 258 @GwtIncompatible("-2147483648/1 expected=2147483648") testDivNonZero()259 public void testDivNonZero() { 260 for (int p : NONZERO_INTEGER_CANDIDATES) { 261 for (int q : NONZERO_INTEGER_CANDIDATES) { 262 for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) { 263 int expected = 264 new BigDecimal(valueOf(p)).divide(new BigDecimal(valueOf(q)), 0, mode).intValue(); 265 assertEquals(p + "/" + q, expected, IntMath.divide(p, q, mode)); 266 } 267 } 268 } 269 } 270 271 @GwtIncompatible("-2147483648/-1 not expected to divide evenly") testDivNonZeroExact()272 public void testDivNonZeroExact() { 273 for (int p : NONZERO_INTEGER_CANDIDATES) { 274 for (int q : NONZERO_INTEGER_CANDIDATES) { 275 boolean dividesEvenly = (p % q) == 0; 276 277 try { 278 assertEquals(p + "/" + q, p, IntMath.divide(p, q, UNNECESSARY) * q); 279 assertTrue(p + "/" + q + " expected to divide evenly", dividesEvenly); 280 } catch (ArithmeticException e) { 281 assertFalse(p + "/" + q + " not expected to divide evenly", dividesEvenly); 282 } 283 } 284 } 285 } 286 287 @GwtIncompatible("pow()") testZeroDivIsAlwaysZero()288 public void testZeroDivIsAlwaysZero() { 289 for (int q : NONZERO_INTEGER_CANDIDATES) { 290 for (RoundingMode mode : ALL_ROUNDING_MODES) { 291 assertEquals(0, IntMath.divide(0, q, mode)); 292 } 293 } 294 } 295 296 @GwtIncompatible("pow()") testDivByZeroAlwaysFails()297 public void testDivByZeroAlwaysFails() { 298 for (int p : ALL_INTEGER_CANDIDATES) { 299 for (RoundingMode mode : ALL_ROUNDING_MODES) { 300 try { 301 IntMath.divide(p, 0, mode); 302 fail("Expected ArithmeticException"); 303 } catch (ArithmeticException expected) {} 304 } 305 } 306 } 307 testMod()308 public void testMod() { 309 for (int x : ALL_INTEGER_CANDIDATES) { 310 for (int m : POSITIVE_INTEGER_CANDIDATES) { 311 assertEquals(valueOf(x).mod(valueOf(m)).intValue(), IntMath.mod(x, m)); 312 } 313 } 314 } 315 testModNegativeModulusFails()316 public void testModNegativeModulusFails() { 317 for (int x : POSITIVE_INTEGER_CANDIDATES) { 318 for (int m : NEGATIVE_INTEGER_CANDIDATES) { 319 try { 320 IntMath.mod(x, m); 321 fail("Expected ArithmeticException"); 322 } catch (ArithmeticException expected) {} 323 } 324 } 325 } 326 testModZeroModulusFails()327 public void testModZeroModulusFails() { 328 for (int x : ALL_INTEGER_CANDIDATES) { 329 try { 330 IntMath.mod(x, 0); 331 fail("Expected ArithmeticException"); 332 } catch (ArithmeticException expected) {} 333 } 334 } 335 testGCD()336 public void testGCD() { 337 for (int a : POSITIVE_INTEGER_CANDIDATES) { 338 for (int b : POSITIVE_INTEGER_CANDIDATES) { 339 assertEquals(valueOf(a).gcd(valueOf(b)), valueOf(IntMath.gcd(a, b))); 340 } 341 } 342 } 343 testGCDZero()344 public void testGCDZero() { 345 for (int a : POSITIVE_INTEGER_CANDIDATES) { 346 assertEquals(a, IntMath.gcd(a, 0)); 347 assertEquals(a, IntMath.gcd(0, a)); 348 } 349 assertEquals(0, IntMath.gcd(0, 0)); 350 } 351 testGCDNegativePositiveThrows()352 public void testGCDNegativePositiveThrows() { 353 for (int a : NEGATIVE_INTEGER_CANDIDATES) { 354 try { 355 IntMath.gcd(a, 3); 356 fail("Expected IllegalArgumentException"); 357 } catch (IllegalArgumentException expected) {} 358 try { 359 IntMath.gcd(3, a); 360 fail("Expected IllegalArgumentException"); 361 } catch (IllegalArgumentException expected) {} 362 } 363 } 364 testGCDNegativeZeroThrows()365 public void testGCDNegativeZeroThrows() { 366 for (int a : NEGATIVE_INTEGER_CANDIDATES) { 367 try { 368 IntMath.gcd(a, 0); 369 fail("Expected IllegalArgumentException"); 370 } catch (IllegalArgumentException expected) {} 371 try { 372 IntMath.gcd(0, a); 373 fail("Expected IllegalArgumentException"); 374 } catch (IllegalArgumentException expected) {} 375 } 376 } 377 testCheckedAdd()378 public void testCheckedAdd() { 379 for (int a : ALL_INTEGER_CANDIDATES) { 380 for (int b : ALL_INTEGER_CANDIDATES) { 381 BigInteger expectedResult = valueOf(a).add(valueOf(b)); 382 boolean expectedSuccess = fitsInInt(expectedResult); 383 try { 384 assertEquals(a + b, IntMath.checkedAdd(a, b)); 385 assertTrue(expectedSuccess); 386 } catch (ArithmeticException e) { 387 assertFalse(expectedSuccess); 388 } 389 } 390 } 391 } 392 testCheckedSubtract()393 public void testCheckedSubtract() { 394 for (int a : ALL_INTEGER_CANDIDATES) { 395 for (int b : ALL_INTEGER_CANDIDATES) { 396 BigInteger expectedResult = valueOf(a).subtract(valueOf(b)); 397 boolean expectedSuccess = fitsInInt(expectedResult); 398 try { 399 assertEquals(a - b, IntMath.checkedSubtract(a, b)); 400 assertTrue(expectedSuccess); 401 } catch (ArithmeticException e) { 402 assertFalse(expectedSuccess); 403 } 404 } 405 } 406 } 407 testCheckedMultiply()408 public void testCheckedMultiply() { 409 for (int a : ALL_INTEGER_CANDIDATES) { 410 for (int b : ALL_INTEGER_CANDIDATES) { 411 BigInteger expectedResult = valueOf(a).multiply(valueOf(b)); 412 boolean expectedSuccess = fitsInInt(expectedResult); 413 try { 414 assertEquals(a * b, IntMath.checkedMultiply(a, b)); 415 assertTrue(expectedSuccess); 416 } catch (ArithmeticException e) { 417 assertFalse(expectedSuccess); 418 } 419 } 420 } 421 } 422 423 @GwtIncompatible("-2147483648^1 expected=2147483648") testCheckedPow()424 public void testCheckedPow() { 425 for (int b : ALL_INTEGER_CANDIDATES) { 426 for (int k : EXPONENTS) { 427 BigInteger expectedResult = valueOf(b).pow(k); 428 boolean expectedSuccess = fitsInInt(expectedResult); 429 try { 430 assertEquals(b + "^" + k, expectedResult.intValue(), IntMath.checkedPow(b, k)); 431 assertTrue(b + "^" + k + " should have succeeded", expectedSuccess); 432 } catch (ArithmeticException e) { 433 assertFalse(b + "^" + k + " should have failed", expectedSuccess); 434 } 435 } 436 } 437 } 438 439 // Depends on the correctness of BigIntegerMath.factorial. 440 @GwtIncompatible("BigIntegerMath") // TODO(cpovirk): GWT-enable BigIntegerMath testFactorial()441 public void testFactorial() { 442 for (int n = 0; n <= 50; n++) { 443 BigInteger expectedBig = BigIntegerMath.factorial(n); 444 int expectedInt = fitsInInt(expectedBig) ? expectedBig.intValue() : Integer.MAX_VALUE; 445 assertEquals(expectedInt, IntMath.factorial(n)); 446 } 447 } 448 449 @GwtIncompatible("factorial") testFactorialNegative()450 public void testFactorialNegative() { 451 for (int n : NEGATIVE_INTEGER_CANDIDATES) { 452 try { 453 IntMath.factorial(n); 454 fail("Expected IllegalArgumentException"); 455 } catch (IllegalArgumentException expected) {} 456 } 457 } 458 459 // Depends on the correctness of BigIntegerMath.binomial. 460 @GwtIncompatible("BigIntegerMath") // TODO(cpovirk): GWT-enable BigIntegerMath testBinomial()461 public void testBinomial() { 462 for (int n = 0; n <= 50; n++) { 463 for (int k = 0; k <= n; k++) { 464 BigInteger expectedBig = BigIntegerMath.binomial(n, k); 465 int expectedInt = fitsInInt(expectedBig) ? expectedBig.intValue() : Integer.MAX_VALUE; 466 assertEquals(expectedInt, IntMath.binomial(n, k)); 467 } 468 } 469 } 470 471 @GwtIncompatible("binomial") testBinomialOutside()472 public void testBinomialOutside() { 473 for (int n = 0; n <= 50; n++) { 474 try { 475 IntMath.binomial(n, -1); 476 fail("Expected IllegalArgumentException"); 477 } catch (IllegalArgumentException expected) {} 478 try { 479 IntMath.binomial(n, n + 1); 480 fail("Expected IllegalArgumentException"); 481 } catch (IllegalArgumentException expected) {} 482 } 483 } 484 485 @GwtIncompatible("binomial") testBinomialNegative()486 public void testBinomialNegative() { 487 for (int n : NEGATIVE_INTEGER_CANDIDATES) { 488 try { 489 IntMath.binomial(n, 0); 490 fail("Expected IllegalArgumentException"); 491 } catch (IllegalArgumentException expected) {} 492 } 493 } 494 fitsInInt(BigInteger big)495 private boolean fitsInInt(BigInteger big) { 496 return big.bitLength() <= 31; 497 } 498 499 @GwtIncompatible("NullPointerTester") testNullPointers()500 public void testNullPointers() throws Exception { 501 NullPointerTester tester = new NullPointerTester(); 502 tester.setDefault(int.class, 1); 503 tester.setDefault(RoundingMode.class, FLOOR); 504 tester.testAllPublicStaticMethods(IntMath.class); 505 } 506 } 507