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