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