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_LONG_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.NEGATIVE_LONG_CANDIDATES; 25 import static com.google.common.math.MathTesting.NONZERO_LONG_CANDIDATES; 26 import static com.google.common.math.MathTesting.POSITIVE_INTEGER_CANDIDATES; 27 import static com.google.common.math.MathTesting.POSITIVE_LONG_CANDIDATES; 28 import static com.google.common.truth.Truth.assertThat; 29 import static com.google.common.truth.Truth.assertWithMessage; 30 import static java.math.BigInteger.valueOf; 31 import static java.math.RoundingMode.FLOOR; 32 import static java.math.RoundingMode.UNNECESSARY; 33 34 import com.google.common.annotations.GwtCompatible; 35 import com.google.common.annotations.GwtIncompatible; 36 import com.google.common.testing.NullPointerTester; 37 import java.math.BigDecimal; 38 import java.math.BigInteger; 39 import java.math.RoundingMode; 40 import java.util.EnumSet; 41 import java.util.Random; 42 import junit.framework.TestCase; 43 44 /** 45 * Tests for LongMath. 46 * 47 * @author Louis Wasserman 48 */ 49 @GwtCompatible(emulated = true) 50 public class LongMathTest extends TestCase { 51 @SuppressWarnings("ConstantOverflow") testMaxSignedPowerOfTwo()52 public void testMaxSignedPowerOfTwo() { 53 assertTrue(LongMath.isPowerOfTwo(LongMath.MAX_SIGNED_POWER_OF_TWO)); 54 assertFalse(LongMath.isPowerOfTwo(LongMath.MAX_SIGNED_POWER_OF_TWO * 2)); 55 } 56 testCeilingPowerOfTwo()57 public void testCeilingPowerOfTwo() { 58 for (long x : POSITIVE_LONG_CANDIDATES) { 59 BigInteger expectedResult = BigIntegerMath.ceilingPowerOfTwo(BigInteger.valueOf(x)); 60 if (fitsInLong(expectedResult)) { 61 assertEquals(expectedResult.longValue(), LongMath.ceilingPowerOfTwo(x)); 62 } else { 63 try { 64 LongMath.ceilingPowerOfTwo(x); 65 fail("Expected ArithmeticException"); 66 } catch (ArithmeticException expected) { 67 } 68 } 69 } 70 } 71 testFloorPowerOfTwo()72 public void testFloorPowerOfTwo() { 73 for (long x : POSITIVE_LONG_CANDIDATES) { 74 BigInteger expectedResult = BigIntegerMath.floorPowerOfTwo(BigInteger.valueOf(x)); 75 assertEquals(expectedResult.longValue(), LongMath.floorPowerOfTwo(x)); 76 } 77 } 78 testCeilingPowerOfTwoNegative()79 public void testCeilingPowerOfTwoNegative() { 80 for (long x : NEGATIVE_LONG_CANDIDATES) { 81 try { 82 LongMath.ceilingPowerOfTwo(x); 83 fail("Expected IllegalArgumentException"); 84 } catch (IllegalArgumentException expected) { 85 } 86 } 87 } 88 testFloorPowerOfTwoNegative()89 public void testFloorPowerOfTwoNegative() { 90 for (long x : NEGATIVE_LONG_CANDIDATES) { 91 try { 92 LongMath.floorPowerOfTwo(x); 93 fail("Expected IllegalArgumentException"); 94 } catch (IllegalArgumentException expected) { 95 } 96 } 97 } 98 testCeilingPowerOfTwoZero()99 public void testCeilingPowerOfTwoZero() { 100 try { 101 LongMath.ceilingPowerOfTwo(0L); 102 fail("Expected IllegalArgumentException"); 103 } catch (IllegalArgumentException expected) { 104 } 105 } 106 testFloorPowerOfTwoZero()107 public void testFloorPowerOfTwoZero() { 108 try { 109 LongMath.floorPowerOfTwo(0L); 110 fail("Expected IllegalArgumentException"); 111 } catch (IllegalArgumentException expected) { 112 } 113 } 114 115 @GwtIncompatible // TODO testConstantMaxPowerOfSqrt2Unsigned()116 public void testConstantMaxPowerOfSqrt2Unsigned() { 117 assertEquals( 118 /*expected=*/ BigIntegerMath.sqrt(BigInteger.ZERO.setBit(2 * Long.SIZE - 1), FLOOR) 119 .longValue(), 120 /*actual=*/ LongMath.MAX_POWER_OF_SQRT2_UNSIGNED); 121 } 122 123 @GwtIncompatible // BigIntegerMath // TODO(cpovirk): GWT-enable BigIntegerMath testMaxLog10ForLeadingZeros()124 public void testMaxLog10ForLeadingZeros() { 125 for (int i = 0; i < Long.SIZE; i++) { 126 assertEquals( 127 BigIntegerMath.log10(BigInteger.ONE.shiftLeft(Long.SIZE - i), FLOOR), 128 LongMath.maxLog10ForLeadingZeros[i]); 129 } 130 } 131 132 @GwtIncompatible // TODO testConstantsPowersOf10()133 public void testConstantsPowersOf10() { 134 for (int i = 0; i < LongMath.powersOf10.length; i++) { 135 assertEquals(LongMath.checkedPow(10, i), LongMath.powersOf10[i]); 136 } 137 try { 138 LongMath.checkedPow(10, LongMath.powersOf10.length); 139 fail("Expected ArithmeticException"); 140 } catch (ArithmeticException expected) { 141 } 142 } 143 144 @GwtIncompatible // TODO testConstantsHalfPowersOf10()145 public void testConstantsHalfPowersOf10() { 146 for (int i = 0; i < LongMath.halfPowersOf10.length; i++) { 147 assertEquals( 148 BigIntegerMath.sqrt(BigInteger.TEN.pow(2 * i + 1), FLOOR), 149 BigInteger.valueOf(LongMath.halfPowersOf10[i])); 150 } 151 BigInteger nextBigger = 152 BigIntegerMath.sqrt(BigInteger.TEN.pow(2 * LongMath.halfPowersOf10.length + 1), FLOOR); 153 assertTrue(nextBigger.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0); 154 } 155 156 @GwtIncompatible // TODO testConstantsSqrtMaxLong()157 public void testConstantsSqrtMaxLong() { 158 assertEquals( 159 /*expected=*/ LongMath.sqrt(Long.MAX_VALUE, FLOOR), 160 /*actual=*/ LongMath.FLOOR_SQRT_MAX_LONG); 161 } 162 163 @GwtIncompatible // TODO testConstantsFactorials()164 public void testConstantsFactorials() { 165 long expected = 1; 166 for (int i = 0; i < LongMath.factorials.length; i++, expected *= i) { 167 assertEquals(expected, LongMath.factorials[i]); 168 } 169 try { 170 LongMath.checkedMultiply( 171 LongMath.factorials[LongMath.factorials.length - 1], LongMath.factorials.length); 172 fail("Expected ArithmeticException"); 173 } catch (ArithmeticException expect) { 174 } 175 } 176 177 @GwtIncompatible // TODO testConstantsBiggestBinomials()178 public void testConstantsBiggestBinomials() { 179 for (int k = 0; k < LongMath.biggestBinomials.length; k++) { 180 assertTrue(fitsInLong(BigIntegerMath.binomial(LongMath.biggestBinomials[k], k))); 181 assertTrue( 182 LongMath.biggestBinomials[k] == Integer.MAX_VALUE 183 || !fitsInLong(BigIntegerMath.binomial(LongMath.biggestBinomials[k] + 1, k))); 184 // In the first case, any long is valid; in the second, we want to test that the next-bigger 185 // long overflows. 186 } 187 int k = LongMath.biggestBinomials.length; 188 assertFalse(fitsInLong(BigIntegerMath.binomial(2 * k, k))); 189 // 2 * k is the smallest value for which we don't replace k with (n-k). 190 } 191 192 @GwtIncompatible // TODO testConstantsBiggestSimpleBinomials()193 public void testConstantsBiggestSimpleBinomials() { 194 for (int k = 0; k < LongMath.biggestSimpleBinomials.length; k++) { 195 assertTrue(LongMath.biggestSimpleBinomials[k] <= LongMath.biggestBinomials[k]); 196 long unused = simpleBinomial(LongMath.biggestSimpleBinomials[k], k); // mustn't throw 197 if (LongMath.biggestSimpleBinomials[k] < Integer.MAX_VALUE) { 198 // unless all n are fair game with this k 199 try { 200 simpleBinomial(LongMath.biggestSimpleBinomials[k] + 1, k); 201 fail("Expected ArithmeticException"); 202 } catch (ArithmeticException expected) { 203 } 204 } 205 } 206 try { 207 int k = LongMath.biggestSimpleBinomials.length; 208 simpleBinomial(2 * k, k); 209 // 2 * k is the smallest value for which we don't replace k with (n-k). 210 fail("Expected ArithmeticException"); 211 } catch (ArithmeticException expected) { 212 } 213 } 214 215 @AndroidIncompatible // slow testLessThanBranchFree()216 public void testLessThanBranchFree() { 217 for (long x : ALL_LONG_CANDIDATES) { 218 for (long y : ALL_LONG_CANDIDATES) { 219 BigInteger difference = BigInteger.valueOf(x).subtract(BigInteger.valueOf(y)); 220 if (fitsInLong(difference)) { 221 int expected = (x < y) ? 1 : 0; 222 int actual = LongMath.lessThanBranchFree(x, y); 223 assertEquals(expected, actual); 224 } 225 } 226 } 227 } 228 229 // Throws an ArithmeticException if "the simple implementation" of binomial coefficients overflows 230 @GwtIncompatible // TODO simpleBinomial(int n, int k)231 private long simpleBinomial(int n, int k) { 232 long accum = 1; 233 for (int i = 0; i < k; i++) { 234 accum = LongMath.checkedMultiply(accum, n - i); 235 accum /= i + 1; 236 } 237 return accum; 238 } 239 240 @GwtIncompatible // java.math.BigInteger testIsPowerOfTwo()241 public void testIsPowerOfTwo() { 242 for (long x : ALL_LONG_CANDIDATES) { 243 // Checks for a single bit set. 244 BigInteger bigX = BigInteger.valueOf(x); 245 boolean expected = (bigX.signum() > 0) && (bigX.bitCount() == 1); 246 assertEquals(expected, LongMath.isPowerOfTwo(x)); 247 } 248 } 249 testLog2ZeroAlwaysThrows()250 public void testLog2ZeroAlwaysThrows() { 251 for (RoundingMode mode : ALL_ROUNDING_MODES) { 252 try { 253 LongMath.log2(0L, mode); 254 fail("Expected IllegalArgumentException"); 255 } catch (IllegalArgumentException expected) { 256 } 257 } 258 } 259 testLog2NegativeAlwaysThrows()260 public void testLog2NegativeAlwaysThrows() { 261 for (long x : NEGATIVE_LONG_CANDIDATES) { 262 for (RoundingMode mode : ALL_ROUNDING_MODES) { 263 try { 264 LongMath.log2(x, mode); 265 fail("Expected IllegalArgumentException"); 266 } catch (IllegalArgumentException expected) { 267 } 268 } 269 } 270 } 271 272 /* Relies on the correctness of BigIntegerMath.log2 for all modes except UNNECESSARY. */ testLog2MatchesBigInteger()273 public void testLog2MatchesBigInteger() { 274 for (long x : POSITIVE_LONG_CANDIDATES) { 275 for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) { 276 // The BigInteger implementation is tested separately, use it as the reference. 277 assertEquals(BigIntegerMath.log2(valueOf(x), mode), LongMath.log2(x, mode)); 278 } 279 } 280 } 281 282 /* Relies on the correctness of isPowerOfTwo(long). */ testLog2Exact()283 public void testLog2Exact() { 284 for (long x : POSITIVE_LONG_CANDIDATES) { 285 // We only expect an exception if x was not a power of 2. 286 boolean isPowerOf2 = LongMath.isPowerOfTwo(x); 287 try { 288 assertEquals(x, 1L << LongMath.log2(x, UNNECESSARY)); 289 assertTrue(isPowerOf2); 290 } catch (ArithmeticException e) { 291 assertFalse(isPowerOf2); 292 } 293 } 294 } 295 296 @GwtIncompatible // TODO testLog10ZeroAlwaysThrows()297 public void testLog10ZeroAlwaysThrows() { 298 for (RoundingMode mode : ALL_ROUNDING_MODES) { 299 try { 300 LongMath.log10(0L, mode); 301 fail("Expected IllegalArgumentException"); 302 } catch (IllegalArgumentException expected) { 303 } 304 } 305 } 306 307 @GwtIncompatible // TODO testLog10NegativeAlwaysThrows()308 public void testLog10NegativeAlwaysThrows() { 309 for (long x : NEGATIVE_LONG_CANDIDATES) { 310 for (RoundingMode mode : ALL_ROUNDING_MODES) { 311 try { 312 LongMath.log10(x, mode); 313 fail("Expected IllegalArgumentException"); 314 } catch (IllegalArgumentException expected) { 315 } 316 } 317 } 318 } 319 320 // Relies on the correctness of BigIntegerMath.log10 for all modes except UNNECESSARY. 321 @GwtIncompatible // TODO testLog10MatchesBigInteger()322 public void testLog10MatchesBigInteger() { 323 for (long x : POSITIVE_LONG_CANDIDATES) { 324 for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) { 325 assertEquals(BigIntegerMath.log10(valueOf(x), mode), LongMath.log10(x, mode)); 326 } 327 } 328 } 329 330 // Relies on the correctness of log10(long, FLOOR) and of pow(long, int). 331 @GwtIncompatible // TODO testLog10Exact()332 public void testLog10Exact() { 333 for (long x : POSITIVE_LONG_CANDIDATES) { 334 int floor = LongMath.log10(x, FLOOR); 335 boolean expectedSuccess = LongMath.pow(10, floor) == x; 336 try { 337 assertEquals(floor, LongMath.log10(x, UNNECESSARY)); 338 assertTrue(expectedSuccess); 339 } catch (ArithmeticException e) { 340 if (expectedSuccess) { 341 failFormat("expected log10(%s, UNNECESSARY) = %s; got ArithmeticException", x, floor); 342 } 343 } 344 } 345 } 346 347 @GwtIncompatible // TODO testLog10TrivialOnPowerOf10()348 public void testLog10TrivialOnPowerOf10() { 349 long x = 1000000000000L; 350 for (RoundingMode mode : ALL_ROUNDING_MODES) { 351 assertEquals(12, LongMath.log10(x, mode)); 352 } 353 } 354 355 @GwtIncompatible // TODO testSqrtNegativeAlwaysThrows()356 public void testSqrtNegativeAlwaysThrows() { 357 for (long x : NEGATIVE_LONG_CANDIDATES) { 358 for (RoundingMode mode : ALL_ROUNDING_MODES) { 359 try { 360 LongMath.sqrt(x, mode); 361 fail("Expected IllegalArgumentException"); 362 } catch (IllegalArgumentException expected) { 363 } 364 } 365 } 366 } 367 368 // Relies on the correctness of BigIntegerMath.sqrt for all modes except UNNECESSARY. 369 @GwtIncompatible // TODO testSqrtMatchesBigInteger()370 public void testSqrtMatchesBigInteger() { 371 for (long x : POSITIVE_LONG_CANDIDATES) { 372 for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) { 373 // Promote the long value (rather than using longValue() on the expected value) to avoid 374 // any risk of truncation which could lead to a false positive. 375 assertEquals(BigIntegerMath.sqrt(valueOf(x), mode), valueOf(LongMath.sqrt(x, mode))); 376 } 377 } 378 } 379 380 /* Relies on the correctness of sqrt(long, FLOOR). */ 381 @GwtIncompatible // TODO testSqrtExactMatchesFloorOrThrows()382 public void testSqrtExactMatchesFloorOrThrows() { 383 for (long x : POSITIVE_LONG_CANDIDATES) { 384 long sqrtFloor = LongMath.sqrt(x, FLOOR); 385 // We only expect an exception if x was not a perfect square. 386 boolean isPerfectSquare = (sqrtFloor * sqrtFloor == x); 387 try { 388 assertEquals(sqrtFloor, LongMath.sqrt(x, UNNECESSARY)); 389 assertTrue(isPerfectSquare); 390 } catch (ArithmeticException e) { 391 assertFalse(isPerfectSquare); 392 } 393 } 394 } 395 396 @GwtIncompatible // TODO testPow()397 public void testPow() { 398 for (long i : ALL_LONG_CANDIDATES) { 399 for (int exp : EXPONENTS) { 400 assertEquals(LongMath.pow(i, exp), valueOf(i).pow(exp).longValue()); 401 } 402 } 403 } 404 405 @GwtIncompatible // TODO 406 @AndroidIncompatible // TODO(cpovirk): File BigDecimal.divide() rounding bug. testDivNonZero()407 public void testDivNonZero() { 408 for (long p : NONZERO_LONG_CANDIDATES) { 409 for (long q : NONZERO_LONG_CANDIDATES) { 410 for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) { 411 long expected = 412 new BigDecimal(valueOf(p)).divide(new BigDecimal(valueOf(q)), 0, mode).longValue(); 413 long actual = LongMath.divide(p, q, mode); 414 if (expected != actual) { 415 failFormat("expected divide(%s, %s, %s) = %s; got %s", p, q, mode, expected, actual); 416 } 417 } 418 } 419 } 420 } 421 422 @GwtIncompatible // TODO 423 @AndroidIncompatible // Bug in older versions of Android we test against, since fixed. testDivNonZeroExact()424 public void testDivNonZeroExact() { 425 for (long p : NONZERO_LONG_CANDIDATES) { 426 for (long q : NONZERO_LONG_CANDIDATES) { 427 boolean expectedSuccess = (p % q) == 0L; 428 429 try { 430 assertEquals(p, LongMath.divide(p, q, UNNECESSARY) * q); 431 assertTrue(expectedSuccess); 432 } catch (ArithmeticException e) { 433 if (expectedSuccess) { 434 failFormat( 435 "expected divide(%s, %s, UNNECESSARY) to succeed; got ArithmeticException", p, q); 436 } 437 } 438 } 439 } 440 } 441 442 @GwtIncompatible // TODO testZeroDivIsAlwaysZero()443 public void testZeroDivIsAlwaysZero() { 444 for (long q : NONZERO_LONG_CANDIDATES) { 445 for (RoundingMode mode : ALL_ROUNDING_MODES) { 446 assertEquals(0L, LongMath.divide(0L, q, mode)); 447 } 448 } 449 } 450 451 @GwtIncompatible // TODO testDivByZeroAlwaysFails()452 public void testDivByZeroAlwaysFails() { 453 for (long p : ALL_LONG_CANDIDATES) { 454 for (RoundingMode mode : ALL_ROUNDING_MODES) { 455 try { 456 LongMath.divide(p, 0L, mode); 457 fail("Expected ArithmeticException"); 458 } catch (ArithmeticException expected) { 459 } 460 } 461 } 462 } 463 464 @GwtIncompatible // TODO testIntMod()465 public void testIntMod() { 466 for (long x : ALL_LONG_CANDIDATES) { 467 for (int m : POSITIVE_INTEGER_CANDIDATES) { 468 assertEquals(valueOf(x).mod(valueOf(m)).intValue(), LongMath.mod(x, m)); 469 } 470 } 471 } 472 473 @GwtIncompatible // TODO testIntModNegativeModulusFails()474 public void testIntModNegativeModulusFails() { 475 for (long x : ALL_LONG_CANDIDATES) { 476 for (int m : NEGATIVE_INTEGER_CANDIDATES) { 477 try { 478 LongMath.mod(x, m); 479 fail("Expected ArithmeticException"); 480 } catch (ArithmeticException expected) { 481 } 482 } 483 } 484 } 485 486 @GwtIncompatible // TODO testIntModZeroModulusFails()487 public void testIntModZeroModulusFails() { 488 for (long x : ALL_LONG_CANDIDATES) { 489 try { 490 LongMath.mod(x, 0); 491 fail("Expected AE"); 492 } catch (ArithmeticException expected) { 493 } 494 } 495 } 496 497 @AndroidIncompatible // slow 498 @GwtIncompatible // TODO testMod()499 public void testMod() { 500 for (long x : ALL_LONG_CANDIDATES) { 501 for (long m : POSITIVE_LONG_CANDIDATES) { 502 assertEquals(valueOf(x).mod(valueOf(m)).longValue(), LongMath.mod(x, m)); 503 } 504 } 505 } 506 507 @GwtIncompatible // TODO testModNegativeModulusFails()508 public void testModNegativeModulusFails() { 509 for (long x : ALL_LONG_CANDIDATES) { 510 for (long m : NEGATIVE_LONG_CANDIDATES) { 511 try { 512 LongMath.mod(x, m); 513 fail("Expected ArithmeticException"); 514 } catch (ArithmeticException expected) { 515 } 516 } 517 } 518 } 519 testGCDExhaustive()520 public void testGCDExhaustive() { 521 for (long a : POSITIVE_LONG_CANDIDATES) { 522 for (long b : POSITIVE_LONG_CANDIDATES) { 523 assertEquals(valueOf(a).gcd(valueOf(b)), valueOf(LongMath.gcd(a, b))); 524 } 525 } 526 } 527 528 @GwtIncompatible // TODO testGCDZero()529 public void testGCDZero() { 530 for (long a : POSITIVE_LONG_CANDIDATES) { 531 assertEquals(a, LongMath.gcd(a, 0)); 532 assertEquals(a, LongMath.gcd(0, a)); 533 } 534 assertEquals(0, LongMath.gcd(0, 0)); 535 } 536 537 @GwtIncompatible // TODO testGCDNegativePositiveThrows()538 public void testGCDNegativePositiveThrows() { 539 for (long a : NEGATIVE_LONG_CANDIDATES) { 540 try { 541 LongMath.gcd(a, 3); 542 fail("Expected IllegalArgumentException"); 543 } catch (IllegalArgumentException expected) { 544 } 545 try { 546 LongMath.gcd(3, a); 547 fail("Expected IllegalArgumentException"); 548 } catch (IllegalArgumentException expected) { 549 } 550 } 551 } 552 553 @GwtIncompatible // TODO testGCDNegativeZeroThrows()554 public void testGCDNegativeZeroThrows() { 555 for (long a : NEGATIVE_LONG_CANDIDATES) { 556 try { 557 LongMath.gcd(a, 0); 558 fail("Expected IllegalArgumentException"); 559 } catch (IllegalArgumentException expected) { 560 } 561 try { 562 LongMath.gcd(0, a); 563 fail("Expected IllegalArgumentException"); 564 } catch (IllegalArgumentException expected) { 565 } 566 } 567 } 568 569 @AndroidIncompatible // slow 570 @GwtIncompatible // TODO testCheckedAdd()571 public void testCheckedAdd() { 572 for (long a : ALL_LONG_CANDIDATES) { 573 for (long b : ALL_LONG_CANDIDATES) { 574 BigInteger expectedResult = valueOf(a).add(valueOf(b)); 575 boolean expectedSuccess = fitsInLong(expectedResult); 576 try { 577 assertEquals(a + b, LongMath.checkedAdd(a, b)); 578 assertTrue(expectedSuccess); 579 } catch (ArithmeticException e) { 580 if (expectedSuccess) { 581 failFormat( 582 "expected checkedAdd(%s, %s) = %s; got ArithmeticException", a, b, expectedResult); 583 } 584 } 585 } 586 } 587 } 588 589 @GwtIncompatible // TODO 590 @AndroidIncompatible // slow testCheckedSubtract()591 public void testCheckedSubtract() { 592 for (long a : ALL_LONG_CANDIDATES) { 593 for (long b : ALL_LONG_CANDIDATES) { 594 BigInteger expectedResult = valueOf(a).subtract(valueOf(b)); 595 boolean expectedSuccess = fitsInLong(expectedResult); 596 try { 597 assertEquals(a - b, LongMath.checkedSubtract(a, b)); 598 assertTrue(expectedSuccess); 599 } catch (ArithmeticException e) { 600 if (expectedSuccess) { 601 failFormat( 602 "expected checkedSubtract(%s, %s) = %s; got ArithmeticException", 603 a, b, expectedResult); 604 } 605 } 606 } 607 } 608 } 609 610 @AndroidIncompatible // slow testCheckedMultiply()611 public void testCheckedMultiply() { 612 boolean isAndroid = TestPlatform.isAndroid(); 613 for (long a : ALL_LONG_CANDIDATES) { 614 for (long b : ALL_LONG_CANDIDATES) { 615 if (isAndroid && a == -4294967296L && b == 2147483648L) { 616 /* 617 * Bug in older versions of Android we test against, since fixed: -9223372036854775808L / 618 * -4294967296L = -9223372036854775808L! 619 * 620 * To be clear, this bug affects not the test's computation of the expected result but the 621 * _actual prod code_. But it probably affects only unusual cases. 622 */ 623 continue; 624 } 625 BigInteger expectedResult = valueOf(a).multiply(valueOf(b)); 626 boolean expectedSuccess = fitsInLong(expectedResult); 627 try { 628 assertEquals(a * b, LongMath.checkedMultiply(a, b)); 629 assertTrue(expectedSuccess); 630 } catch (ArithmeticException e) { 631 if (expectedSuccess) { 632 failFormat( 633 "expected checkedMultiply(%s, %s) = %s; got ArithmeticException", 634 a, b, expectedResult); 635 } 636 } 637 } 638 } 639 } 640 641 @GwtIncompatible // TODO testCheckedPow()642 public void testCheckedPow() { 643 for (long b : ALL_LONG_CANDIDATES) { 644 for (int exp : EXPONENTS) { 645 BigInteger expectedResult = valueOf(b).pow(exp); 646 boolean expectedSuccess = fitsInLong(expectedResult); 647 try { 648 assertEquals(expectedResult.longValue(), LongMath.checkedPow(b, exp)); 649 assertTrue(expectedSuccess); 650 } catch (ArithmeticException e) { 651 if (expectedSuccess) { 652 failFormat( 653 "expected checkedPow(%s, %s) = %s; got ArithmeticException", 654 b, exp, expectedResult); 655 } 656 } 657 } 658 } 659 } 660 661 @AndroidIncompatible // slow 662 @GwtIncompatible // TODO testSaturatedAdd()663 public void testSaturatedAdd() { 664 for (long a : ALL_LONG_CANDIDATES) { 665 for (long b : ALL_LONG_CANDIDATES) { 666 assertOperationEquals( 667 a, b, "s+", saturatedCast(valueOf(a).add(valueOf(b))), LongMath.saturatedAdd(a, b)); 668 } 669 } 670 } 671 672 @AndroidIncompatible // slow 673 @GwtIncompatible // TODO testSaturatedSubtract()674 public void testSaturatedSubtract() { 675 for (long a : ALL_LONG_CANDIDATES) { 676 for (long b : ALL_LONG_CANDIDATES) { 677 assertOperationEquals( 678 a, 679 b, 680 "s-", 681 saturatedCast(valueOf(a).subtract(valueOf(b))), 682 LongMath.saturatedSubtract(a, b)); 683 } 684 } 685 } 686 687 @AndroidIncompatible // slow 688 @GwtIncompatible // TODO testSaturatedMultiply()689 public void testSaturatedMultiply() { 690 for (long a : ALL_LONG_CANDIDATES) { 691 for (long b : ALL_LONG_CANDIDATES) { 692 assertOperationEquals( 693 a, 694 b, 695 "s*", 696 saturatedCast(valueOf(a).multiply(valueOf(b))), 697 LongMath.saturatedMultiply(a, b)); 698 } 699 } 700 } 701 702 @GwtIncompatible // TODO testSaturatedPow()703 public void testSaturatedPow() { 704 for (long a : ALL_LONG_CANDIDATES) { 705 for (int b : EXPONENTS) { 706 assertOperationEquals( 707 a, b, "s^", saturatedCast(valueOf(a).pow(b)), LongMath.saturatedPow(a, b)); 708 } 709 } 710 } 711 assertOperationEquals(long a, long b, String op, long expected, long actual)712 private void assertOperationEquals(long a, long b, String op, long expected, long actual) { 713 if (expected != actual) { 714 fail("Expected for " + a + " " + op + " " + b + " = " + expected + ", but got " + actual); 715 } 716 } 717 718 // Depends on the correctness of BigIntegerMath.factorial. 719 @GwtIncompatible // TODO testFactorial()720 public void testFactorial() { 721 for (int n = 0; n <= 50; n++) { 722 BigInteger expectedBig = BigIntegerMath.factorial(n); 723 long expectedLong = fitsInLong(expectedBig) ? expectedBig.longValue() : Long.MAX_VALUE; 724 assertEquals(expectedLong, LongMath.factorial(n)); 725 } 726 } 727 728 @GwtIncompatible // TODO testFactorialNegative()729 public void testFactorialNegative() { 730 for (int n : NEGATIVE_INTEGER_CANDIDATES) { 731 try { 732 LongMath.factorial(n); 733 fail("Expected IllegalArgumentException"); 734 } catch (IllegalArgumentException expected) { 735 } 736 } 737 } 738 739 // Depends on the correctness of BigIntegerMath.binomial. testBinomial()740 public void testBinomial() { 741 for (int n = 0; n <= 70; n++) { 742 for (int k = 0; k <= n; k++) { 743 BigInteger expectedBig = BigIntegerMath.binomial(n, k); 744 long expectedLong = fitsInLong(expectedBig) ? expectedBig.longValue() : Long.MAX_VALUE; 745 assertEquals(expectedLong, LongMath.binomial(n, k)); 746 } 747 } 748 } 749 750 751 @GwtIncompatible // Slow testBinomial_exhaustiveNotOverflowing()752 public void testBinomial_exhaustiveNotOverflowing() { 753 // Tests all of the inputs to LongMath.binomial that won't cause it to overflow, that weren't 754 // tested in the previous method, for k >= 3. 755 for (int k = 3; k < LongMath.biggestBinomials.length; k++) { 756 for (int n = 70; n <= LongMath.biggestBinomials[k]; n++) { 757 assertEquals(BigIntegerMath.binomial(n, k).longValue(), LongMath.binomial(n, k)); 758 } 759 } 760 } 761 testBinomialOutside()762 public void testBinomialOutside() { 763 for (int n = 0; n <= 50; n++) { 764 try { 765 LongMath.binomial(n, -1); 766 fail("Expected IllegalArgumentException"); 767 } catch (IllegalArgumentException expected) { 768 } 769 try { 770 LongMath.binomial(n, n + 1); 771 fail("Expected IllegalArgumentException"); 772 } catch (IllegalArgumentException expected) { 773 } 774 } 775 } 776 testBinomialNegative()777 public void testBinomialNegative() { 778 for (int n : NEGATIVE_INTEGER_CANDIDATES) { 779 try { 780 LongMath.binomial(n, 0); 781 fail("Expected IllegalArgumentException"); 782 } catch (IllegalArgumentException expected) { 783 } 784 } 785 } 786 787 788 @GwtIncompatible // far too slow testSqrtOfPerfectSquareAsDoubleIsPerfect()789 public void testSqrtOfPerfectSquareAsDoubleIsPerfect() { 790 // This takes just over a minute on my machine. 791 for (long n = 0; n <= LongMath.FLOOR_SQRT_MAX_LONG; n++) { 792 long actual = (long) Math.sqrt(n * n); 793 assertTrue(actual == n); 794 } 795 } 796 testSqrtOfLongIsAtMostFloorSqrtMaxLong()797 public void testSqrtOfLongIsAtMostFloorSqrtMaxLong() { 798 long sqrtMaxLong = (long) Math.sqrt(Long.MAX_VALUE); 799 assertTrue(sqrtMaxLong <= LongMath.FLOOR_SQRT_MAX_LONG); 800 } 801 802 @AndroidIncompatible // slow 803 @GwtIncompatible // java.math.BigInteger testMean()804 public void testMean() { 805 // Odd-sized ranges have an obvious mean 806 assertMean(2, 1, 3); 807 808 assertMean(-2, -3, -1); 809 assertMean(0, -1, 1); 810 assertMean(1, -1, 3); 811 assertMean((1L << 62) - 1, -1, Long.MAX_VALUE); 812 813 // Even-sized ranges should prefer the lower mean 814 assertMean(2, 1, 4); 815 assertMean(-3, -4, -1); 816 assertMean(0, -1, 2); 817 assertMean(0, Long.MIN_VALUE + 2, Long.MAX_VALUE); 818 assertMean(0, 0, 1); 819 assertMean(-1, -1, 0); 820 assertMean(-1, Long.MIN_VALUE, Long.MAX_VALUE); 821 822 // x == y == mean 823 assertMean(1, 1, 1); 824 assertMean(0, 0, 0); 825 assertMean(-1, -1, -1); 826 assertMean(Long.MIN_VALUE, Long.MIN_VALUE, Long.MIN_VALUE); 827 assertMean(Long.MAX_VALUE, Long.MAX_VALUE, Long.MAX_VALUE); 828 829 // Exhaustive checks 830 for (long x : ALL_LONG_CANDIDATES) { 831 for (long y : ALL_LONG_CANDIDATES) { 832 assertMean(x, y); 833 } 834 } 835 } 836 837 /** Helper method that asserts the arithmetic mean of x and y is equal to the expectedMean. */ assertMean(long expectedMean, long x, long y)838 private static void assertMean(long expectedMean, long x, long y) { 839 assertEquals( 840 "The expectedMean should be the same as computeMeanSafely", 841 expectedMean, 842 computeMeanSafely(x, y)); 843 assertMean(x, y); 844 } 845 846 /** 847 * Helper method that asserts the arithmetic mean of x and y is equal to the result of 848 * computeMeanSafely. 849 */ assertMean(long x, long y)850 private static void assertMean(long x, long y) { 851 long expectedMean = computeMeanSafely(x, y); 852 assertEquals(expectedMean, LongMath.mean(x, y)); 853 assertEquals( 854 "The mean of x and y should equal the mean of y and x", expectedMean, LongMath.mean(y, x)); 855 } 856 857 /** 858 * Computes the mean in a way that is obvious and resilient to overflow by using BigInteger 859 * arithmetic. 860 */ computeMeanSafely(long x, long y)861 private static long computeMeanSafely(long x, long y) { 862 BigInteger bigX = BigInteger.valueOf(x); 863 BigInteger bigY = BigInteger.valueOf(y); 864 BigDecimal bigMean = 865 new BigDecimal(bigX.add(bigY)).divide(BigDecimal.valueOf(2), BigDecimal.ROUND_FLOOR); 866 // parseInt blows up on overflow as opposed to intValue() which does not. 867 return Long.parseLong(bigMean.toString()); 868 } 869 fitsInLong(BigInteger big)870 private static boolean fitsInLong(BigInteger big) { 871 return big.bitLength() <= 63; 872 } 873 874 private static final BigInteger MAX_LONG = BigInteger.valueOf(Long.MAX_VALUE); 875 private static final BigInteger MIN_LONG = BigInteger.valueOf(Long.MIN_VALUE); 876 saturatedCast(BigInteger big)877 private static long saturatedCast(BigInteger big) { 878 if (big.compareTo(MAX_LONG) > 0) { 879 return Long.MAX_VALUE; 880 } 881 if (big.compareTo(MIN_LONG) < 0) { 882 return Long.MIN_VALUE; 883 } 884 return big.longValue(); 885 } 886 887 @GwtIncompatible // NullPointerTester testNullPointers()888 public void testNullPointers() { 889 NullPointerTester tester = new NullPointerTester(); 890 tester.setDefault(int.class, 1); 891 tester.setDefault(long.class, 1L); 892 tester.testAllPublicStaticMethods(LongMath.class); 893 } 894 895 @GwtIncompatible // isPrime is GWT-incompatible testIsPrimeSmall()896 public void testIsPrimeSmall() { 897 // Check the first 1000 integers 898 for (int i = 2; i < 1000; i++) { 899 assertEquals(BigInteger.valueOf(i).isProbablePrime(100), LongMath.isPrime(i)); 900 } 901 } 902 903 @GwtIncompatible // isPrime is GWT-incompatible testIsPrimeManyConstants()904 public void testIsPrimeManyConstants() { 905 // Test the thorough test inputs, which also includes special constants in the Miller-Rabin 906 // tests. 907 for (long l : POSITIVE_LONG_CANDIDATES) { 908 assertEquals(BigInteger.valueOf(l).isProbablePrime(100), LongMath.isPrime(l)); 909 } 910 } 911 912 @GwtIncompatible // isPrime is GWT-incompatible testIsPrimeOnUniformRandom()913 public void testIsPrimeOnUniformRandom() { 914 Random rand = new Random(1); 915 for (int bits = 10; bits < 63; bits++) { 916 for (int i = 0; i < 2000; i++) { 917 // A random long between 0 and Long.MAX_VALUE, inclusive. 918 long l = rand.nextLong() & ((1L << bits) - 1); 919 assertEquals(BigInteger.valueOf(l).isProbablePrime(100), LongMath.isPrime(l)); 920 } 921 } 922 } 923 924 @GwtIncompatible // isPrime is GWT-incompatible testIsPrimeOnRandomPrimes()925 public void testIsPrimeOnRandomPrimes() { 926 Random rand = new Random(1); 927 for (int bits = 10; bits < 63; bits++) { 928 for (int i = 0; i < 100; i++) { 929 long p = BigInteger.probablePrime(bits, rand).longValue(); 930 assertTrue(LongMath.isPrime(p)); 931 } 932 } 933 } 934 935 @GwtIncompatible // isPrime is GWT-incompatible testIsPrimeOnRandomComposites()936 public void testIsPrimeOnRandomComposites() { 937 Random rand = new Random(1); 938 for (int bits = 5; bits < 32; bits++) { 939 for (int i = 0; i < 100; i++) { 940 long p = BigInteger.probablePrime(bits, rand).longValue(); 941 long q = BigInteger.probablePrime(bits, rand).longValue(); 942 assertFalse(LongMath.isPrime(p * q)); 943 } 944 } 945 } 946 947 @GwtIncompatible // isPrime is GWT-incompatible testIsPrimeThrowsOnNegative()948 public void testIsPrimeThrowsOnNegative() { 949 try { 950 LongMath.isPrime(-1); 951 fail("Expected IllegalArgumentException"); 952 } catch (IllegalArgumentException expected) { 953 } 954 } 955 956 private static final long[] roundToDoubleTestCandidates = { 957 0, 958 16, 959 1L << 53, 960 (1L << 53) + 1, 961 (1L << 53) + 2, 962 (1L << 53) + 3, 963 (1L << 53) + 4, 964 1L << 54, 965 (1L << 54) + 1, 966 (1L << 54) + 2, 967 (1L << 54) + 3, 968 (1L << 54) + 4, 969 0x7ffffffffffffe00L, // halfway between 2^63 and next-lower double 970 0x7ffffffffffffe01L, // above + 1 971 0x7ffffffffffffdffL, // above - 1 972 Long.MAX_VALUE - (1L << 11) + 1, 973 Long.MAX_VALUE - 2, 974 Long.MAX_VALUE - 1, 975 Long.MAX_VALUE, 976 -16, 977 -1L << 53, 978 -(1L << 53) - 1, 979 -(1L << 53) - 2, 980 -(1L << 53) - 3, 981 -(1L << 53) - 4, 982 -1L << 54, 983 -(1L << 54) - 1, 984 -(1L << 54) - 2, 985 -(1L << 54) - 3, 986 -(1L << 54) - 4, 987 Long.MIN_VALUE + 2, 988 Long.MIN_VALUE + 1, 989 Long.MIN_VALUE 990 }; 991 992 @GwtIncompatible testRoundToDoubleAgainstBigInteger()993 public void testRoundToDoubleAgainstBigInteger() { 994 for (RoundingMode roundingMode : EnumSet.complementOf(EnumSet.of(UNNECESSARY))) { 995 for (long candidate : roundToDoubleTestCandidates) { 996 assertThat(LongMath.roundToDouble(candidate, roundingMode)) 997 .isEqualTo(BigIntegerMath.roundToDouble(BigInteger.valueOf(candidate), roundingMode)); 998 } 999 } 1000 } 1001 1002 @GwtIncompatible testRoundToDoubleAgainstBigIntegerUnnecessary()1003 public void testRoundToDoubleAgainstBigIntegerUnnecessary() { 1004 for (long candidate : roundToDoubleTestCandidates) { 1005 Double expectedDouble = null; 1006 try { 1007 expectedDouble = BigIntegerMath.roundToDouble(BigInteger.valueOf(candidate), UNNECESSARY); 1008 } catch (ArithmeticException expected) { 1009 // do nothing 1010 } 1011 1012 if (expectedDouble != null) { 1013 assertThat(LongMath.roundToDouble(candidate, UNNECESSARY)).isEqualTo(expectedDouble); 1014 } else { 1015 try { 1016 LongMath.roundToDouble(candidate, UNNECESSARY); 1017 fail("Expected ArithmeticException on roundToDouble(" + candidate + ", UNNECESSARY)"); 1018 } catch (ArithmeticException expected) { 1019 // success 1020 } 1021 } 1022 } 1023 } 1024 failFormat(String template, Object... args)1025 private static void failFormat(String template, Object... args) { 1026 assertWithMessage(template, args).fail(); 1027 } 1028 } 1029