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 com.google.common.math.TestPlatform.intsCanGoOutOfRange; 27 import static java.math.BigInteger.valueOf; 28 import static java.math.RoundingMode.FLOOR; 29 import static java.math.RoundingMode.UNNECESSARY; 30 31 import com.google.common.annotations.GwtCompatible; 32 import com.google.common.annotations.GwtIncompatible; 33 import com.google.common.testing.NullPointerTester; 34 import java.math.BigDecimal; 35 import java.math.BigInteger; 36 import java.math.RoundingMode; 37 import java.util.Random; 38 import junit.framework.TestCase; 39 40 /** 41 * Tests for {@link IntMath}. 42 * 43 * @author Louis Wasserman 44 */ 45 @GwtCompatible(emulated = true) 46 public class IntMathTest extends TestCase { testMaxSignedPowerOfTwo()47 public void testMaxSignedPowerOfTwo() { 48 assertTrue(IntMath.isPowerOfTwo(IntMath.MAX_SIGNED_POWER_OF_TWO)); 49 50 // Extra work required to make GWT happy. 51 long value = IntMath.MAX_SIGNED_POWER_OF_TWO * 2L; 52 assertFalse(IntMath.isPowerOfTwo((int) value)); 53 } 54 testCeilingPowerOfTwo()55 public void testCeilingPowerOfTwo() { 56 for (int x : POSITIVE_INTEGER_CANDIDATES) { 57 BigInteger expectedResult = BigIntegerMath.ceilingPowerOfTwo(BigInteger.valueOf(x)); 58 if (fitsInInt(expectedResult)) { 59 assertEquals(expectedResult.intValue(), IntMath.ceilingPowerOfTwo(x)); 60 } else { 61 try { 62 IntMath.ceilingPowerOfTwo(x); 63 fail("Expected ArithmeticException"); 64 } catch (ArithmeticException expected) { 65 } 66 } 67 } 68 } 69 testFloorPowerOfTwo()70 public void testFloorPowerOfTwo() { 71 for (int x : POSITIVE_INTEGER_CANDIDATES) { 72 BigInteger expectedResult = BigIntegerMath.floorPowerOfTwo(BigInteger.valueOf(x)); 73 assertEquals(expectedResult.intValue(), IntMath.floorPowerOfTwo(x)); 74 } 75 } 76 testCeilingPowerOfTwoNegative()77 public void testCeilingPowerOfTwoNegative() { 78 for (int x : NEGATIVE_INTEGER_CANDIDATES) { 79 try { 80 IntMath.ceilingPowerOfTwo(x); 81 fail("Expected IllegalArgumentException"); 82 } catch (IllegalArgumentException expected) { 83 } 84 } 85 } 86 testFloorPowerOfTwoNegative()87 public void testFloorPowerOfTwoNegative() { 88 for (int x : NEGATIVE_INTEGER_CANDIDATES) { 89 try { 90 IntMath.floorPowerOfTwo(x); 91 fail("Expected IllegalArgumentException"); 92 } catch (IllegalArgumentException expected) { 93 } 94 } 95 } 96 testCeilingPowerOfTwoZero()97 public void testCeilingPowerOfTwoZero() { 98 try { 99 IntMath.ceilingPowerOfTwo(0); 100 fail("Expected IllegalArgumentException"); 101 } catch (IllegalArgumentException expected) { 102 } 103 } 104 testFloorPowerOfTwoZero()105 public void testFloorPowerOfTwoZero() { 106 try { 107 IntMath.floorPowerOfTwo(0); 108 fail("Expected IllegalArgumentException"); 109 } catch (IllegalArgumentException expected) { 110 } 111 } 112 113 @GwtIncompatible // BigIntegerMath // TODO(cpovirk): GWT-enable BigIntegerMath testConstantMaxPowerOfSqrt2Unsigned()114 public void testConstantMaxPowerOfSqrt2Unsigned() { 115 assertEquals( 116 /*expected=*/ BigIntegerMath.sqrt(BigInteger.ZERO.setBit(2 * Integer.SIZE - 1), FLOOR) 117 .intValue(), 118 /*actual=*/ IntMath.MAX_POWER_OF_SQRT2_UNSIGNED); 119 } 120 121 @GwtIncompatible // pow() testConstantsPowersOf10()122 public void testConstantsPowersOf10() { 123 for (int i = 0; i < IntMath.powersOf10.length - 1; i++) { 124 assertEquals(IntMath.pow(10, i), IntMath.powersOf10[i]); 125 } 126 } 127 128 @GwtIncompatible // BigIntegerMath // TODO(cpovirk): GWT-enable BigIntegerMath testMaxLog10ForLeadingZeros()129 public void testMaxLog10ForLeadingZeros() { 130 for (int i = 0; i < Integer.SIZE; i++) { 131 assertEquals( 132 BigIntegerMath.log10(BigInteger.ONE.shiftLeft(Integer.SIZE - i), FLOOR), 133 IntMath.maxLog10ForLeadingZeros[i]); 134 } 135 } 136 137 @GwtIncompatible // BigIntegerMath // TODO(cpovirk): GWT-enable BigIntegerMath testConstantsHalfPowersOf10()138 public void testConstantsHalfPowersOf10() { 139 for (int i = 0; i < IntMath.halfPowersOf10.length; i++) { 140 assert IntMath.halfPowersOf10[i] 141 == Math.min( 142 Integer.MAX_VALUE, 143 BigIntegerMath.sqrt(BigInteger.TEN.pow(2 * i + 1), FLOOR).longValue()); 144 } 145 } 146 testConstantsBiggestBinomials()147 public void testConstantsBiggestBinomials() { 148 for (int k = 0; k < IntMath.biggestBinomials.length; k++) { 149 assertTrue(fitsInInt(BigIntegerMath.binomial(IntMath.biggestBinomials[k], k))); 150 assertTrue( 151 IntMath.biggestBinomials[k] == Integer.MAX_VALUE 152 || !fitsInInt(BigIntegerMath.binomial(IntMath.biggestBinomials[k] + 1, k))); 153 // In the first case, any int is valid; in the second, we want to test that the next-bigger 154 // int overflows. 155 } 156 assertFalse( 157 fitsInInt( 158 BigIntegerMath.binomial( 159 2 * IntMath.biggestBinomials.length, IntMath.biggestBinomials.length))); 160 } 161 162 @GwtIncompatible // sqrt testPowersSqrtMaxInt()163 public void testPowersSqrtMaxInt() { 164 assertEquals( 165 /*expected=*/ IntMath.sqrt(Integer.MAX_VALUE, FLOOR), 166 /*actual=*/ IntMath.FLOOR_SQRT_MAX_INT); 167 } 168 169 @AndroidIncompatible // presumably slow testLessThanBranchFree()170 public void testLessThanBranchFree() { 171 for (int x : ALL_INTEGER_CANDIDATES) { 172 for (int y : ALL_INTEGER_CANDIDATES) { 173 if (LongMath.fitsInInt((long) x - y)) { 174 int expected = (x < y) ? 1 : 0; 175 int actual = IntMath.lessThanBranchFree(x, y); 176 assertEquals(expected, actual); 177 } 178 } 179 } 180 } 181 182 @GwtIncompatible // java.math.BigInteger testIsPowerOfTwo()183 public void testIsPowerOfTwo() { 184 for (int x : ALL_INTEGER_CANDIDATES) { 185 // Checks for a single bit set. 186 BigInteger bigX = BigInteger.valueOf(x); 187 boolean expected = (bigX.signum() > 0) && (bigX.bitCount() == 1); 188 assertEquals(expected, IntMath.isPowerOfTwo(x)); 189 } 190 } 191 testLog2ZeroAlwaysThrows()192 public void testLog2ZeroAlwaysThrows() { 193 for (RoundingMode mode : ALL_ROUNDING_MODES) { 194 try { 195 IntMath.log2(0, mode); 196 fail("Expected IllegalArgumentException"); 197 } catch (IllegalArgumentException expected) { 198 } 199 } 200 } 201 testLog2NegativeAlwaysThrows()202 public void testLog2NegativeAlwaysThrows() { 203 for (int x : NEGATIVE_INTEGER_CANDIDATES) { 204 for (RoundingMode mode : ALL_ROUNDING_MODES) { 205 try { 206 IntMath.log2(x, mode); 207 fail("Expected IllegalArgumentException"); 208 } catch (IllegalArgumentException expected) { 209 } 210 } 211 } 212 } 213 214 // Relies on the correctness of BigIntegrerMath.log2 for all modes except UNNECESSARY. testLog2MatchesBigInteger()215 public void testLog2MatchesBigInteger() { 216 for (int x : POSITIVE_INTEGER_CANDIDATES) { 217 for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) { 218 assertEquals(BigIntegerMath.log2(valueOf(x), mode), IntMath.log2(x, mode)); 219 } 220 } 221 } 222 223 // Relies on the correctness of isPowerOfTwo(int). testLog2Exact()224 public void testLog2Exact() { 225 for (int x : POSITIVE_INTEGER_CANDIDATES) { 226 // We only expect an exception if x was not a power of 2. 227 boolean isPowerOf2 = IntMath.isPowerOfTwo(x); 228 try { 229 assertEquals(x, 1 << IntMath.log2(x, UNNECESSARY)); 230 assertTrue(isPowerOf2); 231 } catch (ArithmeticException e) { 232 assertFalse(isPowerOf2); 233 } 234 } 235 } 236 237 @GwtIncompatible // log10 testLog10ZeroAlwaysThrows()238 public void testLog10ZeroAlwaysThrows() { 239 for (RoundingMode mode : ALL_ROUNDING_MODES) { 240 try { 241 IntMath.log10(0, mode); 242 fail("Expected IllegalArgumentException"); 243 } catch (IllegalArgumentException expected) { 244 } 245 } 246 } 247 248 @GwtIncompatible // log10 testLog10NegativeAlwaysThrows()249 public void testLog10NegativeAlwaysThrows() { 250 for (int x : NEGATIVE_INTEGER_CANDIDATES) { 251 for (RoundingMode mode : ALL_ROUNDING_MODES) { 252 try { 253 IntMath.log10(x, mode); 254 fail("Expected IllegalArgumentException"); 255 } catch (IllegalArgumentException expected) { 256 } 257 } 258 } 259 } 260 261 // Relies on the correctness of BigIntegerMath.log10 for all modes except UNNECESSARY. 262 @GwtIncompatible // BigIntegerMath // TODO(cpovirk): GWT-enable BigIntegerMath testLog10MatchesBigInteger()263 public void testLog10MatchesBigInteger() { 264 for (int x : POSITIVE_INTEGER_CANDIDATES) { 265 for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) { 266 // The BigInteger implementation is tested separately, use it as the reference. 267 assertEquals(BigIntegerMath.log10(valueOf(x), mode), IntMath.log10(x, mode)); 268 } 269 } 270 } 271 272 // Relies on the correctness of log10(int, FLOOR) and of pow(int, int). 273 @GwtIncompatible // pow() testLog10Exact()274 public void testLog10Exact() { 275 for (int x : POSITIVE_INTEGER_CANDIDATES) { 276 int floor = IntMath.log10(x, FLOOR); 277 boolean expectSuccess = IntMath.pow(10, floor) == x; 278 try { 279 assertEquals(floor, IntMath.log10(x, UNNECESSARY)); 280 assertTrue(expectSuccess); 281 } catch (ArithmeticException e) { 282 assertFalse(expectSuccess); 283 } 284 } 285 } 286 287 @GwtIncompatible // log10 testLog10TrivialOnPowerOfTen()288 public void testLog10TrivialOnPowerOfTen() { 289 int x = 1000000; 290 for (RoundingMode mode : ALL_ROUNDING_MODES) { 291 assertEquals(6, IntMath.log10(x, mode)); 292 } 293 } 294 295 // Simple test to cover sqrt(0) for all types and all modes. 296 @GwtIncompatible // sqrt testSqrtZeroAlwaysZero()297 public void testSqrtZeroAlwaysZero() { 298 for (RoundingMode mode : ALL_ROUNDING_MODES) { 299 assertEquals(0, IntMath.sqrt(0, mode)); 300 } 301 } 302 303 @GwtIncompatible // sqrt testSqrtNegativeAlwaysThrows()304 public void testSqrtNegativeAlwaysThrows() { 305 for (int x : NEGATIVE_INTEGER_CANDIDATES) { 306 for (RoundingMode mode : RoundingMode.values()) { 307 try { 308 IntMath.sqrt(x, mode); 309 fail("Expected IllegalArgumentException"); 310 } catch (IllegalArgumentException expected) { 311 } 312 } 313 } 314 } 315 316 /* Relies on the correctness of BigIntegerMath.sqrt for all modes except UNNECESSARY. */ 317 @GwtIncompatible // BigIntegerMath // TODO(cpovirk): GWT-enable BigIntegerMath testSqrtMatchesBigInteger()318 public void testSqrtMatchesBigInteger() { 319 for (int x : POSITIVE_INTEGER_CANDIDATES) { 320 for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) { 321 // The BigInteger implementation is tested separately, use it as the reference. 322 // Promote the int value (rather than using intValue() on the expected value) to avoid 323 // any risk of truncation which could lead to a false positive. 324 assertEquals(BigIntegerMath.sqrt(valueOf(x), mode), valueOf(IntMath.sqrt(x, mode))); 325 } 326 } 327 } 328 329 /* Relies on the correctness of sqrt(int, FLOOR). */ 330 @GwtIncompatible // sqrt testSqrtExactMatchesFloorOrThrows()331 public void testSqrtExactMatchesFloorOrThrows() { 332 for (int x : POSITIVE_INTEGER_CANDIDATES) { 333 int floor = IntMath.sqrt(x, FLOOR); 334 // We only expect an exception if x was not a perfect square. 335 boolean isPerfectSquare = (floor * floor == x); 336 try { 337 assertEquals(floor, IntMath.sqrt(x, UNNECESSARY)); 338 assertTrue(isPerfectSquare); 339 } catch (ArithmeticException e) { 340 assertFalse(isPerfectSquare); 341 } 342 } 343 } 344 345 @GwtIncompatible // 2147483646^2 expected=4 testPow()346 public void testPow() { 347 for (int i : ALL_INTEGER_CANDIDATES) { 348 for (int pow : EXPONENTS) { 349 assertEquals(i + "^" + pow, BigInteger.valueOf(i).pow(pow).intValue(), IntMath.pow(i, pow)); 350 } 351 } 352 } 353 354 @AndroidIncompatible // slow testDivNonZero()355 public void testDivNonZero() { 356 for (int p : NONZERO_INTEGER_CANDIDATES) { 357 for (int q : NONZERO_INTEGER_CANDIDATES) { 358 for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) { 359 // Skip some tests that fail due to GWT's non-compliant int implementation. 360 // TODO(cpovirk): does this test fail for only some rounding modes or for all? 361 if (p == -2147483648 && q == -1 && intsCanGoOutOfRange()) { 362 continue; 363 } 364 int expected = 365 new BigDecimal(valueOf(p)).divide(new BigDecimal(valueOf(q)), 0, mode).intValue(); 366 assertEquals(p + "/" + q, force32(expected), IntMath.divide(p, q, mode)); 367 } 368 } 369 } 370 } 371 372 @AndroidIncompatible // presumably slow testDivNonZeroExact()373 public void testDivNonZeroExact() { 374 for (int p : NONZERO_INTEGER_CANDIDATES) { 375 for (int q : NONZERO_INTEGER_CANDIDATES) { 376 // Skip some tests that fail due to GWT's non-compliant int implementation. 377 if (p == -2147483648 && q == -1 && intsCanGoOutOfRange()) { 378 continue; 379 } 380 boolean dividesEvenly = (p % q) == 0; 381 try { 382 assertEquals(p + "/" + q, p, IntMath.divide(p, q, UNNECESSARY) * q); 383 assertTrue(p + "/" + q + " not expected to divide evenly", dividesEvenly); 384 } catch (ArithmeticException e) { 385 assertFalse(p + "/" + q + " expected to divide evenly", dividesEvenly); 386 } 387 } 388 } 389 } 390 testZeroDivIsAlwaysZero()391 public void testZeroDivIsAlwaysZero() { 392 for (int q : NONZERO_INTEGER_CANDIDATES) { 393 for (RoundingMode mode : ALL_ROUNDING_MODES) { 394 assertEquals(0, IntMath.divide(0, q, mode)); 395 } 396 } 397 } 398 testDivByZeroAlwaysFails()399 public void testDivByZeroAlwaysFails() { 400 for (int p : ALL_INTEGER_CANDIDATES) { 401 for (RoundingMode mode : ALL_ROUNDING_MODES) { 402 try { 403 IntMath.divide(p, 0, mode); 404 fail("Expected ArithmeticException"); 405 } catch (ArithmeticException expected) { 406 } 407 } 408 } 409 } 410 testMod()411 public void testMod() { 412 for (int x : ALL_INTEGER_CANDIDATES) { 413 for (int m : POSITIVE_INTEGER_CANDIDATES) { 414 assertEquals(valueOf(x).mod(valueOf(m)).intValue(), IntMath.mod(x, m)); 415 } 416 } 417 } 418 testModNegativeModulusFails()419 public void testModNegativeModulusFails() { 420 for (int x : POSITIVE_INTEGER_CANDIDATES) { 421 for (int m : NEGATIVE_INTEGER_CANDIDATES) { 422 try { 423 IntMath.mod(x, m); 424 fail("Expected ArithmeticException"); 425 } catch (ArithmeticException expected) { 426 } 427 } 428 } 429 } 430 testModZeroModulusFails()431 public void testModZeroModulusFails() { 432 for (int x : ALL_INTEGER_CANDIDATES) { 433 try { 434 IntMath.mod(x, 0); 435 fail("Expected ArithmeticException"); 436 } catch (ArithmeticException expected) { 437 } 438 } 439 } 440 testGCD()441 public void testGCD() { 442 for (int a : POSITIVE_INTEGER_CANDIDATES) { 443 for (int b : POSITIVE_INTEGER_CANDIDATES) { 444 assertEquals(valueOf(a).gcd(valueOf(b)), valueOf(IntMath.gcd(a, b))); 445 } 446 } 447 } 448 testGCDZero()449 public void testGCDZero() { 450 for (int a : POSITIVE_INTEGER_CANDIDATES) { 451 assertEquals(a, IntMath.gcd(a, 0)); 452 assertEquals(a, IntMath.gcd(0, a)); 453 } 454 assertEquals(0, IntMath.gcd(0, 0)); 455 } 456 testGCDNegativePositiveThrows()457 public void testGCDNegativePositiveThrows() { 458 for (int a : NEGATIVE_INTEGER_CANDIDATES) { 459 try { 460 IntMath.gcd(a, 3); 461 fail("Expected IllegalArgumentException"); 462 } catch (IllegalArgumentException expected) { 463 } 464 try { 465 IntMath.gcd(3, a); 466 fail("Expected IllegalArgumentException"); 467 } catch (IllegalArgumentException expected) { 468 } 469 } 470 } 471 testGCDNegativeZeroThrows()472 public void testGCDNegativeZeroThrows() { 473 for (int a : NEGATIVE_INTEGER_CANDIDATES) { 474 try { 475 IntMath.gcd(a, 0); 476 fail("Expected IllegalArgumentException"); 477 } catch (IllegalArgumentException expected) { 478 } 479 try { 480 IntMath.gcd(0, a); 481 fail("Expected IllegalArgumentException"); 482 } catch (IllegalArgumentException expected) { 483 } 484 } 485 } 486 487 @AndroidIncompatible // slow testCheckedAdd()488 public void testCheckedAdd() { 489 for (int a : ALL_INTEGER_CANDIDATES) { 490 for (int b : ALL_INTEGER_CANDIDATES) { 491 BigInteger expectedResult = valueOf(a).add(valueOf(b)); 492 boolean expectedSuccess = fitsInInt(expectedResult); 493 try { 494 assertEquals(a + b, IntMath.checkedAdd(a, b)); 495 assertTrue(expectedSuccess); 496 } catch (ArithmeticException e) { 497 assertFalse(expectedSuccess); 498 } 499 } 500 } 501 } 502 503 @AndroidIncompatible // slow testCheckedSubtract()504 public void testCheckedSubtract() { 505 for (int a : ALL_INTEGER_CANDIDATES) { 506 for (int b : ALL_INTEGER_CANDIDATES) { 507 BigInteger expectedResult = valueOf(a).subtract(valueOf(b)); 508 boolean expectedSuccess = fitsInInt(expectedResult); 509 try { 510 assertEquals(a - b, IntMath.checkedSubtract(a, b)); 511 assertTrue(expectedSuccess); 512 } catch (ArithmeticException e) { 513 assertFalse(expectedSuccess); 514 } 515 } 516 } 517 } 518 519 @AndroidIncompatible // presumably slow testCheckedMultiply()520 public void testCheckedMultiply() { 521 for (int a : ALL_INTEGER_CANDIDATES) { 522 for (int b : ALL_INTEGER_CANDIDATES) { 523 BigInteger expectedResult = valueOf(a).multiply(valueOf(b)); 524 boolean expectedSuccess = fitsInInt(expectedResult); 525 try { 526 assertEquals(a * b, IntMath.checkedMultiply(a, b)); 527 assertTrue(expectedSuccess); 528 } catch (ArithmeticException e) { 529 assertFalse(expectedSuccess); 530 } 531 } 532 } 533 } 534 testCheckedPow()535 public void testCheckedPow() { 536 for (int b : ALL_INTEGER_CANDIDATES) { 537 for (int k : EXPONENTS) { 538 BigInteger expectedResult = valueOf(b).pow(k); 539 boolean expectedSuccess = fitsInInt(expectedResult); 540 try { 541 assertEquals(b + "^" + k, force32(expectedResult.intValue()), IntMath.checkedPow(b, k)); 542 assertTrue(b + "^" + k + " should have succeeded", expectedSuccess); 543 } catch (ArithmeticException e) { 544 assertFalse(b + "^" + k + " should have failed", expectedSuccess); 545 } 546 } 547 } 548 } 549 550 @AndroidIncompatible // slow 551 @GwtIncompatible // TODO testSaturatedAdd()552 public void testSaturatedAdd() { 553 for (int a : ALL_INTEGER_CANDIDATES) { 554 for (int b : ALL_INTEGER_CANDIDATES) { 555 assertOperationEquals( 556 a, b, "s+", saturatedCast(valueOf(a).add(valueOf(b))), IntMath.saturatedAdd(a, b)); 557 } 558 } 559 } 560 561 @AndroidIncompatible // slow 562 @GwtIncompatible // TODO testSaturatedSubtract()563 public void testSaturatedSubtract() { 564 for (int a : ALL_INTEGER_CANDIDATES) { 565 for (int b : ALL_INTEGER_CANDIDATES) { 566 assertOperationEquals( 567 a, 568 b, 569 "s-", 570 saturatedCast(valueOf(a).subtract(valueOf(b))), 571 IntMath.saturatedSubtract(a, b)); 572 } 573 } 574 } 575 576 @AndroidIncompatible // slow 577 @GwtIncompatible // TODO testSaturatedMultiply()578 public void testSaturatedMultiply() { 579 for (int a : ALL_INTEGER_CANDIDATES) { 580 for (int b : ALL_INTEGER_CANDIDATES) { 581 assertOperationEquals( 582 a, 583 b, 584 "s*", 585 saturatedCast(valueOf(a).multiply(valueOf(b))), 586 IntMath.saturatedMultiply(a, b)); 587 } 588 } 589 } 590 591 @GwtIncompatible // TODO testSaturatedPow()592 public void testSaturatedPow() { 593 for (int a : ALL_INTEGER_CANDIDATES) { 594 for (int b : EXPONENTS) { 595 assertOperationEquals( 596 a, b, "s^", saturatedCast(valueOf(a).pow(b)), IntMath.saturatedPow(a, b)); 597 } 598 } 599 } 600 601 private static final BigInteger MAX_INT = BigInteger.valueOf(Integer.MAX_VALUE); 602 private static final BigInteger MIN_INT = BigInteger.valueOf(Integer.MIN_VALUE); 603 saturatedCast(BigInteger big)604 private static int saturatedCast(BigInteger big) { 605 if (big.compareTo(MAX_INT) > 0) { 606 return Integer.MAX_VALUE; 607 } 608 if (big.compareTo(MIN_INT) < 0) { 609 return Integer.MIN_VALUE; 610 } 611 return big.intValue(); 612 } 613 assertOperationEquals(int a, int b, String op, int expected, int actual)614 private void assertOperationEquals(int a, int b, String op, int expected, int actual) { 615 if (expected != actual) { 616 fail("Expected for " + a + " " + op + " " + b + " = " + expected + ", but got " + actual); 617 } 618 } 619 620 // Depends on the correctness of BigIntegerMath.factorial. testFactorial()621 public void testFactorial() { 622 for (int n = 0; n <= 50; n++) { 623 BigInteger expectedBig = BigIntegerMath.factorial(n); 624 int expectedInt = fitsInInt(expectedBig) ? expectedBig.intValue() : Integer.MAX_VALUE; 625 assertEquals(expectedInt, IntMath.factorial(n)); 626 } 627 } 628 testFactorialNegative()629 public void testFactorialNegative() { 630 for (int n : NEGATIVE_INTEGER_CANDIDATES) { 631 try { 632 IntMath.factorial(n); 633 fail("Expected IllegalArgumentException"); 634 } catch (IllegalArgumentException expected) { 635 } 636 } 637 } 638 639 // Depends on the correctness of BigIntegerMath.binomial. testBinomial()640 public void testBinomial() { 641 for (int n = 0; n <= 50; n++) { 642 for (int k = 0; k <= n; k++) { 643 BigInteger expectedBig = BigIntegerMath.binomial(n, k); 644 int expectedInt = fitsInInt(expectedBig) ? expectedBig.intValue() : Integer.MAX_VALUE; 645 assertEquals(expectedInt, IntMath.binomial(n, k)); 646 } 647 } 648 } 649 testBinomialOutside()650 public void testBinomialOutside() { 651 for (int n = 0; n <= 50; n++) { 652 try { 653 IntMath.binomial(n, -1); 654 fail("Expected IllegalArgumentException"); 655 } catch (IllegalArgumentException expected) { 656 } 657 try { 658 IntMath.binomial(n, n + 1); 659 fail("Expected IllegalArgumentException"); 660 } catch (IllegalArgumentException expected) { 661 } 662 } 663 } 664 testBinomialNegative()665 public void testBinomialNegative() { 666 for (int n : NEGATIVE_INTEGER_CANDIDATES) { 667 try { 668 IntMath.binomial(n, 0); 669 fail("Expected IllegalArgumentException"); 670 } catch (IllegalArgumentException expected) { 671 } 672 } 673 } 674 675 @AndroidIncompatible // slow 676 @GwtIncompatible // java.math.BigInteger testMean()677 public void testMean() { 678 // Odd-sized ranges have an obvious mean 679 assertMean(2, 1, 3); 680 681 assertMean(-2, -3, -1); 682 assertMean(0, -1, 1); 683 assertMean(1, -1, 3); 684 assertMean((1 << 30) - 1, -1, Integer.MAX_VALUE); 685 686 // Even-sized ranges should prefer the lower mean 687 assertMean(2, 1, 4); 688 assertMean(-3, -4, -1); 689 assertMean(0, -1, 2); 690 assertMean(0, Integer.MIN_VALUE + 2, Integer.MAX_VALUE); 691 assertMean(0, 0, 1); 692 assertMean(-1, -1, 0); 693 assertMean(-1, Integer.MIN_VALUE, Integer.MAX_VALUE); 694 695 // x == y == mean 696 assertMean(1, 1, 1); 697 assertMean(0, 0, 0); 698 assertMean(-1, -1, -1); 699 assertMean(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE); 700 assertMean(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE); 701 702 // Exhaustive checks 703 for (int x : ALL_INTEGER_CANDIDATES) { 704 for (int y : ALL_INTEGER_CANDIDATES) { 705 assertMean(x, y); 706 } 707 } 708 } 709 710 /** Helper method that asserts the arithmetic mean of x and y is equal to the expectedMean. */ assertMean(int expectedMean, int x, int y)711 private static void assertMean(int expectedMean, int x, int y) { 712 assertEquals( 713 "The expectedMean should be the same as computeMeanSafely", 714 expectedMean, 715 computeMeanSafely(x, y)); 716 assertMean(x, y); 717 } 718 719 /** 720 * Helper method that asserts the arithmetic mean of x and y is equal to the result of 721 * computeMeanSafely. 722 */ assertMean(int x, int y)723 private static void assertMean(int x, int y) { 724 int expectedMean = computeMeanSafely(x, y); 725 assertEquals(expectedMean, IntMath.mean(x, y)); 726 assertEquals( 727 "The mean of x and y should equal the mean of y and x", expectedMean, IntMath.mean(y, x)); 728 } 729 730 /** 731 * Computes the mean in a way that is obvious and resilient to overflow by using BigInteger 732 * arithmetic. 733 */ computeMeanSafely(int x, int y)734 private static int computeMeanSafely(int x, int y) { 735 BigInteger bigX = BigInteger.valueOf(x); 736 BigInteger bigY = BigInteger.valueOf(y); 737 BigDecimal bigMean = 738 new BigDecimal(bigX.add(bigY)).divide(BigDecimal.valueOf(2), BigDecimal.ROUND_FLOOR); 739 // parseInt blows up on overflow as opposed to intValue() which does not. 740 return Integer.parseInt(bigMean.toString()); 741 } 742 fitsInInt(BigInteger big)743 private static boolean fitsInInt(BigInteger big) { 744 return big.bitLength() <= 31; 745 } 746 747 @GwtIncompatible // NullPointerTester testNullPointers()748 public void testNullPointers() { 749 NullPointerTester tester = new NullPointerTester(); 750 tester.setDefault(int.class, 1); 751 tester.testAllPublicStaticMethods(IntMath.class); 752 } 753 754 @GwtIncompatible // isPrime is GWT-incompatible testIsPrime()755 public void testIsPrime() { 756 // Defer correctness tests to Long.isPrime 757 758 // Check the first 100,000 integers 759 for (int i = 0; i < 100000; i++) { 760 assertEquals(LongMath.isPrime(i), IntMath.isPrime(i)); 761 } 762 763 // Then check 1000 deterministic pseudo-random int values. 764 Random rand = new Random(1); 765 for (int i = 0; i < 1000; i++) { 766 int n = rand.nextInt(Integer.MAX_VALUE); 767 assertEquals(LongMath.isPrime(n), IntMath.isPrime(n)); 768 } 769 } 770 force32(int value)771 private static int force32(int value) { 772 // GWT doesn't consistently overflow values to make them 32-bit, so we need to force it. 773 return value & 0xffffffff; 774 } 775 } 776