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