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