• 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 java.math.BigInteger.valueOf;
27 import static java.math.RoundingMode.FLOOR;
28 import static java.math.RoundingMode.UNNECESSARY;
29 
30 import com.google.common.annotations.GwtCompatible;
31 import com.google.common.annotations.GwtIncompatible;
32 import com.google.common.testing.NullPointerTester;
33 
34 import junit.framework.TestCase;
35 
36 import java.math.BigDecimal;
37 import java.math.BigInteger;
38 import java.math.RoundingMode;
39 
40 /**
41  * Tests for {@link IntMath}.
42  *
43  * @author Louis Wasserman
44  */
45 @GwtCompatible(emulated = true)
46 public class IntMathTest extends TestCase {
47   @GwtIncompatible("BigIntegerMath") // TODO(cpovirk): GWT-enable BigIntegerMath
testConstantMaxPowerOfSqrt2Unsigned()48   public void testConstantMaxPowerOfSqrt2Unsigned() {
49     assertEquals(
50         BigIntegerMath.sqrt(BigInteger.ZERO.setBit(2 * Integer.SIZE - 1), FLOOR).intValue(),
51         IntMath.MAX_POWER_OF_SQRT2_UNSIGNED);
52   }
53 
54   @GwtIncompatible("pow()")
testConstantsPowersOf10()55   public void testConstantsPowersOf10() {
56     for (int i = 0; i < IntMath.POWERS_OF_10.length; i++) {
57       assertEquals(IntMath.pow(10, i), IntMath.POWERS_OF_10[i]);
58     }
59   }
60 
61   @GwtIncompatible("BigIntegerMath") // TODO(cpovirk): GWT-enable BigIntegerMath
testConstantsHalfPowersOf10()62   public void testConstantsHalfPowersOf10() {
63     for (int i = 0; i < IntMath.HALF_POWERS_OF_10.length; i++) {
64       assert IntMath.HALF_POWERS_OF_10[i]
65           == Math.min(Integer.MAX_VALUE,
66               BigIntegerMath.sqrt(BigInteger.TEN.pow(2 * i + 1), FLOOR).longValue());
67     }
68   }
69 
70   @GwtIncompatible("BigIntegerMath") // TODO(cpovirk): GWT-enable BigIntegerMath
testConstantsBiggestBinomials()71   public void testConstantsBiggestBinomials(){
72     for (int k = 0; k < IntMath.BIGGEST_BINOMIALS.length; k++) {
73       assertTrue(fitsInInt(BigIntegerMath.binomial(IntMath.BIGGEST_BINOMIALS[k], k)));
74       assertTrue(IntMath.BIGGEST_BINOMIALS[k] == Integer.MAX_VALUE
75           || !fitsInInt(BigIntegerMath.binomial(IntMath.BIGGEST_BINOMIALS[k] + 1, k)));
76       // In the first case, any int is valid; in the second, we want to test that the next-bigger
77       // int overflows.
78     }
79     assertFalse(
80         fitsInInt(BigIntegerMath.binomial(
81             2 * IntMath.BIGGEST_BINOMIALS.length, IntMath.BIGGEST_BINOMIALS.length)));
82   }
83 
84   @GwtIncompatible("sqrt")
testPowersSqrtMaxInt()85   public void testPowersSqrtMaxInt() {
86     assertEquals(IntMath.sqrt(Integer.MAX_VALUE, FLOOR), IntMath.FLOOR_SQRT_MAX_INT);
87   }
88 
testIsPowerOfTwo()89   public void testIsPowerOfTwo() {
90     for (int x : ALL_INTEGER_CANDIDATES) {
91       // Checks for a single bit set.
92       boolean expected = x > 0 & (x & (x - 1)) == 0;
93       assertEquals(expected, IntMath.isPowerOfTwo(x));
94     }
95   }
96 
97   @GwtIncompatible("log2")
testLog2ZeroAlwaysThrows()98   public void testLog2ZeroAlwaysThrows() {
99     for (RoundingMode mode : ALL_ROUNDING_MODES) {
100       try {
101         IntMath.log2(0, mode);
102         fail("Expected IllegalArgumentException");
103       } catch (IllegalArgumentException expected) {}
104     }
105   }
106 
107   @GwtIncompatible("log2")
testLog2NegativeAlwaysThrows()108   public void testLog2NegativeAlwaysThrows() {
109     for (int x : NEGATIVE_INTEGER_CANDIDATES) {
110       for (RoundingMode mode : ALL_ROUNDING_MODES) {
111         try {
112           IntMath.log2(x, mode);
113           fail("Expected IllegalArgumentException");
114         } catch (IllegalArgumentException expected) {}
115       }
116     }
117   }
118 
119   // Relies on the correctness of BigIntegrerMath.log2 for all modes except UNNECESSARY.
120   @GwtIncompatible("BigIntegerMath") // TODO(cpovirk): GWT-enable BigIntegerMath
testLog2MatchesBigInteger()121   public void testLog2MatchesBigInteger() {
122     for (int x : POSITIVE_INTEGER_CANDIDATES) {
123       for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
124         assertEquals(BigIntegerMath.log2(valueOf(x), mode), IntMath.log2(x, mode));
125       }
126     }
127   }
128 
129   // Relies on the correctness of isPowerOfTwo(int).
130   @GwtIncompatible("log2")
testLog2Exact()131   public void testLog2Exact() {
132     for (int x : POSITIVE_INTEGER_CANDIDATES) {
133       // We only expect an exception if x was not a power of 2.
134       boolean isPowerOf2 = IntMath.isPowerOfTwo(x);
135       try {
136         assertEquals(x, 1 << IntMath.log2(x, UNNECESSARY));
137         assertTrue(isPowerOf2);
138       } catch (ArithmeticException e) {
139         assertFalse(isPowerOf2);
140       }
141     }
142   }
143 
144   @GwtIncompatible("log10")
testLog10ZeroAlwaysThrows()145   public void testLog10ZeroAlwaysThrows() {
146     for (RoundingMode mode : ALL_ROUNDING_MODES) {
147       try {
148         IntMath.log10(0, mode);
149         fail("Expected IllegalArgumentException");
150       } catch (IllegalArgumentException expected) {}
151     }
152   }
153 
154   @GwtIncompatible("log10")
testLog10NegativeAlwaysThrows()155   public void testLog10NegativeAlwaysThrows() {
156     for (int x : NEGATIVE_INTEGER_CANDIDATES) {
157       for (RoundingMode mode : ALL_ROUNDING_MODES) {
158         try {
159           IntMath.log10(x, mode);
160           fail("Expected IllegalArgumentException");
161         } catch (IllegalArgumentException expected) {}
162       }
163     }
164   }
165 
166   // Relies on the correctness of BigIntegerMath.log10 for all modes except UNNECESSARY.
167   @GwtIncompatible("BigIntegerMath") // TODO(cpovirk): GWT-enable BigIntegerMath
testLog10MatchesBigInteger()168   public void testLog10MatchesBigInteger() {
169     for (int x : POSITIVE_INTEGER_CANDIDATES) {
170       for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
171         // The BigInteger implementation is tested separately, use it as the reference.
172         assertEquals(BigIntegerMath.log10(valueOf(x), mode), IntMath.log10(x, mode));
173       }
174     }
175   }
176 
177   // Relies on the correctness of log10(int, FLOOR) and of pow(int, int).
178   @GwtIncompatible("pow()")
testLog10Exact()179   public void testLog10Exact() {
180     for (int x : POSITIVE_INTEGER_CANDIDATES) {
181       int floor = IntMath.log10(x, FLOOR);
182       boolean expectSuccess = IntMath.pow(10, floor) == x;
183       try {
184         assertEquals(floor, IntMath.log10(x, UNNECESSARY));
185         assertTrue(expectSuccess);
186       } catch (ArithmeticException e) {
187         assertFalse(expectSuccess);
188       }
189     }
190   }
191 
192   @GwtIncompatible("log10")
testLog10TrivialOnPowerOfTen()193   public void testLog10TrivialOnPowerOfTen() {
194     int x = 1000000;
195     for (RoundingMode mode : ALL_ROUNDING_MODES) {
196       assertEquals(6, IntMath.log10(x, mode));
197     }
198   }
199 
200   // Simple test to cover sqrt(0) for all types and all modes.
201   @GwtIncompatible("sqrt")
testSqrtZeroAlwaysZero()202   public void testSqrtZeroAlwaysZero() {
203     for (RoundingMode mode : ALL_ROUNDING_MODES) {
204       assertEquals(0, IntMath.sqrt(0, mode));
205     }
206   }
207 
208   @GwtIncompatible("sqrt")
testSqrtNegativeAlwaysThrows()209   public void testSqrtNegativeAlwaysThrows() {
210     for (int x : NEGATIVE_INTEGER_CANDIDATES) {
211       for (RoundingMode mode : RoundingMode.values()) {
212         try {
213           IntMath.sqrt(x, mode);
214           fail("Expected IllegalArgumentException");
215         } catch (IllegalArgumentException expected) {}
216       }
217     }
218   }
219 
220   /* Relies on the correctness of BigIntegerMath.sqrt for all modes except UNNECESSARY. */
221   @GwtIncompatible("BigIntegerMath") // TODO(cpovirk): GWT-enable BigIntegerMath
testSqrtMatchesBigInteger()222   public void testSqrtMatchesBigInteger() {
223     for (int x : POSITIVE_INTEGER_CANDIDATES) {
224       for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
225         // The BigInteger implementation is tested separately, use it as the reference.
226         // Promote the int value (rather than using intValue() on the expected value) to avoid
227         // any risk of truncation which could lead to a false positive.
228         assertEquals(BigIntegerMath.sqrt(valueOf(x), mode), valueOf(IntMath.sqrt(x, mode)));
229       }
230     }
231   }
232 
233   /* Relies on the correctness of sqrt(int, FLOOR). */
234   @GwtIncompatible("sqrt")
testSqrtExactMatchesFloorOrThrows()235   public void testSqrtExactMatchesFloorOrThrows() {
236     for (int x : POSITIVE_INTEGER_CANDIDATES) {
237       int floor = IntMath.sqrt(x, FLOOR);
238       // We only expect an exception if x was not a perfect square.
239       boolean isPerfectSquare = (floor * floor == x);
240       try {
241         assertEquals(floor, IntMath.sqrt(x, UNNECESSARY));
242         assertTrue(isPerfectSquare);
243       } catch (ArithmeticException e) {
244         assertFalse(isPerfectSquare);
245       }
246     }
247   }
248 
249   @GwtIncompatible("2147483646^2 expected=4")
testPow()250   public void testPow() {
251     for (int i : ALL_INTEGER_CANDIDATES) {
252       for (int pow : EXPONENTS) {
253         assertEquals(i + "^" + pow, BigInteger.valueOf(i).pow(pow).intValue(), IntMath.pow(i, pow));
254       }
255     }
256   }
257 
258   @GwtIncompatible("-2147483648/1 expected=2147483648")
testDivNonZero()259   public void testDivNonZero() {
260     for (int p : NONZERO_INTEGER_CANDIDATES) {
261       for (int q : NONZERO_INTEGER_CANDIDATES) {
262         for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
263           int expected =
264               new BigDecimal(valueOf(p)).divide(new BigDecimal(valueOf(q)), 0, mode).intValue();
265           assertEquals(p + "/" + q, expected, IntMath.divide(p, q, mode));
266         }
267       }
268     }
269   }
270 
271   @GwtIncompatible("-2147483648/-1 not expected to divide evenly")
testDivNonZeroExact()272   public void testDivNonZeroExact() {
273     for (int p : NONZERO_INTEGER_CANDIDATES) {
274       for (int q : NONZERO_INTEGER_CANDIDATES) {
275         boolean dividesEvenly = (p % q) == 0;
276 
277         try {
278           assertEquals(p + "/" + q, p, IntMath.divide(p, q, UNNECESSARY) * q);
279           assertTrue(p + "/" + q + " expected to divide evenly", dividesEvenly);
280         } catch (ArithmeticException e) {
281           assertFalse(p + "/" + q + " not expected to divide evenly", dividesEvenly);
282         }
283       }
284     }
285   }
286 
287   @GwtIncompatible("pow()")
testZeroDivIsAlwaysZero()288   public void testZeroDivIsAlwaysZero() {
289     for (int q : NONZERO_INTEGER_CANDIDATES) {
290       for (RoundingMode mode : ALL_ROUNDING_MODES) {
291         assertEquals(0, IntMath.divide(0, q, mode));
292       }
293     }
294   }
295 
296   @GwtIncompatible("pow()")
testDivByZeroAlwaysFails()297   public void testDivByZeroAlwaysFails() {
298     for (int p : ALL_INTEGER_CANDIDATES) {
299       for (RoundingMode mode : ALL_ROUNDING_MODES) {
300         try {
301           IntMath.divide(p, 0, mode);
302           fail("Expected ArithmeticException");
303         } catch (ArithmeticException expected) {}
304       }
305     }
306   }
307 
testMod()308   public void testMod() {
309     for (int x : ALL_INTEGER_CANDIDATES) {
310       for (int m : POSITIVE_INTEGER_CANDIDATES) {
311         assertEquals(valueOf(x).mod(valueOf(m)).intValue(), IntMath.mod(x, m));
312       }
313     }
314   }
315 
testModNegativeModulusFails()316   public void testModNegativeModulusFails() {
317     for (int x : POSITIVE_INTEGER_CANDIDATES) {
318       for (int m : NEGATIVE_INTEGER_CANDIDATES) {
319         try {
320           IntMath.mod(x, m);
321           fail("Expected ArithmeticException");
322         } catch (ArithmeticException expected) {}
323       }
324     }
325   }
326 
testModZeroModulusFails()327   public void testModZeroModulusFails() {
328     for (int x : ALL_INTEGER_CANDIDATES) {
329       try {
330         IntMath.mod(x, 0);
331         fail("Expected ArithmeticException");
332       } catch (ArithmeticException expected) {}
333     }
334   }
335 
testGCD()336   public void testGCD() {
337     for (int a : POSITIVE_INTEGER_CANDIDATES) {
338       for (int b : POSITIVE_INTEGER_CANDIDATES) {
339         assertEquals(valueOf(a).gcd(valueOf(b)), valueOf(IntMath.gcd(a, b)));
340       }
341     }
342   }
343 
testGCDZero()344   public void testGCDZero() {
345     for (int a : POSITIVE_INTEGER_CANDIDATES) {
346       assertEquals(a, IntMath.gcd(a, 0));
347       assertEquals(a, IntMath.gcd(0, a));
348     }
349     assertEquals(0, IntMath.gcd(0, 0));
350   }
351 
testGCDNegativePositiveThrows()352   public void testGCDNegativePositiveThrows() {
353     for (int a : NEGATIVE_INTEGER_CANDIDATES) {
354       try {
355         IntMath.gcd(a, 3);
356         fail("Expected IllegalArgumentException");
357       } catch (IllegalArgumentException expected) {}
358       try {
359         IntMath.gcd(3, a);
360         fail("Expected IllegalArgumentException");
361       } catch (IllegalArgumentException expected) {}
362     }
363   }
364 
testGCDNegativeZeroThrows()365   public void testGCDNegativeZeroThrows() {
366     for (int a : NEGATIVE_INTEGER_CANDIDATES) {
367       try {
368         IntMath.gcd(a, 0);
369         fail("Expected IllegalArgumentException");
370       } catch (IllegalArgumentException expected) {}
371       try {
372         IntMath.gcd(0, a);
373         fail("Expected IllegalArgumentException");
374       } catch (IllegalArgumentException expected) {}
375     }
376   }
377 
testCheckedAdd()378   public void testCheckedAdd() {
379     for (int a : ALL_INTEGER_CANDIDATES) {
380       for (int b : ALL_INTEGER_CANDIDATES) {
381         BigInteger expectedResult = valueOf(a).add(valueOf(b));
382         boolean expectedSuccess = fitsInInt(expectedResult);
383         try {
384           assertEquals(a + b, IntMath.checkedAdd(a, b));
385           assertTrue(expectedSuccess);
386         } catch (ArithmeticException e) {
387           assertFalse(expectedSuccess);
388         }
389       }
390     }
391   }
392 
testCheckedSubtract()393   public void testCheckedSubtract() {
394     for (int a : ALL_INTEGER_CANDIDATES) {
395       for (int b : ALL_INTEGER_CANDIDATES) {
396         BigInteger expectedResult = valueOf(a).subtract(valueOf(b));
397         boolean expectedSuccess = fitsInInt(expectedResult);
398         try {
399           assertEquals(a - b, IntMath.checkedSubtract(a, b));
400           assertTrue(expectedSuccess);
401         } catch (ArithmeticException e) {
402           assertFalse(expectedSuccess);
403         }
404       }
405     }
406   }
407 
testCheckedMultiply()408   public void testCheckedMultiply() {
409     for (int a : ALL_INTEGER_CANDIDATES) {
410       for (int b : ALL_INTEGER_CANDIDATES) {
411         BigInteger expectedResult = valueOf(a).multiply(valueOf(b));
412         boolean expectedSuccess = fitsInInt(expectedResult);
413         try {
414           assertEquals(a * b, IntMath.checkedMultiply(a, b));
415           assertTrue(expectedSuccess);
416         } catch (ArithmeticException e) {
417           assertFalse(expectedSuccess);
418         }
419       }
420     }
421   }
422 
423   @GwtIncompatible("-2147483648^1 expected=2147483648")
testCheckedPow()424   public void testCheckedPow() {
425     for (int b : ALL_INTEGER_CANDIDATES) {
426       for (int k : EXPONENTS) {
427         BigInteger expectedResult = valueOf(b).pow(k);
428         boolean expectedSuccess = fitsInInt(expectedResult);
429         try {
430           assertEquals(b + "^" + k, expectedResult.intValue(), IntMath.checkedPow(b, k));
431           assertTrue(b + "^" + k + " should have succeeded", expectedSuccess);
432         } catch (ArithmeticException e) {
433           assertFalse(b + "^" + k + " should have failed", expectedSuccess);
434         }
435       }
436     }
437   }
438 
439   // Depends on the correctness of BigIntegerMath.factorial.
440   @GwtIncompatible("BigIntegerMath") // TODO(cpovirk): GWT-enable BigIntegerMath
testFactorial()441   public void testFactorial() {
442     for (int n = 0; n <= 50; n++) {
443       BigInteger expectedBig = BigIntegerMath.factorial(n);
444       int expectedInt = fitsInInt(expectedBig) ? expectedBig.intValue() : Integer.MAX_VALUE;
445       assertEquals(expectedInt, IntMath.factorial(n));
446     }
447   }
448 
449   @GwtIncompatible("factorial")
testFactorialNegative()450   public void testFactorialNegative() {
451     for (int n : NEGATIVE_INTEGER_CANDIDATES) {
452       try {
453         IntMath.factorial(n);
454         fail("Expected IllegalArgumentException");
455       } catch (IllegalArgumentException expected) {}
456     }
457   }
458 
459   // Depends on the correctness of BigIntegerMath.binomial.
460   @GwtIncompatible("BigIntegerMath") // TODO(cpovirk): GWT-enable BigIntegerMath
testBinomial()461   public void testBinomial() {
462     for (int n = 0; n <= 50; n++) {
463       for (int k = 0; k <= n; k++) {
464         BigInteger expectedBig = BigIntegerMath.binomial(n, k);
465         int expectedInt = fitsInInt(expectedBig) ? expectedBig.intValue() : Integer.MAX_VALUE;
466         assertEquals(expectedInt, IntMath.binomial(n, k));
467       }
468     }
469   }
470 
471   @GwtIncompatible("binomial")
testBinomialOutside()472   public void testBinomialOutside() {
473     for (int n = 0; n <= 50; n++) {
474       try {
475         IntMath.binomial(n, -1);
476         fail("Expected IllegalArgumentException");
477       } catch (IllegalArgumentException expected) {}
478       try {
479         IntMath.binomial(n, n + 1);
480         fail("Expected IllegalArgumentException");
481       } catch (IllegalArgumentException expected) {}
482     }
483   }
484 
485   @GwtIncompatible("binomial")
testBinomialNegative()486   public void testBinomialNegative() {
487     for (int n : NEGATIVE_INTEGER_CANDIDATES) {
488       try {
489         IntMath.binomial(n, 0);
490         fail("Expected IllegalArgumentException");
491       } catch (IllegalArgumentException expected) {}
492     }
493   }
494 
fitsInInt(BigInteger big)495   private boolean fitsInInt(BigInteger big) {
496     return big.bitLength() <= 31;
497   }
498 
499   @GwtIncompatible("NullPointerTester")
testNullPointers()500   public void testNullPointers() throws Exception {
501     NullPointerTester tester = new NullPointerTester();
502     tester.setDefault(int.class, 1);
503     tester.setDefault(RoundingMode.class, FLOOR);
504     tester.testAllPublicStaticMethods(IntMath.class);
505   }
506 }
507