• 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.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