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