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