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