• 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_INTEGER_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.NONZERO_INTEGER_CANDIDATES;
25 import static com.google.common.math.MathTesting.POSITIVE_INTEGER_CANDIDATES;
26 import static com.google.common.math.TestPlatform.intsCanGoOutOfRange;
27 import static java.math.BigInteger.valueOf;
28 import static java.math.RoundingMode.FLOOR;
29 import static java.math.RoundingMode.UNNECESSARY;
30 
31 import com.google.common.annotations.GwtCompatible;
32 import com.google.common.annotations.GwtIncompatible;
33 import com.google.common.testing.NullPointerTester;
34 import java.math.BigDecimal;
35 import java.math.BigInteger;
36 import java.math.RoundingMode;
37 import java.util.Random;
38 import junit.framework.TestCase;
39 
40 /**
41  * Tests for {@link IntMath}.
42  *
43  * @author Louis Wasserman
44  */
45 @GwtCompatible(emulated = true)
46 public class IntMathTest extends TestCase {
testMaxSignedPowerOfTwo()47   public void testMaxSignedPowerOfTwo() {
48     assertTrue(IntMath.isPowerOfTwo(IntMath.MAX_SIGNED_POWER_OF_TWO));
49 
50     // Extra work required to make GWT happy.
51     long value = IntMath.MAX_SIGNED_POWER_OF_TWO * 2L;
52     assertFalse(IntMath.isPowerOfTwo((int) value));
53   }
54 
testCeilingPowerOfTwo()55   public void testCeilingPowerOfTwo() {
56     for (int x : POSITIVE_INTEGER_CANDIDATES) {
57       BigInteger expectedResult = BigIntegerMath.ceilingPowerOfTwo(BigInteger.valueOf(x));
58       if (fitsInInt(expectedResult)) {
59         assertEquals(expectedResult.intValue(), IntMath.ceilingPowerOfTwo(x));
60       } else {
61         try {
62           IntMath.ceilingPowerOfTwo(x);
63           fail("Expected ArithmeticException");
64         } catch (ArithmeticException expected) {
65         }
66       }
67     }
68   }
69 
testFloorPowerOfTwo()70   public void testFloorPowerOfTwo() {
71     for (int x : POSITIVE_INTEGER_CANDIDATES) {
72       BigInteger expectedResult = BigIntegerMath.floorPowerOfTwo(BigInteger.valueOf(x));
73       assertEquals(expectedResult.intValue(), IntMath.floorPowerOfTwo(x));
74     }
75   }
76 
testCeilingPowerOfTwoNegative()77   public void testCeilingPowerOfTwoNegative() {
78     for (int x : NEGATIVE_INTEGER_CANDIDATES) {
79       try {
80         IntMath.ceilingPowerOfTwo(x);
81         fail("Expected IllegalArgumentException");
82       } catch (IllegalArgumentException expected) {
83       }
84     }
85   }
86 
testFloorPowerOfTwoNegative()87   public void testFloorPowerOfTwoNegative() {
88     for (int x : NEGATIVE_INTEGER_CANDIDATES) {
89       try {
90         IntMath.floorPowerOfTwo(x);
91         fail("Expected IllegalArgumentException");
92       } catch (IllegalArgumentException expected) {
93       }
94     }
95   }
96 
testCeilingPowerOfTwoZero()97   public void testCeilingPowerOfTwoZero() {
98     try {
99       IntMath.ceilingPowerOfTwo(0);
100       fail("Expected IllegalArgumentException");
101     } catch (IllegalArgumentException expected) {
102     }
103   }
104 
testFloorPowerOfTwoZero()105   public void testFloorPowerOfTwoZero() {
106     try {
107       IntMath.floorPowerOfTwo(0);
108       fail("Expected IllegalArgumentException");
109     } catch (IllegalArgumentException expected) {
110     }
111   }
112 
113   @GwtIncompatible // BigIntegerMath // TODO(cpovirk): GWT-enable BigIntegerMath
testConstantMaxPowerOfSqrt2Unsigned()114   public void testConstantMaxPowerOfSqrt2Unsigned() {
115     assertEquals(
116         /*expected=*/ BigIntegerMath.sqrt(BigInteger.ZERO.setBit(2 * Integer.SIZE - 1), FLOOR)
117             .intValue(),
118         /*actual=*/ IntMath.MAX_POWER_OF_SQRT2_UNSIGNED);
119   }
120 
121   @GwtIncompatible // pow()
testConstantsPowersOf10()122   public void testConstantsPowersOf10() {
123     for (int i = 0; i < IntMath.powersOf10.length - 1; i++) {
124       assertEquals(IntMath.pow(10, i), IntMath.powersOf10[i]);
125     }
126   }
127 
128   @GwtIncompatible // BigIntegerMath // TODO(cpovirk): GWT-enable BigIntegerMath
testMaxLog10ForLeadingZeros()129   public void testMaxLog10ForLeadingZeros() {
130     for (int i = 0; i < Integer.SIZE; i++) {
131       assertEquals(
132           BigIntegerMath.log10(BigInteger.ONE.shiftLeft(Integer.SIZE - i), FLOOR),
133           IntMath.maxLog10ForLeadingZeros[i]);
134     }
135   }
136 
137   @GwtIncompatible // BigIntegerMath // TODO(cpovirk): GWT-enable BigIntegerMath
testConstantsHalfPowersOf10()138   public void testConstantsHalfPowersOf10() {
139     for (int i = 0; i < IntMath.halfPowersOf10.length; i++) {
140       assert IntMath.halfPowersOf10[i]
141           == Math.min(
142               Integer.MAX_VALUE,
143               BigIntegerMath.sqrt(BigInteger.TEN.pow(2 * i + 1), FLOOR).longValue());
144     }
145   }
146 
testConstantsBiggestBinomials()147   public void testConstantsBiggestBinomials() {
148     for (int k = 0; k < IntMath.biggestBinomials.length; k++) {
149       assertTrue(fitsInInt(BigIntegerMath.binomial(IntMath.biggestBinomials[k], k)));
150       assertTrue(
151           IntMath.biggestBinomials[k] == Integer.MAX_VALUE
152               || !fitsInInt(BigIntegerMath.binomial(IntMath.biggestBinomials[k] + 1, k)));
153       // In the first case, any int is valid; in the second, we want to test that the next-bigger
154       // int overflows.
155     }
156     assertFalse(
157         fitsInInt(
158             BigIntegerMath.binomial(
159                 2 * IntMath.biggestBinomials.length, IntMath.biggestBinomials.length)));
160   }
161 
162   @GwtIncompatible // sqrt
testPowersSqrtMaxInt()163   public void testPowersSqrtMaxInt() {
164     assertEquals(
165         /*expected=*/ IntMath.sqrt(Integer.MAX_VALUE, FLOOR),
166         /*actual=*/ IntMath.FLOOR_SQRT_MAX_INT);
167   }
168 
169   @AndroidIncompatible // presumably slow
testLessThanBranchFree()170   public void testLessThanBranchFree() {
171     for (int x : ALL_INTEGER_CANDIDATES) {
172       for (int y : ALL_INTEGER_CANDIDATES) {
173         if (LongMath.fitsInInt((long) x - y)) {
174           int expected = (x < y) ? 1 : 0;
175           int actual = IntMath.lessThanBranchFree(x, y);
176           assertEquals(expected, actual);
177         }
178       }
179     }
180   }
181 
182   @GwtIncompatible // java.math.BigInteger
testIsPowerOfTwo()183   public void testIsPowerOfTwo() {
184     for (int x : ALL_INTEGER_CANDIDATES) {
185       // Checks for a single bit set.
186       BigInteger bigX = BigInteger.valueOf(x);
187       boolean expected = (bigX.signum() > 0) && (bigX.bitCount() == 1);
188       assertEquals(expected, IntMath.isPowerOfTwo(x));
189     }
190   }
191 
testLog2ZeroAlwaysThrows()192   public void testLog2ZeroAlwaysThrows() {
193     for (RoundingMode mode : ALL_ROUNDING_MODES) {
194       try {
195         IntMath.log2(0, mode);
196         fail("Expected IllegalArgumentException");
197       } catch (IllegalArgumentException expected) {
198       }
199     }
200   }
201 
testLog2NegativeAlwaysThrows()202   public void testLog2NegativeAlwaysThrows() {
203     for (int x : NEGATIVE_INTEGER_CANDIDATES) {
204       for (RoundingMode mode : ALL_ROUNDING_MODES) {
205         try {
206           IntMath.log2(x, mode);
207           fail("Expected IllegalArgumentException");
208         } catch (IllegalArgumentException expected) {
209         }
210       }
211     }
212   }
213 
214   // Relies on the correctness of BigIntegrerMath.log2 for all modes except UNNECESSARY.
testLog2MatchesBigInteger()215   public void testLog2MatchesBigInteger() {
216     for (int x : POSITIVE_INTEGER_CANDIDATES) {
217       for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
218         assertEquals(BigIntegerMath.log2(valueOf(x), mode), IntMath.log2(x, mode));
219       }
220     }
221   }
222 
223   // Relies on the correctness of isPowerOfTwo(int).
testLog2Exact()224   public void testLog2Exact() {
225     for (int x : POSITIVE_INTEGER_CANDIDATES) {
226       // We only expect an exception if x was not a power of 2.
227       boolean isPowerOf2 = IntMath.isPowerOfTwo(x);
228       try {
229         assertEquals(x, 1 << IntMath.log2(x, UNNECESSARY));
230         assertTrue(isPowerOf2);
231       } catch (ArithmeticException e) {
232         assertFalse(isPowerOf2);
233       }
234     }
235   }
236 
237   @GwtIncompatible // log10
testLog10ZeroAlwaysThrows()238   public void testLog10ZeroAlwaysThrows() {
239     for (RoundingMode mode : ALL_ROUNDING_MODES) {
240       try {
241         IntMath.log10(0, mode);
242         fail("Expected IllegalArgumentException");
243       } catch (IllegalArgumentException expected) {
244       }
245     }
246   }
247 
248   @GwtIncompatible // log10
testLog10NegativeAlwaysThrows()249   public void testLog10NegativeAlwaysThrows() {
250     for (int x : NEGATIVE_INTEGER_CANDIDATES) {
251       for (RoundingMode mode : ALL_ROUNDING_MODES) {
252         try {
253           IntMath.log10(x, mode);
254           fail("Expected IllegalArgumentException");
255         } catch (IllegalArgumentException expected) {
256         }
257       }
258     }
259   }
260 
261   // Relies on the correctness of BigIntegerMath.log10 for all modes except UNNECESSARY.
262   @GwtIncompatible // BigIntegerMath // TODO(cpovirk): GWT-enable BigIntegerMath
testLog10MatchesBigInteger()263   public void testLog10MatchesBigInteger() {
264     for (int x : POSITIVE_INTEGER_CANDIDATES) {
265       for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
266         // The BigInteger implementation is tested separately, use it as the reference.
267         assertEquals(BigIntegerMath.log10(valueOf(x), mode), IntMath.log10(x, mode));
268       }
269     }
270   }
271 
272   // Relies on the correctness of log10(int, FLOOR) and of pow(int, int).
273   @GwtIncompatible // pow()
testLog10Exact()274   public void testLog10Exact() {
275     for (int x : POSITIVE_INTEGER_CANDIDATES) {
276       int floor = IntMath.log10(x, FLOOR);
277       boolean expectSuccess = IntMath.pow(10, floor) == x;
278       try {
279         assertEquals(floor, IntMath.log10(x, UNNECESSARY));
280         assertTrue(expectSuccess);
281       } catch (ArithmeticException e) {
282         assertFalse(expectSuccess);
283       }
284     }
285   }
286 
287   @GwtIncompatible // log10
testLog10TrivialOnPowerOfTen()288   public void testLog10TrivialOnPowerOfTen() {
289     int x = 1000000;
290     for (RoundingMode mode : ALL_ROUNDING_MODES) {
291       assertEquals(6, IntMath.log10(x, mode));
292     }
293   }
294 
295   // Simple test to cover sqrt(0) for all types and all modes.
296   @GwtIncompatible // sqrt
testSqrtZeroAlwaysZero()297   public void testSqrtZeroAlwaysZero() {
298     for (RoundingMode mode : ALL_ROUNDING_MODES) {
299       assertEquals(0, IntMath.sqrt(0, mode));
300     }
301   }
302 
303   @GwtIncompatible // sqrt
testSqrtNegativeAlwaysThrows()304   public void testSqrtNegativeAlwaysThrows() {
305     for (int x : NEGATIVE_INTEGER_CANDIDATES) {
306       for (RoundingMode mode : RoundingMode.values()) {
307         try {
308           IntMath.sqrt(x, mode);
309           fail("Expected IllegalArgumentException");
310         } catch (IllegalArgumentException expected) {
311         }
312       }
313     }
314   }
315 
316   /* Relies on the correctness of BigIntegerMath.sqrt for all modes except UNNECESSARY. */
317   @GwtIncompatible // BigIntegerMath // TODO(cpovirk): GWT-enable BigIntegerMath
testSqrtMatchesBigInteger()318   public void testSqrtMatchesBigInteger() {
319     for (int x : POSITIVE_INTEGER_CANDIDATES) {
320       for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
321         // The BigInteger implementation is tested separately, use it as the reference.
322         // Promote the int value (rather than using intValue() on the expected value) to avoid
323         // any risk of truncation which could lead to a false positive.
324         assertEquals(BigIntegerMath.sqrt(valueOf(x), mode), valueOf(IntMath.sqrt(x, mode)));
325       }
326     }
327   }
328 
329   /* Relies on the correctness of sqrt(int, FLOOR). */
330   @GwtIncompatible // sqrt
testSqrtExactMatchesFloorOrThrows()331   public void testSqrtExactMatchesFloorOrThrows() {
332     for (int x : POSITIVE_INTEGER_CANDIDATES) {
333       int floor = IntMath.sqrt(x, FLOOR);
334       // We only expect an exception if x was not a perfect square.
335       boolean isPerfectSquare = (floor * floor == x);
336       try {
337         assertEquals(floor, IntMath.sqrt(x, UNNECESSARY));
338         assertTrue(isPerfectSquare);
339       } catch (ArithmeticException e) {
340         assertFalse(isPerfectSquare);
341       }
342     }
343   }
344 
345   @GwtIncompatible // 2147483646^2 expected=4
testPow()346   public void testPow() {
347     for (int i : ALL_INTEGER_CANDIDATES) {
348       for (int pow : EXPONENTS) {
349         assertEquals(i + "^" + pow, BigInteger.valueOf(i).pow(pow).intValue(), IntMath.pow(i, pow));
350       }
351     }
352   }
353 
354   @AndroidIncompatible // slow
testDivNonZero()355   public void testDivNonZero() {
356     for (int p : NONZERO_INTEGER_CANDIDATES) {
357       for (int q : NONZERO_INTEGER_CANDIDATES) {
358         for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
359           // Skip some tests that fail due to GWT's non-compliant int implementation.
360           // TODO(cpovirk): does this test fail for only some rounding modes or for all?
361           if (p == -2147483648 && q == -1 && intsCanGoOutOfRange()) {
362             continue;
363           }
364           int expected =
365               new BigDecimal(valueOf(p)).divide(new BigDecimal(valueOf(q)), 0, mode).intValue();
366           assertEquals(p + "/" + q, force32(expected), IntMath.divide(p, q, mode));
367         }
368       }
369     }
370   }
371 
372   @AndroidIncompatible // presumably slow
testDivNonZeroExact()373   public void testDivNonZeroExact() {
374     for (int p : NONZERO_INTEGER_CANDIDATES) {
375       for (int q : NONZERO_INTEGER_CANDIDATES) {
376         // Skip some tests that fail due to GWT's non-compliant int implementation.
377         if (p == -2147483648 && q == -1 && intsCanGoOutOfRange()) {
378           continue;
379         }
380         boolean dividesEvenly = (p % q) == 0;
381         try {
382           assertEquals(p + "/" + q, p, IntMath.divide(p, q, UNNECESSARY) * q);
383           assertTrue(p + "/" + q + " not expected to divide evenly", dividesEvenly);
384         } catch (ArithmeticException e) {
385           assertFalse(p + "/" + q + " expected to divide evenly", dividesEvenly);
386         }
387       }
388     }
389   }
390 
testZeroDivIsAlwaysZero()391   public void testZeroDivIsAlwaysZero() {
392     for (int q : NONZERO_INTEGER_CANDIDATES) {
393       for (RoundingMode mode : ALL_ROUNDING_MODES) {
394         assertEquals(0, IntMath.divide(0, q, mode));
395       }
396     }
397   }
398 
testDivByZeroAlwaysFails()399   public void testDivByZeroAlwaysFails() {
400     for (int p : ALL_INTEGER_CANDIDATES) {
401       for (RoundingMode mode : ALL_ROUNDING_MODES) {
402         try {
403           IntMath.divide(p, 0, mode);
404           fail("Expected ArithmeticException");
405         } catch (ArithmeticException expected) {
406         }
407       }
408     }
409   }
410 
testMod()411   public void testMod() {
412     for (int x : ALL_INTEGER_CANDIDATES) {
413       for (int m : POSITIVE_INTEGER_CANDIDATES) {
414         assertEquals(valueOf(x).mod(valueOf(m)).intValue(), IntMath.mod(x, m));
415       }
416     }
417   }
418 
testModNegativeModulusFails()419   public void testModNegativeModulusFails() {
420     for (int x : POSITIVE_INTEGER_CANDIDATES) {
421       for (int m : NEGATIVE_INTEGER_CANDIDATES) {
422         try {
423           IntMath.mod(x, m);
424           fail("Expected ArithmeticException");
425         } catch (ArithmeticException expected) {
426         }
427       }
428     }
429   }
430 
testModZeroModulusFails()431   public void testModZeroModulusFails() {
432     for (int x : ALL_INTEGER_CANDIDATES) {
433       try {
434         IntMath.mod(x, 0);
435         fail("Expected ArithmeticException");
436       } catch (ArithmeticException expected) {
437       }
438     }
439   }
440 
testGCD()441   public void testGCD() {
442     for (int a : POSITIVE_INTEGER_CANDIDATES) {
443       for (int b : POSITIVE_INTEGER_CANDIDATES) {
444         assertEquals(valueOf(a).gcd(valueOf(b)), valueOf(IntMath.gcd(a, b)));
445       }
446     }
447   }
448 
testGCDZero()449   public void testGCDZero() {
450     for (int a : POSITIVE_INTEGER_CANDIDATES) {
451       assertEquals(a, IntMath.gcd(a, 0));
452       assertEquals(a, IntMath.gcd(0, a));
453     }
454     assertEquals(0, IntMath.gcd(0, 0));
455   }
456 
testGCDNegativePositiveThrows()457   public void testGCDNegativePositiveThrows() {
458     for (int a : NEGATIVE_INTEGER_CANDIDATES) {
459       try {
460         IntMath.gcd(a, 3);
461         fail("Expected IllegalArgumentException");
462       } catch (IllegalArgumentException expected) {
463       }
464       try {
465         IntMath.gcd(3, a);
466         fail("Expected IllegalArgumentException");
467       } catch (IllegalArgumentException expected) {
468       }
469     }
470   }
471 
testGCDNegativeZeroThrows()472   public void testGCDNegativeZeroThrows() {
473     for (int a : NEGATIVE_INTEGER_CANDIDATES) {
474       try {
475         IntMath.gcd(a, 0);
476         fail("Expected IllegalArgumentException");
477       } catch (IllegalArgumentException expected) {
478       }
479       try {
480         IntMath.gcd(0, a);
481         fail("Expected IllegalArgumentException");
482       } catch (IllegalArgumentException expected) {
483       }
484     }
485   }
486 
487   @AndroidIncompatible // slow
testCheckedAdd()488   public void testCheckedAdd() {
489     for (int a : ALL_INTEGER_CANDIDATES) {
490       for (int b : ALL_INTEGER_CANDIDATES) {
491         BigInteger expectedResult = valueOf(a).add(valueOf(b));
492         boolean expectedSuccess = fitsInInt(expectedResult);
493         try {
494           assertEquals(a + b, IntMath.checkedAdd(a, b));
495           assertTrue(expectedSuccess);
496         } catch (ArithmeticException e) {
497           assertFalse(expectedSuccess);
498         }
499       }
500     }
501   }
502 
503   @AndroidIncompatible // slow
testCheckedSubtract()504   public void testCheckedSubtract() {
505     for (int a : ALL_INTEGER_CANDIDATES) {
506       for (int b : ALL_INTEGER_CANDIDATES) {
507         BigInteger expectedResult = valueOf(a).subtract(valueOf(b));
508         boolean expectedSuccess = fitsInInt(expectedResult);
509         try {
510           assertEquals(a - b, IntMath.checkedSubtract(a, b));
511           assertTrue(expectedSuccess);
512         } catch (ArithmeticException e) {
513           assertFalse(expectedSuccess);
514         }
515       }
516     }
517   }
518 
519   @AndroidIncompatible // presumably slow
testCheckedMultiply()520   public void testCheckedMultiply() {
521     for (int a : ALL_INTEGER_CANDIDATES) {
522       for (int b : ALL_INTEGER_CANDIDATES) {
523         BigInteger expectedResult = valueOf(a).multiply(valueOf(b));
524         boolean expectedSuccess = fitsInInt(expectedResult);
525         try {
526           assertEquals(a * b, IntMath.checkedMultiply(a, b));
527           assertTrue(expectedSuccess);
528         } catch (ArithmeticException e) {
529           assertFalse(expectedSuccess);
530         }
531       }
532     }
533   }
534 
testCheckedPow()535   public void testCheckedPow() {
536     for (int b : ALL_INTEGER_CANDIDATES) {
537       for (int k : EXPONENTS) {
538         BigInteger expectedResult = valueOf(b).pow(k);
539         boolean expectedSuccess = fitsInInt(expectedResult);
540         try {
541           assertEquals(b + "^" + k, force32(expectedResult.intValue()), IntMath.checkedPow(b, k));
542           assertTrue(b + "^" + k + " should have succeeded", expectedSuccess);
543         } catch (ArithmeticException e) {
544           assertFalse(b + "^" + k + " should have failed", expectedSuccess);
545         }
546       }
547     }
548   }
549 
550   @AndroidIncompatible // slow
551   @GwtIncompatible // TODO
testSaturatedAdd()552   public void testSaturatedAdd() {
553     for (int a : ALL_INTEGER_CANDIDATES) {
554       for (int b : ALL_INTEGER_CANDIDATES) {
555         assertOperationEquals(
556             a, b, "s+", saturatedCast(valueOf(a).add(valueOf(b))), IntMath.saturatedAdd(a, b));
557       }
558     }
559   }
560 
561   @AndroidIncompatible // slow
562   @GwtIncompatible // TODO
testSaturatedSubtract()563   public void testSaturatedSubtract() {
564     for (int a : ALL_INTEGER_CANDIDATES) {
565       for (int b : ALL_INTEGER_CANDIDATES) {
566         assertOperationEquals(
567             a,
568             b,
569             "s-",
570             saturatedCast(valueOf(a).subtract(valueOf(b))),
571             IntMath.saturatedSubtract(a, b));
572       }
573     }
574   }
575 
576   @AndroidIncompatible // slow
577   @GwtIncompatible // TODO
testSaturatedMultiply()578   public void testSaturatedMultiply() {
579     for (int a : ALL_INTEGER_CANDIDATES) {
580       for (int b : ALL_INTEGER_CANDIDATES) {
581         assertOperationEquals(
582             a,
583             b,
584             "s*",
585             saturatedCast(valueOf(a).multiply(valueOf(b))),
586             IntMath.saturatedMultiply(a, b));
587       }
588     }
589   }
590 
591   @GwtIncompatible // TODO
testSaturatedPow()592   public void testSaturatedPow() {
593     for (int a : ALL_INTEGER_CANDIDATES) {
594       for (int b : EXPONENTS) {
595         assertOperationEquals(
596             a, b, "s^", saturatedCast(valueOf(a).pow(b)), IntMath.saturatedPow(a, b));
597       }
598     }
599   }
600 
601   private static final BigInteger MAX_INT = BigInteger.valueOf(Integer.MAX_VALUE);
602   private static final BigInteger MIN_INT = BigInteger.valueOf(Integer.MIN_VALUE);
603 
saturatedCast(BigInteger big)604   private static int saturatedCast(BigInteger big) {
605     if (big.compareTo(MAX_INT) > 0) {
606       return Integer.MAX_VALUE;
607     }
608     if (big.compareTo(MIN_INT) < 0) {
609       return Integer.MIN_VALUE;
610     }
611     return big.intValue();
612   }
613 
assertOperationEquals(int a, int b, String op, int expected, int actual)614   private void assertOperationEquals(int a, int b, String op, int expected, int actual) {
615     if (expected != actual) {
616       fail("Expected for " + a + " " + op + " " + b + " = " + expected + ", but got " + actual);
617     }
618   }
619 
620   // Depends on the correctness of BigIntegerMath.factorial.
testFactorial()621   public void testFactorial() {
622     for (int n = 0; n <= 50; n++) {
623       BigInteger expectedBig = BigIntegerMath.factorial(n);
624       int expectedInt = fitsInInt(expectedBig) ? expectedBig.intValue() : Integer.MAX_VALUE;
625       assertEquals(expectedInt, IntMath.factorial(n));
626     }
627   }
628 
testFactorialNegative()629   public void testFactorialNegative() {
630     for (int n : NEGATIVE_INTEGER_CANDIDATES) {
631       try {
632         IntMath.factorial(n);
633         fail("Expected IllegalArgumentException");
634       } catch (IllegalArgumentException expected) {
635       }
636     }
637   }
638 
639   // Depends on the correctness of BigIntegerMath.binomial.
testBinomial()640   public void testBinomial() {
641     for (int n = 0; n <= 50; n++) {
642       for (int k = 0; k <= n; k++) {
643         BigInteger expectedBig = BigIntegerMath.binomial(n, k);
644         int expectedInt = fitsInInt(expectedBig) ? expectedBig.intValue() : Integer.MAX_VALUE;
645         assertEquals(expectedInt, IntMath.binomial(n, k));
646       }
647     }
648   }
649 
testBinomialOutside()650   public void testBinomialOutside() {
651     for (int n = 0; n <= 50; n++) {
652       try {
653         IntMath.binomial(n, -1);
654         fail("Expected IllegalArgumentException");
655       } catch (IllegalArgumentException expected) {
656       }
657       try {
658         IntMath.binomial(n, n + 1);
659         fail("Expected IllegalArgumentException");
660       } catch (IllegalArgumentException expected) {
661       }
662     }
663   }
664 
testBinomialNegative()665   public void testBinomialNegative() {
666     for (int n : NEGATIVE_INTEGER_CANDIDATES) {
667       try {
668         IntMath.binomial(n, 0);
669         fail("Expected IllegalArgumentException");
670       } catch (IllegalArgumentException expected) {
671       }
672     }
673   }
674 
675   @AndroidIncompatible // slow
676   @GwtIncompatible // java.math.BigInteger
testMean()677   public void testMean() {
678     // Odd-sized ranges have an obvious mean
679     assertMean(2, 1, 3);
680 
681     assertMean(-2, -3, -1);
682     assertMean(0, -1, 1);
683     assertMean(1, -1, 3);
684     assertMean((1 << 30) - 1, -1, Integer.MAX_VALUE);
685 
686     // Even-sized ranges should prefer the lower mean
687     assertMean(2, 1, 4);
688     assertMean(-3, -4, -1);
689     assertMean(0, -1, 2);
690     assertMean(0, Integer.MIN_VALUE + 2, Integer.MAX_VALUE);
691     assertMean(0, 0, 1);
692     assertMean(-1, -1, 0);
693     assertMean(-1, Integer.MIN_VALUE, Integer.MAX_VALUE);
694 
695     // x == y == mean
696     assertMean(1, 1, 1);
697     assertMean(0, 0, 0);
698     assertMean(-1, -1, -1);
699     assertMean(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE);
700     assertMean(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
701 
702     // Exhaustive checks
703     for (int x : ALL_INTEGER_CANDIDATES) {
704       for (int y : ALL_INTEGER_CANDIDATES) {
705         assertMean(x, y);
706       }
707     }
708   }
709 
710   /** Helper method that asserts the arithmetic mean of x and y is equal to the expectedMean. */
assertMean(int expectedMean, int x, int y)711   private static void assertMean(int expectedMean, int x, int y) {
712     assertEquals(
713         "The expectedMean should be the same as computeMeanSafely",
714         expectedMean,
715         computeMeanSafely(x, y));
716     assertMean(x, y);
717   }
718 
719   /**
720    * Helper method that asserts the arithmetic mean of x and y is equal to the result of
721    * computeMeanSafely.
722    */
assertMean(int x, int y)723   private static void assertMean(int x, int y) {
724     int expectedMean = computeMeanSafely(x, y);
725     assertEquals(expectedMean, IntMath.mean(x, y));
726     assertEquals(
727         "The mean of x and y should equal the mean of y and x", expectedMean, IntMath.mean(y, x));
728   }
729 
730   /**
731    * Computes the mean in a way that is obvious and resilient to overflow by using BigInteger
732    * arithmetic.
733    */
computeMeanSafely(int x, int y)734   private static int computeMeanSafely(int x, int y) {
735     BigInteger bigX = BigInteger.valueOf(x);
736     BigInteger bigY = BigInteger.valueOf(y);
737     BigDecimal bigMean =
738         new BigDecimal(bigX.add(bigY)).divide(BigDecimal.valueOf(2), BigDecimal.ROUND_FLOOR);
739     // parseInt blows up on overflow as opposed to intValue() which does not.
740     return Integer.parseInt(bigMean.toString());
741   }
742 
fitsInInt(BigInteger big)743   private static boolean fitsInInt(BigInteger big) {
744     return big.bitLength() <= 31;
745   }
746 
747   @GwtIncompatible // NullPointerTester
testNullPointers()748   public void testNullPointers() {
749     NullPointerTester tester = new NullPointerTester();
750     tester.setDefault(int.class, 1);
751     tester.testAllPublicStaticMethods(IntMath.class);
752   }
753 
754   @GwtIncompatible // isPrime is GWT-incompatible
testIsPrime()755   public void testIsPrime() {
756     // Defer correctness tests to Long.isPrime
757 
758     // Check the first 100,000 integers
759     for (int i = 0; i < 100000; i++) {
760       assertEquals(LongMath.isPrime(i), IntMath.isPrime(i));
761     }
762 
763     // Then check 1000 deterministic pseudo-random int values.
764     Random rand = new Random(1);
765     for (int i = 0; i < 1000; i++) {
766       int n = rand.nextInt(Integer.MAX_VALUE);
767       assertEquals(LongMath.isPrime(n), IntMath.isPrime(n));
768     }
769   }
770 
force32(int value)771   private static int force32(int value) {
772     // GWT doesn't consistently overflow values to make them 32-bit, so we need to force it.
773     return value & 0xffffffff;
774   }
775 }
776