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_INTEGER_CANDIDATES;
20 import static com.google.common.math.MathTesting.ALL_LONG_CANDIDATES;
21 import static com.google.common.math.MathTesting.ALL_ROUNDING_MODES;
22 import static com.google.common.math.MathTesting.ALL_SAFE_ROUNDING_MODES;
23 import static com.google.common.math.MathTesting.EXPONENTS;
24 import static com.google.common.math.MathTesting.NEGATIVE_INTEGER_CANDIDATES;
25 import static com.google.common.math.MathTesting.NEGATIVE_LONG_CANDIDATES;
26 import static com.google.common.math.MathTesting.NONZERO_LONG_CANDIDATES;
27 import static com.google.common.math.MathTesting.POSITIVE_INTEGER_CANDIDATES;
28 import static com.google.common.math.MathTesting.POSITIVE_LONG_CANDIDATES;
29 import static java.math.BigInteger.valueOf;
30 import static java.math.RoundingMode.FLOOR;
31 import static java.math.RoundingMode.UNNECESSARY;
32 
33 import com.google.common.annotations.GwtCompatible;
34 import com.google.common.annotations.GwtIncompatible;
35 import com.google.common.testing.NullPointerTester;
36 
37 import junit.framework.TestCase;
38 
39 import java.math.BigDecimal;
40 import java.math.BigInteger;
41 import java.math.RoundingMode;
42 
43 /**
44  * Tests for LongMath.
45  *
46  * @author Louis Wasserman
47  */
48 @GwtCompatible(emulated = true)
49 public class LongMathTest extends TestCase {
50   @GwtIncompatible("TODO")
testConstantMaxPowerOfSqrt2Unsigned()51   public void testConstantMaxPowerOfSqrt2Unsigned() {
52     assertEquals(BigIntegerMath.sqrt(BigInteger.ZERO.setBit(2 * Long.SIZE - 1), FLOOR).longValue(),
53         LongMath.MAX_POWER_OF_SQRT2_UNSIGNED);
54   }
55 
56   @GwtIncompatible("BigIntegerMath") // TODO(cpovirk): GWT-enable BigIntegerMath
testMaxLog10ForLeadingZeros()57   public void testMaxLog10ForLeadingZeros() {
58     for (int i = 0; i < Long.SIZE; i++) {
59       assertEquals(
60           BigIntegerMath.log10(BigInteger.ONE.shiftLeft(Long.SIZE - i), FLOOR),
61           LongMath.maxLog10ForLeadingZeros[i]);
62     }
63   }
64 
65   @GwtIncompatible("TODO")
testConstantsPowersOf10()66   public void testConstantsPowersOf10() {
67     for (int i = 0; i < LongMath.powersOf10.length; i++) {
68       assertEquals(LongMath.checkedPow(10, i), LongMath.powersOf10[i]);
69     }
70     try {
71       LongMath.checkedPow(10, LongMath.powersOf10.length);
72       fail("Expected ArithmeticException");
73     } catch (ArithmeticException expected) {}
74   }
75 
76   @GwtIncompatible("TODO")
testConstantsHalfPowersOf10()77   public void testConstantsHalfPowersOf10() {
78     for (int i = 0; i < LongMath.halfPowersOf10.length; i++) {
79       assertEquals(BigIntegerMath.sqrt(BigInteger.TEN.pow(2 * i + 1), FLOOR),
80           BigInteger.valueOf(LongMath.halfPowersOf10[i]));
81     }
82     BigInteger nextBigger =
83         BigIntegerMath.sqrt(BigInteger.TEN.pow(2 * LongMath.halfPowersOf10.length + 1), FLOOR);
84     assertTrue(nextBigger.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0);
85   }
86 
87   @GwtIncompatible("TODO")
testConstantsSqrtMaxLong()88   public void testConstantsSqrtMaxLong() {
89     assertEquals(LongMath.sqrt(Long.MAX_VALUE, FLOOR), LongMath.FLOOR_SQRT_MAX_LONG);
90   }
91 
92   @GwtIncompatible("TODO")
testConstantsFactorials()93   public void testConstantsFactorials() {
94     long expected = 1;
95     for (int i = 0; i < LongMath.factorials.length; i++, expected *= i) {
96       assertEquals(expected, LongMath.factorials[i]);
97     }
98     try {
99       LongMath.checkedMultiply(
100           LongMath.factorials[LongMath.factorials.length - 1], LongMath.factorials.length);
101       fail("Expected ArithmeticException");
102     } catch (ArithmeticException expect) {}
103   }
104 
105   @GwtIncompatible("TODO")
testConstantsBiggestBinomials()106   public void testConstantsBiggestBinomials() {
107     for (int k = 0; k < LongMath.biggestBinomials.length; k++) {
108       assertTrue(fitsInLong(BigIntegerMath.binomial(LongMath.biggestBinomials[k], k)));
109       assertTrue(LongMath.biggestBinomials[k] == Integer.MAX_VALUE
110           || !fitsInLong(BigIntegerMath.binomial(LongMath.biggestBinomials[k] + 1, k)));
111       // In the first case, any long is valid; in the second, we want to test that the next-bigger
112       // long overflows.
113     }
114     int k = LongMath.biggestBinomials.length;
115     assertFalse(fitsInLong(BigIntegerMath.binomial(2 * k, k)));
116     // 2 * k is the smallest value for which we don't replace k with (n-k).
117   }
118 
119   @GwtIncompatible("TODO")
testConstantsBiggestSimpleBinomials()120   public void testConstantsBiggestSimpleBinomials() {
121     for (int k = 0; k < LongMath.biggestSimpleBinomials.length; k++) {
122       assertTrue(LongMath.biggestSimpleBinomials[k] <= LongMath.biggestBinomials[k]);
123       simpleBinomial(LongMath.biggestSimpleBinomials[k], k); // mustn't throw
124       if (LongMath.biggestSimpleBinomials[k] < Integer.MAX_VALUE) {
125         // unless all n are fair game with this k
126         try {
127           simpleBinomial(LongMath.biggestSimpleBinomials[k] + 1, k);
128           fail("Expected ArithmeticException");
129         } catch (ArithmeticException expected) {}
130       }
131     }
132     try {
133       int k = LongMath.biggestSimpleBinomials.length;
134       simpleBinomial(2 * k, k);
135       // 2 * k is the smallest value for which we don't replace k with (n-k).
136       fail("Expected ArithmeticException");
137     } catch (ArithmeticException expected) {}
138   }
139 
testLessThanBranchFree()140   public void testLessThanBranchFree() {
141     for (long x : ALL_LONG_CANDIDATES) {
142       for (long y : ALL_LONG_CANDIDATES) {
143         BigInteger difference = BigInteger.valueOf(x).subtract(BigInteger.valueOf(y));
144         if (fitsInLong(difference)) {
145           int expected = (x < y) ? 1 : 0;
146           int actual = LongMath.lessThanBranchFree(x, y);
147           assertEquals(expected, actual);
148         }
149       }
150     }
151   }
152 
153   // Throws an ArithmeticException if "the simple implementation" of binomial coefficients overflows
154   @GwtIncompatible("TODO")
simpleBinomial(int n, int k)155   private long simpleBinomial(int n, int k) {
156     long accum = 1;
157     for (int i = 0; i < k; i++) {
158       accum = LongMath.checkedMultiply(accum, n - i);
159       accum /= i + 1;
160     }
161     return accum;
162   }
163 
164   @GwtIncompatible("java.math.BigInteger")
testIsPowerOfTwo()165   public void testIsPowerOfTwo() {
166     for (long x : ALL_LONG_CANDIDATES) {
167       // Checks for a single bit set.
168       BigInteger bigX = BigInteger.valueOf(x);
169       boolean expected = (bigX.signum() > 0) && (bigX.bitCount() == 1);
170       assertEquals(expected, LongMath.isPowerOfTwo(x));
171     }
172   }
173 
testLog2ZeroAlwaysThrows()174   public void testLog2ZeroAlwaysThrows() {
175     for (RoundingMode mode : ALL_ROUNDING_MODES) {
176       try {
177         LongMath.log2(0L, mode);
178         fail("Expected IllegalArgumentException");
179       } catch (IllegalArgumentException expected) {}
180     }
181   }
182 
testLog2NegativeAlwaysThrows()183   public void testLog2NegativeAlwaysThrows() {
184     for (long x : NEGATIVE_LONG_CANDIDATES) {
185       for (RoundingMode mode : ALL_ROUNDING_MODES) {
186         try {
187           LongMath.log2(x, mode);
188           fail("Expected IllegalArgumentException");
189         } catch (IllegalArgumentException expected) {}
190       }
191     }
192   }
193 
194   /* Relies on the correctness of BigIntegerMath.log2 for all modes except UNNECESSARY. */
testLog2MatchesBigInteger()195   public void testLog2MatchesBigInteger() {
196     for (long x : POSITIVE_LONG_CANDIDATES) {
197       for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
198         // The BigInteger implementation is tested separately, use it as the reference.
199         assertEquals(BigIntegerMath.log2(valueOf(x), mode), LongMath.log2(x, mode));
200       }
201     }
202   }
203 
204   /* Relies on the correctness of isPowerOfTwo(long). */
testLog2Exact()205   public void testLog2Exact() {
206     for (long x : POSITIVE_LONG_CANDIDATES) {
207       // We only expect an exception if x was not a power of 2.
208       boolean isPowerOf2 = LongMath.isPowerOfTwo(x);
209       try {
210         assertEquals(x, 1L << LongMath.log2(x, UNNECESSARY));
211         assertTrue(isPowerOf2);
212       } catch (ArithmeticException e) {
213         assertFalse(isPowerOf2);
214       }
215     }
216   }
217 
218   @GwtIncompatible("TODO")
testLog10ZeroAlwaysThrows()219   public void testLog10ZeroAlwaysThrows() {
220     for (RoundingMode mode : ALL_ROUNDING_MODES) {
221       try {
222         LongMath.log10(0L, mode);
223         fail("Expected IllegalArgumentException");
224       } catch (IllegalArgumentException expected) {}
225     }
226   }
227 
228   @GwtIncompatible("TODO")
testLog10NegativeAlwaysThrows()229   public void testLog10NegativeAlwaysThrows() {
230     for (long x : NEGATIVE_LONG_CANDIDATES) {
231       for (RoundingMode mode : ALL_ROUNDING_MODES) {
232         try {
233           LongMath.log10(x, mode);
234           fail("Expected IllegalArgumentException");
235         } catch (IllegalArgumentException expected) {}
236       }
237     }
238   }
239 
240   // Relies on the correctness of BigIntegerMath.log10 for all modes except UNNECESSARY.
241   @GwtIncompatible("TODO")
testLog10MatchesBigInteger()242   public void testLog10MatchesBigInteger() {
243     for (long x : POSITIVE_LONG_CANDIDATES) {
244       for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
245         assertEquals(BigIntegerMath.log10(valueOf(x), mode), LongMath.log10(x, mode));
246       }
247     }
248   }
249 
250   // Relies on the correctness of log10(long, FLOOR) and of pow(long, int).
251   @GwtIncompatible("TODO")
testLog10Exact()252   public void testLog10Exact() {
253     for (long x : POSITIVE_LONG_CANDIDATES) {
254       int floor = LongMath.log10(x, FLOOR);
255       boolean expectSuccess = LongMath.pow(10, floor) == x;
256       try {
257         assertEquals(floor, LongMath.log10(x, UNNECESSARY));
258         assertTrue(expectSuccess);
259       } catch (ArithmeticException e) {
260         assertFalse(expectSuccess);
261       }
262     }
263   }
264 
265   @GwtIncompatible("TODO")
testLog10TrivialOnPowerOf10()266   public void testLog10TrivialOnPowerOf10() {
267     long x = 1000000000000L;
268     for (RoundingMode mode : ALL_ROUNDING_MODES) {
269       assertEquals(12, LongMath.log10(x, mode));
270     }
271   }
272 
273   @GwtIncompatible("TODO")
testSqrtNegativeAlwaysThrows()274   public void testSqrtNegativeAlwaysThrows() {
275     for (long x : NEGATIVE_LONG_CANDIDATES) {
276       for (RoundingMode mode : ALL_ROUNDING_MODES) {
277         try {
278           LongMath.sqrt(x, mode);
279           fail("Expected IllegalArgumentException");
280         } catch (IllegalArgumentException expected) {}
281       }
282     }
283   }
284 
285   // Relies on the correctness of BigIntegerMath.sqrt for all modes except UNNECESSARY.
286   @GwtIncompatible("TODO")
testSqrtMatchesBigInteger()287   public void testSqrtMatchesBigInteger() {
288     for (long x : POSITIVE_LONG_CANDIDATES) {
289       for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
290         // Promote the long value (rather than using longValue() on the expected value) to avoid
291         // any risk of truncation which could lead to a false positive.
292         assertEquals(BigIntegerMath.sqrt(valueOf(x), mode), valueOf(LongMath.sqrt(x, mode)));
293       }
294     }
295   }
296 
297   /* Relies on the correctness of sqrt(long, FLOOR). */
298   @GwtIncompatible("TODO")
testSqrtExactMatchesFloorOrThrows()299   public void testSqrtExactMatchesFloorOrThrows() {
300     for (long x : POSITIVE_LONG_CANDIDATES) {
301       long sqrtFloor = LongMath.sqrt(x, FLOOR);
302       // We only expect an exception if x was not a perfect square.
303       boolean isPerfectSquare = (sqrtFloor * sqrtFloor == x);
304       try {
305         assertEquals(sqrtFloor, LongMath.sqrt(x, UNNECESSARY));
306         assertTrue(isPerfectSquare);
307       } catch (ArithmeticException e) {
308         assertFalse(isPerfectSquare);
309       }
310     }
311   }
312 
313   @GwtIncompatible("TODO")
testPow()314   public void testPow() {
315     for (long i : ALL_LONG_CANDIDATES) {
316       for (int exp : EXPONENTS) {
317         assertEquals(LongMath.pow(i, exp), valueOf(i)
318             .pow(exp)
319             .longValue());
320       }
321     }
322   }
323 
324   @GwtIncompatible("TODO")
testDivNonZero()325   public void testDivNonZero() {
326     for (long p : NONZERO_LONG_CANDIDATES) {
327       for (long q : NONZERO_LONG_CANDIDATES) {
328         for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
329           long expected =
330               new BigDecimal(valueOf(p)).divide(new BigDecimal(valueOf(q)), 0, mode).longValue();
331           assertEquals(expected, LongMath.divide(p, q, mode));
332         }
333       }
334     }
335   }
336 
337   @GwtIncompatible("TODO")
testDivNonZeroExact()338   public void testDivNonZeroExact() {
339     for (long p : NONZERO_LONG_CANDIDATES) {
340       for (long q : NONZERO_LONG_CANDIDATES) {
341         boolean dividesEvenly = (p % q) == 0L;
342 
343         try {
344           assertEquals(p, LongMath.divide(p, q, UNNECESSARY) * q);
345           assertTrue(dividesEvenly);
346         } catch (ArithmeticException e) {
347           assertFalse(dividesEvenly);
348         }
349       }
350     }
351   }
352 
353   @GwtIncompatible("TODO")
testZeroDivIsAlwaysZero()354   public void testZeroDivIsAlwaysZero() {
355     for (long q : NONZERO_LONG_CANDIDATES) {
356       for (RoundingMode mode : ALL_ROUNDING_MODES) {
357         assertEquals(0L, LongMath.divide(0L, q, mode));
358       }
359     }
360   }
361 
362   @GwtIncompatible("TODO")
testDivByZeroAlwaysFails()363   public void testDivByZeroAlwaysFails() {
364     for (long p : ALL_LONG_CANDIDATES) {
365       for (RoundingMode mode : ALL_ROUNDING_MODES) {
366         try {
367           LongMath.divide(p, 0L, mode);
368           fail("Expected ArithmeticException");
369         } catch (ArithmeticException expected) {}
370       }
371     }
372   }
373 
374   @GwtIncompatible("TODO")
testIntMod()375   public void testIntMod() {
376     for (long x : ALL_LONG_CANDIDATES) {
377       for (int m : POSITIVE_INTEGER_CANDIDATES) {
378         assertEquals(valueOf(x)
379             .mod(valueOf(m))
380             .intValue(), LongMath.mod(x, m));
381       }
382     }
383   }
384 
385   @GwtIncompatible("TODO")
testIntModNegativeModulusFails()386   public void testIntModNegativeModulusFails() {
387     for (long x : ALL_LONG_CANDIDATES) {
388       for (int m : NEGATIVE_INTEGER_CANDIDATES) {
389         try {
390           LongMath.mod(x, m);
391           fail("Expected ArithmeticException");
392         } catch (ArithmeticException expected) {}
393       }
394     }
395   }
396 
397   @GwtIncompatible("TODO")
testIntModZeroModulusFails()398   public void testIntModZeroModulusFails() {
399     for (long x : ALL_LONG_CANDIDATES) {
400       try {
401         LongMath.mod(x, 0);
402         fail("Expected AE");
403       } catch (ArithmeticException expected) {}
404     }
405   }
406 
407   @GwtIncompatible("TODO")
testMod()408   public void testMod() {
409     for (long x : ALL_LONG_CANDIDATES) {
410       for (long m : POSITIVE_LONG_CANDIDATES) {
411         assertEquals(valueOf(x)
412             .mod(valueOf(m))
413             .longValue(), LongMath.mod(x, m));
414       }
415     }
416   }
417 
418   @GwtIncompatible("TODO")
testModNegativeModulusFails()419   public void testModNegativeModulusFails() {
420     for (long x : ALL_LONG_CANDIDATES) {
421       for (long m : NEGATIVE_LONG_CANDIDATES) {
422         try {
423           LongMath.mod(x, m);
424           fail("Expected ArithmeticException");
425         } catch (ArithmeticException expected) {}
426       }
427     }
428   }
429 
testGCDExhaustive()430   public void testGCDExhaustive() {
431     for (long a : POSITIVE_LONG_CANDIDATES) {
432       for (long b : POSITIVE_LONG_CANDIDATES) {
433         assertEquals(valueOf(a).gcd(valueOf(b)), valueOf(LongMath.gcd(a, b)));
434       }
435     }
436   }
437 
438   @GwtIncompatible("TODO")
testGCDZero()439   public void testGCDZero() {
440     for (long a : POSITIVE_LONG_CANDIDATES) {
441       assertEquals(a, LongMath.gcd(a, 0));
442       assertEquals(a, LongMath.gcd(0, a));
443     }
444     assertEquals(0, LongMath.gcd(0, 0));
445   }
446 
447   @GwtIncompatible("TODO")
testGCDNegativePositiveThrows()448   public void testGCDNegativePositiveThrows() {
449     for (long a : NEGATIVE_LONG_CANDIDATES) {
450       try {
451         LongMath.gcd(a, 3);
452         fail("Expected IllegalArgumentException");
453       } catch (IllegalArgumentException expected) {}
454       try {
455         LongMath.gcd(3, a);
456         fail("Expected IllegalArgumentException");
457       } catch (IllegalArgumentException expected) {}
458     }
459   }
460 
461   @GwtIncompatible("TODO")
testGCDNegativeZeroThrows()462   public void testGCDNegativeZeroThrows() {
463     for (long a : NEGATIVE_LONG_CANDIDATES) {
464       try {
465         LongMath.gcd(a, 0);
466         fail("Expected IllegalArgumentException");
467       } catch (IllegalArgumentException expected) {}
468       try {
469         LongMath.gcd(0, a);
470         fail("Expected IllegalArgumentException");
471       } catch (IllegalArgumentException expected) {}
472     }
473   }
474 
475   @GwtIncompatible("TODO")
testCheckedAdd()476   public void testCheckedAdd() {
477     for (long a : ALL_INTEGER_CANDIDATES) {
478       for (long b : ALL_INTEGER_CANDIDATES) {
479         BigInteger expectedResult = valueOf(a).add(valueOf(b));
480         boolean expectedSuccess = fitsInLong(expectedResult);
481         try {
482           assertEquals(a + b, LongMath.checkedAdd(a, b));
483           assertTrue(expectedSuccess);
484         } catch (ArithmeticException e) {
485           assertFalse(expectedSuccess);
486         }
487       }
488     }
489   }
490 
491   @GwtIncompatible("TODO")
testCheckedSubtract()492   public void testCheckedSubtract() {
493     for (long a : ALL_INTEGER_CANDIDATES) {
494       for (long b : ALL_INTEGER_CANDIDATES) {
495         BigInteger expectedResult = valueOf(a).subtract(valueOf(b));
496         boolean expectedSuccess = fitsInLong(expectedResult);
497         try {
498           assertEquals(a - b, LongMath.checkedSubtract(a, b));
499           assertTrue(expectedSuccess);
500         } catch (ArithmeticException e) {
501           assertFalse(expectedSuccess);
502         }
503       }
504     }
505   }
506 
507   @GwtIncompatible("TODO")
testCheckedMultiply()508   public void testCheckedMultiply() {
509     for (long a : ALL_INTEGER_CANDIDATES) {
510       for (long b : ALL_INTEGER_CANDIDATES) {
511         BigInteger expectedResult = valueOf(a).multiply(valueOf(b));
512         boolean expectedSuccess = fitsInLong(expectedResult);
513         try {
514           assertEquals(a * b, LongMath.checkedMultiply(a, b));
515           assertTrue(expectedSuccess);
516         } catch (ArithmeticException e) {
517           assertFalse(expectedSuccess);
518         }
519       }
520     }
521   }
522 
523   @GwtIncompatible("TODO")
testCheckedPow()524   public void testCheckedPow() {
525     for (long b : ALL_INTEGER_CANDIDATES) {
526       for (int exp : EXPONENTS) {
527         BigInteger expectedResult = valueOf(b).pow(exp);
528         boolean expectedSuccess = fitsInLong(expectedResult);
529         try {
530           assertEquals(expectedResult.longValue(), LongMath.checkedPow(b, exp));
531           assertTrue(expectedSuccess);
532         } catch (ArithmeticException e) {
533           assertFalse(expectedSuccess);
534         }
535       }
536     }
537   }
538 
539   // Depends on the correctness of BigIntegerMath.factorial.
540   @GwtIncompatible("TODO")
testFactorial()541   public void testFactorial() {
542     for (int n = 0; n <= 50; n++) {
543       BigInteger expectedBig = BigIntegerMath.factorial(n);
544       long expectedLong = fitsInLong(expectedBig) ? expectedBig.longValue() : Long.MAX_VALUE;
545       assertEquals(expectedLong, LongMath.factorial(n));
546     }
547   }
548 
549   @GwtIncompatible("TODO")
testFactorialNegative()550   public void testFactorialNegative() {
551     for (int n : NEGATIVE_INTEGER_CANDIDATES) {
552       try {
553         LongMath.factorial(n);
554         fail("Expected IllegalArgumentException");
555       } catch (IllegalArgumentException expected) {}
556     }
557   }
558 
559   // Depends on the correctness of BigIntegerMath.binomial.
testBinomial()560   public void testBinomial() {
561     for (int n = 0; n <= 70; n++) {
562       for (int k = 0; k <= n; k++) {
563         BigInteger expectedBig = BigIntegerMath.binomial(n, k);
564         long expectedLong = fitsInLong(expectedBig) ? expectedBig.longValue() : Long.MAX_VALUE;
565         assertEquals(expectedLong, LongMath.binomial(n, k));
566       }
567     }
568   }
569 
570   @GwtIncompatible("Slow")
testBinomial_exhaustiveNotOverflowing()571   public void testBinomial_exhaustiveNotOverflowing() {
572     // Tests all of the inputs to LongMath.binomial that won't cause it to overflow, that weren't
573     // tested in the previous method, for k >= 3.
574     for (int k = 3; k < LongMath.biggestBinomials.length; k++) {
575       for (int n = 70; n <= LongMath.biggestBinomials[k]; n++) {
576         assertEquals(BigIntegerMath.binomial(n, k).longValue(), LongMath.binomial(n, k));
577       }
578     }
579   }
580 
testBinomialOutside()581   public void testBinomialOutside() {
582     for (int n = 0; n <= 50; n++) {
583       try {
584         LongMath.binomial(n, -1);
585         fail("Expected IllegalArgumentException");
586       } catch (IllegalArgumentException expected) {}
587       try {
588         LongMath.binomial(n, n + 1);
589         fail("Expected IllegalArgumentException");
590       } catch (IllegalArgumentException expected) {}
591     }
592   }
593 
testBinomialNegative()594   public void testBinomialNegative() {
595     for (int n : NEGATIVE_INTEGER_CANDIDATES) {
596       try {
597         LongMath.binomial(n, 0);
598         fail("Expected IllegalArgumentException");
599       } catch (IllegalArgumentException expected) {}
600     }
601   }
602 
603   @GwtIncompatible("far too slow")
testSqrtOfPerfectSquareAsDoubleIsPerfect()604   public void testSqrtOfPerfectSquareAsDoubleIsPerfect() {
605     // This takes just over a minute on my machine.
606     for (long n = 0; n <= LongMath.FLOOR_SQRT_MAX_LONG; n++) {
607       long actual = (long) Math.sqrt(n * n);
608       assertTrue(actual == n);
609     }
610   }
611 
testSqrtOfLongIsAtMostFloorSqrtMaxLong()612   public void testSqrtOfLongIsAtMostFloorSqrtMaxLong() {
613     long sqrtMaxLong = (long) Math.sqrt(Long.MAX_VALUE);
614     assertTrue(sqrtMaxLong <= LongMath.FLOOR_SQRT_MAX_LONG);
615   }
616 
617   @GwtIncompatible("java.math.BigInteger")
testMean()618   public void testMean() {
619     // Odd-sized ranges have an obvious mean
620     assertMean(2, 1, 3);
621 
622     assertMean(-2, -3, -1);
623     assertMean(0, -1, 1);
624     assertMean(1, -1, 3);
625     assertMean((1L << 62) - 1, -1, Long.MAX_VALUE);
626 
627     // Even-sized ranges should prefer the lower mean
628     assertMean(2, 1, 4);
629     assertMean(-3, -4, -1);
630     assertMean(0, -1, 2);
631     assertMean(0, Long.MIN_VALUE + 2, Long.MAX_VALUE);
632     assertMean(0, 0, 1);
633     assertMean(-1, -1, 0);
634     assertMean(-1, Long.MIN_VALUE, Long.MAX_VALUE);
635 
636     // x == y == mean
637     assertMean(1, 1, 1);
638     assertMean(0, 0, 0);
639     assertMean(-1, -1, -1);
640     assertMean(Long.MIN_VALUE, Long.MIN_VALUE, Long.MIN_VALUE);
641     assertMean(Long.MAX_VALUE, Long.MAX_VALUE, Long.MAX_VALUE);
642 
643     // Exhaustive checks
644     for (long x : ALL_LONG_CANDIDATES) {
645       for (long y : ALL_LONG_CANDIDATES) {
646         assertMean(x, y);
647       }
648     }
649   }
650 
651   /**
652    * Helper method that asserts the arithmetic mean of x and y is equal
653    * to the expectedMean.
654    */
assertMean(long expectedMean, long x, long y)655   private static void assertMean(long expectedMean, long x, long y) {
656     assertEquals("The expectedMean should be the same as computeMeanSafely",
657         expectedMean, computeMeanSafely(x, y));
658     assertMean(x, y);
659   }
660 
661   /**
662    * Helper method that asserts the arithmetic mean of x and y is equal
663    *to the result of computeMeanSafely.
664    */
assertMean(long x, long y)665   private static void assertMean(long x, long y) {
666     long expectedMean = computeMeanSafely(x, y);
667     assertEquals(expectedMean, LongMath.mean(x, y));
668     assertEquals("The mean of x and y should equal the mean of y and x",
669         expectedMean, LongMath.mean(y, x));
670   }
671 
672   /**
673    * Computes the mean in a way that is obvious and resilient to
674    * overflow by using BigInteger arithmetic.
675    */
computeMeanSafely(long x, long y)676   private static long computeMeanSafely(long x, long y) {
677     BigInteger bigX = BigInteger.valueOf(x);
678     BigInteger bigY = BigInteger.valueOf(y);
679     BigDecimal bigMean = new BigDecimal(bigX.add(bigY))
680         .divide(BigDecimal.valueOf(2), BigDecimal.ROUND_FLOOR);
681     // parseInt blows up on overflow as opposed to intValue() which does not.
682     return Long.parseLong(bigMean.toString());
683   }
684 
fitsInLong(BigInteger big)685   private static boolean fitsInLong(BigInteger big) {
686     return big.bitLength() <= 63;
687   }
688 
689   @GwtIncompatible("NullPointerTester")
testNullPointers()690   public void testNullPointers() {
691     NullPointerTester tester = new NullPointerTester();
692     tester.setDefault(int.class, 1);
693     tester.setDefault(long.class, 1L);
694     tester.testAllPublicStaticMethods(LongMath.class);
695   }
696 }
697