• 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_BIGINTEGER_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.NEGATIVE_BIGINTEGER_CANDIDATES;
23 import static com.google.common.math.MathTesting.NONZERO_BIGINTEGER_CANDIDATES;
24 import static com.google.common.math.MathTesting.POSITIVE_BIGINTEGER_CANDIDATES;
25 import static com.google.common.truth.Truth.assertThat;
26 import static com.google.common.truth.Truth.assertWithMessage;
27 import static java.math.BigInteger.ONE;
28 import static java.math.BigInteger.TEN;
29 import static java.math.BigInteger.ZERO;
30 import static java.math.RoundingMode.CEILING;
31 import static java.math.RoundingMode.DOWN;
32 import static java.math.RoundingMode.FLOOR;
33 import static java.math.RoundingMode.HALF_DOWN;
34 import static java.math.RoundingMode.HALF_EVEN;
35 import static java.math.RoundingMode.HALF_UP;
36 import static java.math.RoundingMode.UNNECESSARY;
37 import static java.math.RoundingMode.UP;
38 import static java.math.RoundingMode.values;
39 import static java.util.Arrays.asList;
40 
41 import com.google.common.annotations.GwtCompatible;
42 import com.google.common.annotations.GwtIncompatible;
43 import com.google.common.annotations.J2ktIncompatible;
44 import com.google.common.testing.NullPointerTester;
45 import com.google.errorprone.annotations.CanIgnoreReturnValue;
46 import java.math.BigDecimal;
47 import java.math.BigInteger;
48 import java.math.RoundingMode;
49 import java.util.EnumMap;
50 import java.util.EnumSet;
51 import java.util.Map;
52 import junit.framework.TestCase;
53 
54 /**
55  * Tests for BigIntegerMath.
56  *
57  * @author Louis Wasserman
58  */
59 @ElementTypesAreNonnullByDefault
60 @GwtCompatible(emulated = true)
61 public class BigIntegerMathTest extends TestCase {
testCeilingPowerOfTwo()62   public void testCeilingPowerOfTwo() {
63     for (BigInteger x : POSITIVE_BIGINTEGER_CANDIDATES) {
64       BigInteger result = BigIntegerMath.ceilingPowerOfTwo(x);
65       assertTrue(BigIntegerMath.isPowerOfTwo(result));
66       assertTrue(result.compareTo(x) >= 0);
67       assertTrue(result.compareTo(x.add(x)) < 0);
68     }
69   }
70 
71   public void testFloorPowerOfTwo() {
72     for (BigInteger x : POSITIVE_BIGINTEGER_CANDIDATES) {
73       BigInteger result = BigIntegerMath.floorPowerOfTwo(x);
74       assertTrue(BigIntegerMath.isPowerOfTwo(result));
75       assertTrue(result.compareTo(x) <= 0);
76       assertTrue(result.add(result).compareTo(x) > 0);
77     }
78   }
79 
80   public void testCeilingPowerOfTwoNegative() {
81     for (BigInteger x : NEGATIVE_BIGINTEGER_CANDIDATES) {
82       try {
83         BigIntegerMath.ceilingPowerOfTwo(x);
84         fail("Expected IllegalArgumentException");
85       } catch (IllegalArgumentException expected) {
86       }
87     }
88   }
89 
90   public void testFloorPowerOfTwoNegative() {
91     for (BigInteger x : NEGATIVE_BIGINTEGER_CANDIDATES) {
92       try {
93         BigIntegerMath.floorPowerOfTwo(x);
94         fail("Expected IllegalArgumentException");
95       } catch (IllegalArgumentException expected) {
96       }
97     }
98   }
99 
100   public void testCeilingPowerOfTwoZero() {
101     try {
102       BigIntegerMath.ceilingPowerOfTwo(BigInteger.ZERO);
103       fail("Expected IllegalArgumentException");
104     } catch (IllegalArgumentException expected) {
105     }
106   }
107 
108   public void testFloorPowerOfTwoZero() {
109     try {
110       BigIntegerMath.floorPowerOfTwo(BigInteger.ZERO);
111       fail("Expected IllegalArgumentException");
112     } catch (IllegalArgumentException expected) {
113     }
114   }
115 
116   @GwtIncompatible // TODO
117   public void testConstantSqrt2PrecomputedBits() {
118     assertEquals(
119         BigIntegerMath.sqrt(
120             BigInteger.ZERO.setBit(2 * BigIntegerMath.SQRT2_PRECOMPUTE_THRESHOLD + 1), FLOOR),
121         BigIntegerMath.SQRT2_PRECOMPUTED_BITS);
122   }
123 
124   public void testIsPowerOfTwo() {
125     for (BigInteger x : ALL_BIGINTEGER_CANDIDATES) {
126       // Checks for a single bit set.
127       boolean expected = x.signum() > 0 & x.and(x.subtract(ONE)).equals(ZERO);
128       assertEquals(expected, BigIntegerMath.isPowerOfTwo(x));
129     }
130   }
131 
testLog2ZeroAlwaysThrows()132   public void testLog2ZeroAlwaysThrows() {
133     for (RoundingMode mode : ALL_ROUNDING_MODES) {
134       try {
135         BigIntegerMath.log2(ZERO, mode);
136         fail("Expected IllegalArgumentException");
137       } catch (IllegalArgumentException expected) {
138       }
139     }
140   }
141 
testLog2NegativeAlwaysThrows()142   public void testLog2NegativeAlwaysThrows() {
143     for (RoundingMode mode : ALL_ROUNDING_MODES) {
144       try {
145         BigIntegerMath.log2(BigInteger.valueOf(-1), mode);
146         fail("Expected IllegalArgumentException");
147       } catch (IllegalArgumentException expected) {
148       }
149     }
150   }
151 
testLog2Floor()152   public void testLog2Floor() {
153     for (BigInteger x : POSITIVE_BIGINTEGER_CANDIDATES) {
154       for (RoundingMode mode : asList(FLOOR, DOWN)) {
155         int result = BigIntegerMath.log2(x, mode);
156         assertTrue(ZERO.setBit(result).compareTo(x) <= 0);
157         assertTrue(ZERO.setBit(result + 1).compareTo(x) > 0);
158       }
159     }
160   }
161 
testLog2Ceiling()162   public void testLog2Ceiling() {
163     for (BigInteger x : POSITIVE_BIGINTEGER_CANDIDATES) {
164       for (RoundingMode mode : asList(CEILING, UP)) {
165         int result = BigIntegerMath.log2(x, mode);
166         assertTrue(ZERO.setBit(result).compareTo(x) >= 0);
167         assertTrue(result == 0 || ZERO.setBit(result - 1).compareTo(x) < 0);
168       }
169     }
170   }
171 
172   // Relies on the correctness of isPowerOfTwo(BigInteger).
testLog2Exact()173   public void testLog2Exact() {
174     for (BigInteger x : POSITIVE_BIGINTEGER_CANDIDATES) {
175       // We only expect an exception if x was not a power of 2.
176       boolean isPowerOf2 = BigIntegerMath.isPowerOfTwo(x);
177       try {
178         assertEquals(x, ZERO.setBit(BigIntegerMath.log2(x, UNNECESSARY)));
179         assertTrue(isPowerOf2);
180       } catch (ArithmeticException e) {
181         assertFalse(isPowerOf2);
182       }
183     }
184   }
185 
testLog2HalfUp()186   public void testLog2HalfUp() {
187     for (BigInteger x : POSITIVE_BIGINTEGER_CANDIDATES) {
188       int result = BigIntegerMath.log2(x, HALF_UP);
189       BigInteger x2 = x.pow(2);
190       // x^2 < 2^(2 * result + 1), or else we would have rounded up
191       assertTrue(ZERO.setBit(2 * result + 1).compareTo(x2) > 0);
192       // x^2 >= 2^(2 * result - 1), or else we would have rounded down
193       assertTrue(result == 0 || ZERO.setBit(2 * result - 1).compareTo(x2) <= 0);
194     }
195   }
196 
testLog2HalfDown()197   public void testLog2HalfDown() {
198     for (BigInteger x : POSITIVE_BIGINTEGER_CANDIDATES) {
199       int result = BigIntegerMath.log2(x, HALF_DOWN);
200       BigInteger x2 = x.pow(2);
201       // x^2 <= 2^(2 * result + 1), or else we would have rounded up
202       assertTrue(ZERO.setBit(2 * result + 1).compareTo(x2) >= 0);
203       // x^2 > 2^(2 * result - 1), or else we would have rounded down
204       assertTrue(result == 0 || ZERO.setBit(2 * result - 1).compareTo(x2) < 0);
205     }
206   }
207 
208   // Relies on the correctness of log2(BigInteger, {HALF_UP,HALF_DOWN}).
testLog2HalfEven()209   public void testLog2HalfEven() {
210     for (BigInteger x : POSITIVE_BIGINTEGER_CANDIDATES) {
211       int halfEven = BigIntegerMath.log2(x, HALF_EVEN);
212       // Now figure out what rounding mode we should behave like (it depends if FLOOR was
213       // odd/even).
214       boolean floorWasEven = (BigIntegerMath.log2(x, FLOOR) & 1) == 0;
215       assertEquals(BigIntegerMath.log2(x, floorWasEven ? HALF_DOWN : HALF_UP), halfEven);
216     }
217   }
218 
219   @GwtIncompatible // TODO
testLog10ZeroAlwaysThrows()220   public void testLog10ZeroAlwaysThrows() {
221     for (RoundingMode mode : ALL_ROUNDING_MODES) {
222       try {
223         BigIntegerMath.log10(ZERO, mode);
224         fail("Expected IllegalArgumentException");
225       } catch (IllegalArgumentException expected) {
226       }
227     }
228   }
229 
230   @GwtIncompatible // TODO
testLog10NegativeAlwaysThrows()231   public void testLog10NegativeAlwaysThrows() {
232     for (RoundingMode mode : ALL_ROUNDING_MODES) {
233       try {
234         BigIntegerMath.log10(BigInteger.valueOf(-1), mode);
235         fail("Expected IllegalArgumentException");
236       } catch (IllegalArgumentException expected) {
237       }
238     }
239   }
240 
241   @GwtIncompatible // TODO
testLog10Floor()242   public void testLog10Floor() {
243     for (BigInteger x : POSITIVE_BIGINTEGER_CANDIDATES) {
244       for (RoundingMode mode : asList(FLOOR, DOWN)) {
245         int result = BigIntegerMath.log10(x, mode);
246         assertTrue(TEN.pow(result).compareTo(x) <= 0);
247         assertTrue(TEN.pow(result + 1).compareTo(x) > 0);
248       }
249     }
250   }
251 
252   @GwtIncompatible // TODO
testLog10Ceiling()253   public void testLog10Ceiling() {
254     for (BigInteger x : POSITIVE_BIGINTEGER_CANDIDATES) {
255       for (RoundingMode mode : asList(CEILING, UP)) {
256         int result = BigIntegerMath.log10(x, mode);
257         assertTrue(TEN.pow(result).compareTo(x) >= 0);
258         assertTrue(result == 0 || TEN.pow(result - 1).compareTo(x) < 0);
259       }
260     }
261   }
262 
263   // Relies on the correctness of log10(BigInteger, FLOOR).
264   @GwtIncompatible // TODO
testLog10Exact()265   public void testLog10Exact() {
266     for (BigInteger x : POSITIVE_BIGINTEGER_CANDIDATES) {
267       int logFloor = BigIntegerMath.log10(x, FLOOR);
268       boolean expectSuccess = TEN.pow(logFloor).equals(x);
269       try {
270         assertEquals(logFloor, BigIntegerMath.log10(x, UNNECESSARY));
271         assertTrue(expectSuccess);
272       } catch (ArithmeticException e) {
273         assertFalse(expectSuccess);
274       }
275     }
276   }
277 
278   @GwtIncompatible // TODO
testLog10HalfUp()279   public void testLog10HalfUp() {
280     for (BigInteger x : POSITIVE_BIGINTEGER_CANDIDATES) {
281       int result = BigIntegerMath.log10(x, HALF_UP);
282       BigInteger x2 = x.pow(2);
283       // x^2 < 10^(2 * result + 1), or else we would have rounded up
284       assertTrue(TEN.pow(2 * result + 1).compareTo(x2) > 0);
285       // x^2 >= 10^(2 * result - 1), or else we would have rounded down
286       assertTrue(result == 0 || TEN.pow(2 * result - 1).compareTo(x2) <= 0);
287     }
288   }
289 
290   @GwtIncompatible // TODO
testLog10HalfDown()291   public void testLog10HalfDown() {
292     for (BigInteger x : POSITIVE_BIGINTEGER_CANDIDATES) {
293       int result = BigIntegerMath.log10(x, HALF_DOWN);
294       BigInteger x2 = x.pow(2);
295       // x^2 <= 10^(2 * result + 1), or else we would have rounded up
296       assertTrue(TEN.pow(2 * result + 1).compareTo(x2) >= 0);
297       // x^2 > 10^(2 * result - 1), or else we would have rounded down
298       assertTrue(result == 0 || TEN.pow(2 * result - 1).compareTo(x2) < 0);
299     }
300   }
301 
302   // Relies on the correctness of log10(BigInteger, {HALF_UP,HALF_DOWN}).
303   @GwtIncompatible // TODO
testLog10HalfEven()304   public void testLog10HalfEven() {
305     for (BigInteger x : POSITIVE_BIGINTEGER_CANDIDATES) {
306       int halfEven = BigIntegerMath.log10(x, HALF_EVEN);
307       // Now figure out what rounding mode we should behave like (it depends if FLOOR was
308       // odd/even).
309       boolean floorWasEven = (BigIntegerMath.log10(x, FLOOR) & 1) == 0;
310       assertEquals(BigIntegerMath.log10(x, floorWasEven ? HALF_DOWN : HALF_UP), halfEven);
311     }
312   }
313 
314   @GwtIncompatible // TODO
testLog10TrivialOnPowerOf10()315   public void testLog10TrivialOnPowerOf10() {
316     BigInteger x = BigInteger.TEN.pow(100);
317     for (RoundingMode mode : ALL_ROUNDING_MODES) {
318       assertEquals(100, BigIntegerMath.log10(x, mode));
319     }
320   }
321 
322   @GwtIncompatible // TODO
testSqrtZeroAlwaysZero()323   public void testSqrtZeroAlwaysZero() {
324     for (RoundingMode mode : ALL_ROUNDING_MODES) {
325       assertEquals(ZERO, BigIntegerMath.sqrt(ZERO, mode));
326     }
327   }
328 
329   @GwtIncompatible // TODO
testSqrtNegativeAlwaysThrows()330   public void testSqrtNegativeAlwaysThrows() {
331     for (RoundingMode mode : ALL_ROUNDING_MODES) {
332       try {
333         BigIntegerMath.sqrt(BigInteger.valueOf(-1), mode);
334         fail("Expected IllegalArgumentException");
335       } catch (IllegalArgumentException expected) {
336       }
337     }
338   }
339 
340   @GwtIncompatible // TODO
testSqrtFloor()341   public void testSqrtFloor() {
342     for (BigInteger x : POSITIVE_BIGINTEGER_CANDIDATES) {
343       for (RoundingMode mode : asList(FLOOR, DOWN)) {
344         BigInteger result = BigIntegerMath.sqrt(x, mode);
345         assertTrue(result.compareTo(ZERO) > 0);
346         assertTrue(result.pow(2).compareTo(x) <= 0);
347         assertTrue(result.add(ONE).pow(2).compareTo(x) > 0);
348       }
349     }
350   }
351 
352   @GwtIncompatible // TODO
testSqrtCeiling()353   public void testSqrtCeiling() {
354     for (BigInteger x : POSITIVE_BIGINTEGER_CANDIDATES) {
355       for (RoundingMode mode : asList(CEILING, UP)) {
356         BigInteger result = BigIntegerMath.sqrt(x, mode);
357         assertTrue(result.compareTo(ZERO) > 0);
358         assertTrue(result.pow(2).compareTo(x) >= 0);
359         assertTrue(result.signum() == 0 || result.subtract(ONE).pow(2).compareTo(x) < 0);
360       }
361     }
362   }
363 
364   // Relies on the correctness of sqrt(BigInteger, FLOOR).
365   @GwtIncompatible // TODO
366   public void testSqrtExact() {
367     for (BigInteger x : POSITIVE_BIGINTEGER_CANDIDATES) {
368       BigInteger floor = BigIntegerMath.sqrt(x, FLOOR);
369       // We only expect an exception if x was not a perfect square.
370       boolean isPerfectSquare = floor.pow(2).equals(x);
371       try {
372         assertEquals(floor, BigIntegerMath.sqrt(x, UNNECESSARY));
373         assertTrue(isPerfectSquare);
374       } catch (ArithmeticException e) {
375         assertFalse(isPerfectSquare);
376       }
377     }
378   }
379 
380   @GwtIncompatible // TODO
381   public void testSqrtHalfUp() {
382     for (BigInteger x : POSITIVE_BIGINTEGER_CANDIDATES) {
383       BigInteger result = BigIntegerMath.sqrt(x, HALF_UP);
384       BigInteger plusHalfSquared = result.pow(2).add(result).shiftLeft(2).add(ONE);
385       BigInteger x4 = x.shiftLeft(2);
386       // sqrt(x) < result + 0.5, so 4 * x < (result + 0.5)^2 * 4
387       // (result + 0.5)^2 * 4 = (result^2 + result)*4 + 1
388       assertTrue(x4.compareTo(plusHalfSquared) < 0);
389       BigInteger minusHalfSquared = result.pow(2).subtract(result).shiftLeft(2).add(ONE);
390       // sqrt(x) > result - 0.5, so 4 * x > (result - 0.5)^2 * 4
391       // (result - 0.5)^2 * 4 = (result^2 - result)*4 + 1
392       assertTrue(result.equals(ZERO) || x4.compareTo(minusHalfSquared) >= 0);
393     }
394   }
395 
396   @GwtIncompatible // TODO
397   public void testSqrtHalfDown() {
398     for (BigInteger x : POSITIVE_BIGINTEGER_CANDIDATES) {
399       BigInteger result = BigIntegerMath.sqrt(x, HALF_DOWN);
400       BigInteger plusHalfSquared = result.pow(2).add(result).shiftLeft(2).add(ONE);
401       BigInteger x4 = x.shiftLeft(2);
402       // sqrt(x) <= result + 0.5, so 4 * x <= (result + 0.5)^2 * 4
403       // (result + 0.5)^2 * 4 = (result^2 + result)*4 + 1
404       assertTrue(x4.compareTo(plusHalfSquared) <= 0);
405       BigInteger minusHalfSquared = result.pow(2).subtract(result).shiftLeft(2).add(ONE);
406       // sqrt(x) > result - 0.5, so 4 * x > (result - 0.5)^2 * 4
407       // (result - 0.5)^2 * 4 = (result^2 - result)*4 + 1
408       assertTrue(result.equals(ZERO) || x4.compareTo(minusHalfSquared) > 0);
409     }
410   }
411 
412   // Relies on the correctness of sqrt(BigInteger, {HALF_UP,HALF_DOWN}).
413   @GwtIncompatible // TODO
414   public void testSqrtHalfEven() {
415     for (BigInteger x : POSITIVE_BIGINTEGER_CANDIDATES) {
416       BigInteger halfEven = BigIntegerMath.sqrt(x, HALF_EVEN);
417       // Now figure out what rounding mode we should behave like (it depends if FLOOR was
418       // odd/even).
419       boolean floorWasOdd = BigIntegerMath.sqrt(x, FLOOR).testBit(0);
420       assertEquals(BigIntegerMath.sqrt(x, floorWasOdd ? HALF_UP : HALF_DOWN), halfEven);
421     }
422   }
423 
424   @GwtIncompatible // TODO
425   @AndroidIncompatible // slow
426   public void testDivNonZero() {
427     for (BigInteger p : NONZERO_BIGINTEGER_CANDIDATES) {
428       for (BigInteger q : NONZERO_BIGINTEGER_CANDIDATES) {
429         for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
430           BigInteger expected =
431               new BigDecimal(p).divide(new BigDecimal(q), 0, mode).toBigIntegerExact();
432           assertEquals(expected, BigIntegerMath.divide(p, q, mode));
433         }
434       }
435     }
436   }
437 
438   private static final BigInteger BAD_FOR_ANDROID_P = new BigInteger("-9223372036854775808");
439   private static final BigInteger BAD_FOR_ANDROID_Q = new BigInteger("-1");
440 
441   @GwtIncompatible // TODO
442   @AndroidIncompatible // slow
443   public void testDivNonZeroExact() {
444     String runtimeName = System.getProperty("java.runtime.name");
445     boolean isAndroid = runtimeName != null && runtimeName.contains("Android");
446     for (BigInteger p : NONZERO_BIGINTEGER_CANDIDATES) {
447       for (BigInteger q : NONZERO_BIGINTEGER_CANDIDATES) {
448         if (isAndroid && p.equals(BAD_FOR_ANDROID_P) && q.equals(BAD_FOR_ANDROID_Q)) {
449           // https://issuetracker.google.com/issues/37074172
450           continue;
451         }
452 
453         boolean dividesEvenly = p.remainder(q).equals(ZERO);
454 
455         try {
456           BigInteger quotient = BigIntegerMath.divide(p, q, UNNECESSARY);
457           BigInteger undone = quotient.multiply(q);
458           if (!p.equals(undone)) {
459             failFormat("expected %s.multiply(%s) = %s; got %s", quotient, q, p, undone);
460           }
461           assertTrue(dividesEvenly);
462         } catch (ArithmeticException e) {
463           assertFalse(dividesEvenly);
464         }
465       }
466     }
467   }
468 
469   @GwtIncompatible // TODO
470   public void testZeroDivIsAlwaysZero() {
471     for (BigInteger q : NONZERO_BIGINTEGER_CANDIDATES) {
472       for (RoundingMode mode : ALL_ROUNDING_MODES) {
473         assertEquals(ZERO, BigIntegerMath.divide(ZERO, q, mode));
474       }
475     }
476   }
477 
478   @GwtIncompatible // TODO
479   public void testDivByZeroAlwaysFails() {
480     for (BigInteger p : ALL_BIGINTEGER_CANDIDATES) {
481       for (RoundingMode mode : ALL_ROUNDING_MODES) {
482         try {
483           BigIntegerMath.divide(p, ZERO, mode);
484           fail("Expected ArithmeticException");
485         } catch (ArithmeticException expected) {
486         }
487       }
488     }
489   }
490 
491   public void testFactorial() {
492     BigInteger expected = BigInteger.ONE;
493     for (int i = 1; i <= 200; i++) {
494       expected = expected.multiply(BigInteger.valueOf(i));
495       assertEquals(expected, BigIntegerMath.factorial(i));
496     }
497   }
498 
499   public void testFactorial0() {
500     assertEquals(BigInteger.ONE, BigIntegerMath.factorial(0));
501   }
502 
503   public void testFactorialNegative() {
504     try {
505       BigIntegerMath.factorial(-1);
506       fail("Expected IllegalArgumentException");
507     } catch (IllegalArgumentException expected) {
508     }
509   }
510 
511   public void testBinomialSmall() {
512     runBinomialTest(0, 30);
513   }
514 
515   @GwtIncompatible // too slow
516   public void testBinomialLarge() {
517     runBinomialTest(31, 100);
518   }
519 
520   // Depends on the correctness of BigIntegerMath.factorial
521   private static void runBinomialTest(int firstN, int lastN) {
522     for (int n = firstN; n <= lastN; n++) {
523       for (int k = 0; k <= n; k++) {
524         BigInteger expected =
525             BigIntegerMath.factorial(n)
526                 .divide(BigIntegerMath.factorial(k))
527                 .divide(BigIntegerMath.factorial(n - k));
528         assertEquals(expected, BigIntegerMath.binomial(n, k));
529       }
530     }
531   }
532 
533   public void testBinomialOutside() {
534     for (int n = 0; n <= 50; n++) {
535       try {
536         BigIntegerMath.binomial(n, -1);
537         fail("Expected IllegalArgumentException");
538       } catch (IllegalArgumentException expected) {
539       }
540       try {
541         BigIntegerMath.binomial(n, n + 1);
542         fail("Expected IllegalArgumentException");
543       } catch (IllegalArgumentException expected) {
544       }
545     }
546   }
547 
548   @J2ktIncompatible
549   @GwtIncompatible // EnumSet.complementOf
550   private static final class RoundToDoubleTester {
551     private final BigInteger input;
552     private final Map<RoundingMode, Double> expectedValues = new EnumMap<>(RoundingMode.class);
553     private boolean unnecessaryShouldThrow = false;
554 
555     RoundToDoubleTester(BigInteger input) {
556       this.input = input;
557     }
558 
559     @CanIgnoreReturnValue
560     RoundToDoubleTester setExpectation(double expectedValue, RoundingMode... modes) {
561       for (RoundingMode mode : modes) {
562         Double previous = expectedValues.put(mode, expectedValue);
563         if (previous != null) {
564           throw new AssertionError();
565         }
566       }
567       return this;
568     }
569 
570     @CanIgnoreReturnValue
571     public RoundToDoubleTester roundUnnecessaryShouldThrow() {
572       unnecessaryShouldThrow = true;
573       return this;
574     }
575 
576     public void test() {
577       assertThat(expectedValues.keySet())
578           .containsAtLeastElementsIn(EnumSet.complementOf(EnumSet.of(UNNECESSARY)));
579       for (Map.Entry<RoundingMode, Double> entry : expectedValues.entrySet()) {
580         RoundingMode mode = entry.getKey();
581         Double expectation = entry.getValue();
582         assertWithMessage("roundToDouble(" + input + ", " + mode + ")")
583             .that(BigIntegerMath.roundToDouble(input, mode))
584             .isEqualTo(expectation);
585       }
586 
587       if (!expectedValues.containsKey(UNNECESSARY)) {
588         assertWithMessage("Expected roundUnnecessaryShouldThrow call")
589             .that(unnecessaryShouldThrow)
590             .isTrue();
591         try {
592           BigIntegerMath.roundToDouble(input, UNNECESSARY);
593           fail("Expected ArithmeticException for roundToDouble(" + input + ", UNNECESSARY)");
594         } catch (ArithmeticException expected) {
595           // expected
596         }
597       }
598     }
599   }
600 
601   @J2ktIncompatible
602   @GwtIncompatible
603   public void testRoundToDouble_zero() {
604     new RoundToDoubleTester(BigInteger.ZERO).setExpectation(0.0, values()).test();
605   }
606 
607   @J2ktIncompatible
608   @GwtIncompatible
609   public void testRoundToDouble_smallPositive() {
610     new RoundToDoubleTester(BigInteger.valueOf(16)).setExpectation(16.0, values()).test();
611   }
612 
613   @J2ktIncompatible
614   @GwtIncompatible
615   public void testRoundToDouble_maxPreciselyRepresentable() {
616     new RoundToDoubleTester(BigInteger.valueOf(1L << 53))
617         .setExpectation(Math.pow(2, 53), values())
618         .test();
619   }
620 
621   @J2ktIncompatible
622   @GwtIncompatible
623   public void testRoundToDouble_maxPreciselyRepresentablePlusOne() {
624     double twoToThe53 = Math.pow(2, 53);
625     // the representable doubles are 2^53 and 2^53 + 2.
626     // 2^53+1 is halfway between, so HALF_UP will go up and HALF_DOWN will go down.
627     new RoundToDoubleTester(BigInteger.valueOf((1L << 53) + 1))
628         .setExpectation(twoToThe53, DOWN, FLOOR, HALF_DOWN, HALF_EVEN)
629         .setExpectation(Math.nextUp(twoToThe53), CEILING, UP, HALF_UP)
630         .roundUnnecessaryShouldThrow()
631         .test();
632   }
633 
634   @J2ktIncompatible
635   @GwtIncompatible
636   public void testRoundToDouble_twoToThe54PlusOne() {
637     double twoToThe54 = Math.pow(2, 54);
638     // the representable doubles are 2^54 and 2^54 + 4
639     // 2^54+1 is less than halfway between, so HALF_DOWN and HALF_UP will both go down.
640     new RoundToDoubleTester(BigInteger.valueOf((1L << 54) + 1))
641         .setExpectation(twoToThe54, DOWN, FLOOR, HALF_DOWN, HALF_UP, HALF_EVEN)
642         .setExpectation(Math.nextUp(twoToThe54), CEILING, UP)
643         .roundUnnecessaryShouldThrow()
644         .test();
645   }
646 
647   @J2ktIncompatible
648   @GwtIncompatible
649   public void testRoundToDouble_twoToThe54PlusThree() {
650     double twoToThe54 = Math.pow(2, 54);
651     // the representable doubles are 2^54 and 2^54 + 4
652     // 2^54+3 is more than halfway between, so HALF_DOWN and HALF_UP will both go up.
653     new RoundToDoubleTester(BigInteger.valueOf((1L << 54) + 3))
654         .setExpectation(twoToThe54, DOWN, FLOOR)
655         .setExpectation(Math.nextUp(twoToThe54), CEILING, UP, HALF_DOWN, HALF_UP, HALF_EVEN)
656         .roundUnnecessaryShouldThrow()
657         .test();
658   }
659 
660   @J2ktIncompatible
661   @GwtIncompatible
662   public void testRoundToDouble_twoToThe54PlusFour() {
663     new RoundToDoubleTester(BigInteger.valueOf((1L << 54) + 4))
664         .setExpectation(Math.pow(2, 54) + 4, values())
665         .test();
666   }
667 
668   @J2ktIncompatible
669   @GwtIncompatible
670   public void testRoundToDouble_maxDouble() {
671     BigInteger maxDoubleAsBI = DoubleMath.roundToBigInteger(Double.MAX_VALUE, UNNECESSARY);
672     new RoundToDoubleTester(maxDoubleAsBI).setExpectation(Double.MAX_VALUE, values()).test();
673   }
674 
675   @J2ktIncompatible
676   @GwtIncompatible
677   public void testRoundToDouble_maxDoublePlusOne() {
678     BigInteger maxDoubleAsBI =
679         DoubleMath.roundToBigInteger(Double.MAX_VALUE, UNNECESSARY).add(BigInteger.ONE);
680     new RoundToDoubleTester(maxDoubleAsBI)
681         .setExpectation(Double.MAX_VALUE, DOWN, FLOOR, HALF_EVEN, HALF_UP, HALF_DOWN)
682         .setExpectation(Double.POSITIVE_INFINITY, UP, CEILING)
683         .roundUnnecessaryShouldThrow()
684         .test();
685   }
686 
687   @J2ktIncompatible
688   @GwtIncompatible
689   public void testRoundToDouble_wayTooBig() {
690     BigInteger bi = BigInteger.ONE.shiftLeft(2 * Double.MAX_EXPONENT);
691     new RoundToDoubleTester(bi)
692         .setExpectation(Double.MAX_VALUE, DOWN, FLOOR, HALF_EVEN, HALF_UP, HALF_DOWN)
693         .setExpectation(Double.POSITIVE_INFINITY, UP, CEILING)
694         .roundUnnecessaryShouldThrow()
695         .test();
696   }
697 
698   @J2ktIncompatible
699   @GwtIncompatible
700   public void testRoundToDouble_smallNegative() {
701     new RoundToDoubleTester(BigInteger.valueOf(-16)).setExpectation(-16.0, values()).test();
702   }
703 
704   @J2ktIncompatible
705   @GwtIncompatible
706   public void testRoundToDouble_minPreciselyRepresentable() {
707     new RoundToDoubleTester(BigInteger.valueOf(-1L << 53))
708         .setExpectation(-Math.pow(2, 53), values())
709         .test();
710   }
711 
712   @J2ktIncompatible
713   @GwtIncompatible
714   public void testRoundToDouble_minPreciselyRepresentableMinusOne() {
715     // the representable doubles are -2^53 and -2^53 - 2.
716     // -2^53-1 is halfway between, so HALF_UP will go up and HALF_DOWN will go down.
717     new RoundToDoubleTester(BigInteger.valueOf((-1L << 53) - 1))
718         .setExpectation(-Math.pow(2, 53), DOWN, CEILING, HALF_DOWN, HALF_EVEN)
719         .setExpectation(DoubleUtils.nextDown(-Math.pow(2, 53)), FLOOR, UP, HALF_UP)
720         .roundUnnecessaryShouldThrow()
721         .test();
722   }
723 
724   @J2ktIncompatible
725   @GwtIncompatible
726   public void testRoundToDouble_negativeTwoToThe54MinusOne() {
727     new RoundToDoubleTester(BigInteger.valueOf((-1L << 54) - 1))
728         .setExpectation(-Math.pow(2, 54), DOWN, CEILING, HALF_DOWN, HALF_UP, HALF_EVEN)
729         .setExpectation(DoubleUtils.nextDown(-Math.pow(2, 54)), FLOOR, UP)
730         .roundUnnecessaryShouldThrow()
731         .test();
732   }
733 
734   @J2ktIncompatible
735   @GwtIncompatible
736   public void testRoundToDouble_negativeTwoToThe54MinusThree() {
737     new RoundToDoubleTester(BigInteger.valueOf((-1L << 54) - 3))
738         .setExpectation(-Math.pow(2, 54), DOWN, CEILING)
739         .setExpectation(
740             DoubleUtils.nextDown(-Math.pow(2, 54)), FLOOR, UP, HALF_DOWN, HALF_UP, HALF_EVEN)
741         .roundUnnecessaryShouldThrow()
742         .test();
743   }
744 
745   @J2ktIncompatible
746   @GwtIncompatible
747   public void testRoundToDouble_negativeTwoToThe54MinusFour() {
748     new RoundToDoubleTester(BigInteger.valueOf((-1L << 54) - 4))
749         .setExpectation(-Math.pow(2, 54) - 4, values())
750         .test();
751   }
752 
753   @J2ktIncompatible
754   @GwtIncompatible
755   public void testRoundToDouble_minDouble() {
756     BigInteger minDoubleAsBI = DoubleMath.roundToBigInteger(-Double.MAX_VALUE, UNNECESSARY);
757     new RoundToDoubleTester(minDoubleAsBI).setExpectation(-Double.MAX_VALUE, values()).test();
758   }
759 
760   @J2ktIncompatible
761   @GwtIncompatible
762   public void testRoundToDouble_minDoubleMinusOne() {
763     BigInteger minDoubleAsBI =
764         DoubleMath.roundToBigInteger(-Double.MAX_VALUE, UNNECESSARY).subtract(BigInteger.ONE);
765     new RoundToDoubleTester(minDoubleAsBI)
766         .setExpectation(-Double.MAX_VALUE, DOWN, CEILING, HALF_EVEN, HALF_UP, HALF_DOWN)
767         .setExpectation(Double.NEGATIVE_INFINITY, UP, FLOOR)
768         .roundUnnecessaryShouldThrow()
769         .test();
770   }
771 
772   @J2ktIncompatible
773   @GwtIncompatible
774   public void testRoundToDouble_negativeWayTooBig() {
775     BigInteger bi = BigInteger.ONE.shiftLeft(2 * Double.MAX_EXPONENT).negate();
776     new RoundToDoubleTester(bi)
777         .setExpectation(-Double.MAX_VALUE, DOWN, CEILING, HALF_EVEN, HALF_UP, HALF_DOWN)
778         .setExpectation(Double.NEGATIVE_INFINITY, UP, FLOOR)
779         .roundUnnecessaryShouldThrow()
780         .test();
781   }
782 
783   @J2ktIncompatible
784   @GwtIncompatible // NullPointerTester
785   public void testNullPointers() {
786     NullPointerTester tester = new NullPointerTester();
787     tester.setDefault(BigInteger.class, ONE);
788     tester.setDefault(int.class, 1);
789     tester.setDefault(long.class, 1L);
790     tester.testAllPublicStaticMethods(BigIntegerMath.class);
791   }
792 
793   @GwtIncompatible // String.format
794   private static void failFormat(String template, Object... args) {
795     fail(String.format(template, args));
796   }
797 }
798