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