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.collect.Iterables.get;
20 import static com.google.common.collect.Iterables.size;
21 import static com.google.common.math.MathTesting.ALL_DOUBLE_CANDIDATES;
22 import static com.google.common.math.MathTesting.ALL_ROUNDING_MODES;
23 import static com.google.common.math.MathTesting.ALL_SAFE_ROUNDING_MODES;
24 import static com.google.common.math.MathTesting.DOUBLE_CANDIDATES_EXCEPT_NAN;
25 import static com.google.common.math.MathTesting.FINITE_DOUBLE_CANDIDATES;
26 import static com.google.common.math.MathTesting.FRACTIONAL_DOUBLE_CANDIDATES;
27 import static com.google.common.math.MathTesting.INFINITIES;
28 import static com.google.common.math.MathTesting.INTEGRAL_DOUBLE_CANDIDATES;
29 import static com.google.common.math.MathTesting.NEGATIVE_INTEGER_CANDIDATES;
30 import static com.google.common.math.MathTesting.POSITIVE_FINITE_DOUBLE_CANDIDATES;
31 import static java.math.RoundingMode.CEILING;
32 import static java.math.RoundingMode.DOWN;
33 import static java.math.RoundingMode.FLOOR;
34 import static java.math.RoundingMode.HALF_DOWN;
35 import static java.math.RoundingMode.HALF_EVEN;
36 import static java.math.RoundingMode.HALF_UP;
37 import static java.math.RoundingMode.UNNECESSARY;
38 import static java.math.RoundingMode.UP;
39 import static java.util.Arrays.asList;
40 
41 import com.google.common.annotations.GwtCompatible;
42 import com.google.common.annotations.GwtIncompatible;
43 import com.google.common.collect.ImmutableList;
44 import com.google.common.collect.Iterables;
45 import com.google.common.primitives.Doubles;
46 import com.google.common.testing.NullPointerTester;
47 import java.math.BigDecimal;
48 import java.math.BigInteger;
49 import java.math.RoundingMode;
50 import java.util.Arrays;
51 import java.util.List;
52 import junit.framework.TestCase;
53 
54 /**
55  * Tests for {@code DoubleMath}.
56  *
57  * @author Louis Wasserman
58  */
59 @GwtCompatible(emulated = true)
60 public class DoubleMathTest extends TestCase {
61 
62   private static final BigDecimal MAX_INT_AS_BIG_DECIMAL = BigDecimal.valueOf(Integer.MAX_VALUE);
63   private static final BigDecimal MIN_INT_AS_BIG_DECIMAL = BigDecimal.valueOf(Integer.MIN_VALUE);
64 
65   private static final BigDecimal MAX_LONG_AS_BIG_DECIMAL = BigDecimal.valueOf(Long.MAX_VALUE);
66   private static final BigDecimal MIN_LONG_AS_BIG_DECIMAL = BigDecimal.valueOf(Long.MIN_VALUE);
67 
testConstantsMaxFactorial()68   public void testConstantsMaxFactorial() {
69     BigInteger maxDoubleValue = BigDecimal.valueOf(Double.MAX_VALUE).toBigInteger();
70     assertTrue(BigIntegerMath.factorial(DoubleMath.MAX_FACTORIAL).compareTo(maxDoubleValue) <= 0);
71     assertTrue(
72         BigIntegerMath.factorial(DoubleMath.MAX_FACTORIAL + 1).compareTo(maxDoubleValue) > 0);
73   }
74 
testConstantsEverySixteenthFactorial()75   public void testConstantsEverySixteenthFactorial() {
76     for (int i = 0, n = 0; n <= DoubleMath.MAX_FACTORIAL; i++, n += 16) {
77       assertEquals(
78           BigIntegerMath.factorial(n).doubleValue(), DoubleMath.everySixteenthFactorial[i]);
79     }
80   }
81 
82   @GwtIncompatible // DoubleMath.roundToInt(double, RoundingMode)
testRoundIntegralDoubleToInt()83   public void testRoundIntegralDoubleToInt() {
84     for (double d : INTEGRAL_DOUBLE_CANDIDATES) {
85       for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
86         BigDecimal expected = new BigDecimal(d).setScale(0, mode);
87         boolean isInBounds =
88             expected.compareTo(MAX_INT_AS_BIG_DECIMAL) <= 0
89                 & expected.compareTo(MIN_INT_AS_BIG_DECIMAL) >= 0;
90 
91         try {
92           assertEquals(expected.intValue(), DoubleMath.roundToInt(d, mode));
93           assertTrue(isInBounds);
94         } catch (ArithmeticException e) {
95           assertFalse(isInBounds);
96         }
97       }
98     }
99   }
100 
101   @GwtIncompatible // DoubleMath.roundToInt(double, RoundingMode)
testRoundFractionalDoubleToInt()102   public void testRoundFractionalDoubleToInt() {
103     for (double d : FRACTIONAL_DOUBLE_CANDIDATES) {
104       for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
105         BigDecimal expected = new BigDecimal(d).setScale(0, mode);
106         boolean isInBounds =
107             expected.compareTo(MAX_INT_AS_BIG_DECIMAL) <= 0
108                 & expected.compareTo(MIN_INT_AS_BIG_DECIMAL) >= 0;
109 
110         try {
111           assertEquals(
112               "Rounding " + d + " with mode " + mode,
113               expected.intValue(),
114               DoubleMath.roundToInt(d, mode));
115           assertTrue(isInBounds);
116         } catch (ArithmeticException e) {
117           assertFalse(isInBounds);
118         }
119       }
120     }
121   }
122 
123   @GwtIncompatible // DoubleMath.roundToInt(double, RoundingMode)
testRoundExactIntegralDoubleToInt()124   public void testRoundExactIntegralDoubleToInt() {
125     for (double d : INTEGRAL_DOUBLE_CANDIDATES) {
126       BigDecimal expected = new BigDecimal(d).setScale(0, UNNECESSARY);
127       boolean isInBounds =
128           expected.compareTo(MAX_INT_AS_BIG_DECIMAL) <= 0
129               & expected.compareTo(MIN_INT_AS_BIG_DECIMAL) >= 0;
130 
131       try {
132         assertEquals(expected.intValue(), DoubleMath.roundToInt(d, UNNECESSARY));
133         assertTrue(isInBounds);
134       } catch (ArithmeticException e) {
135         assertFalse(isInBounds);
136       }
137     }
138   }
139 
140   @GwtIncompatible // DoubleMath.roundToInt(double, RoundingMode)
testRoundExactFractionalDoubleToIntFails()141   public void testRoundExactFractionalDoubleToIntFails() {
142     for (double d : FRACTIONAL_DOUBLE_CANDIDATES) {
143       try {
144         DoubleMath.roundToInt(d, UNNECESSARY);
145         fail("Expected ArithmeticException");
146       } catch (ArithmeticException expected) {
147       }
148     }
149   }
150 
151   @GwtIncompatible // DoubleMath.roundToInt(double, RoundingMode)
testRoundNaNToIntAlwaysFails()152   public void testRoundNaNToIntAlwaysFails() {
153     for (RoundingMode mode : ALL_ROUNDING_MODES) {
154       try {
155         DoubleMath.roundToInt(Double.NaN, mode);
156         fail("Expected ArithmeticException");
157       } catch (ArithmeticException expected) {
158       }
159     }
160   }
161 
162   @GwtIncompatible // DoubleMath.roundToInt(double, RoundingMode)
testRoundInfiniteToIntAlwaysFails()163   public void testRoundInfiniteToIntAlwaysFails() {
164     for (RoundingMode mode : ALL_ROUNDING_MODES) {
165       try {
166         DoubleMath.roundToInt(Double.POSITIVE_INFINITY, mode);
167         fail("Expected ArithmeticException");
168       } catch (ArithmeticException expected) {
169       }
170       try {
171         DoubleMath.roundToInt(Double.NEGATIVE_INFINITY, mode);
172         fail("Expected ArithmeticException");
173       } catch (ArithmeticException expected) {
174       }
175     }
176   }
177 
178   @GwtIncompatible // DoubleMath.roundToLong(double, RoundingMode)
testRoundIntegralDoubleToLong()179   public void testRoundIntegralDoubleToLong() {
180     for (double d : INTEGRAL_DOUBLE_CANDIDATES) {
181       for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
182         BigDecimal expected = new BigDecimal(d).setScale(0, mode);
183         boolean isInBounds =
184             expected.compareTo(MAX_LONG_AS_BIG_DECIMAL) <= 0
185                 & expected.compareTo(MIN_LONG_AS_BIG_DECIMAL) >= 0;
186 
187         try {
188           assertEquals(expected.longValue(), DoubleMath.roundToLong(d, mode));
189           assertTrue(isInBounds);
190         } catch (ArithmeticException e) {
191           assertFalse(isInBounds);
192         }
193       }
194     }
195   }
196 
197   @GwtIncompatible // DoubleMath.roundToLong(double, RoundingMode)
testRoundFractionalDoubleToLong()198   public void testRoundFractionalDoubleToLong() {
199     for (double d : FRACTIONAL_DOUBLE_CANDIDATES) {
200       for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
201         BigDecimal expected = new BigDecimal(d).setScale(0, mode);
202         boolean isInBounds =
203             expected.compareTo(MAX_LONG_AS_BIG_DECIMAL) <= 0
204                 & expected.compareTo(MIN_LONG_AS_BIG_DECIMAL) >= 0;
205 
206         try {
207           assertEquals(expected.longValue(), DoubleMath.roundToLong(d, mode));
208           assertTrue(isInBounds);
209         } catch (ArithmeticException e) {
210           assertFalse(isInBounds);
211         }
212       }
213     }
214   }
215 
216   @GwtIncompatible // DoubleMath.roundToLong(double, RoundingMode)
testRoundExactIntegralDoubleToLong()217   public void testRoundExactIntegralDoubleToLong() {
218     for (double d : INTEGRAL_DOUBLE_CANDIDATES) {
219       // every mode except UNNECESSARY
220       BigDecimal expected = new BigDecimal(d).setScale(0, UNNECESSARY);
221       boolean isInBounds =
222           expected.compareTo(MAX_LONG_AS_BIG_DECIMAL) <= 0
223               & expected.compareTo(MIN_LONG_AS_BIG_DECIMAL) >= 0;
224 
225       try {
226         assertEquals(expected.longValue(), DoubleMath.roundToLong(d, UNNECESSARY));
227         assertTrue(isInBounds);
228       } catch (ArithmeticException e) {
229         assertFalse(isInBounds);
230       }
231     }
232   }
233 
234   @GwtIncompatible // DoubleMath.roundToLong(double, RoundingMode)
testRoundExactFractionalDoubleToLongFails()235   public void testRoundExactFractionalDoubleToLongFails() {
236     for (double d : FRACTIONAL_DOUBLE_CANDIDATES) {
237       try {
238         DoubleMath.roundToLong(d, UNNECESSARY);
239         fail("Expected ArithmeticException");
240       } catch (ArithmeticException expected) {
241       }
242     }
243   }
244 
245   @GwtIncompatible // DoubleMath.roundToLong(double, RoundingMode)
testRoundNaNToLongAlwaysFails()246   public void testRoundNaNToLongAlwaysFails() {
247     for (RoundingMode mode : ALL_ROUNDING_MODES) {
248       try {
249         DoubleMath.roundToLong(Double.NaN, mode);
250         fail("Expected ArithmeticException");
251       } catch (ArithmeticException expected) {
252       }
253     }
254   }
255 
256   @GwtIncompatible // DoubleMath.roundToLong(double, RoundingMode)
testRoundInfiniteToLongAlwaysFails()257   public void testRoundInfiniteToLongAlwaysFails() {
258     for (RoundingMode mode : ALL_ROUNDING_MODES) {
259       try {
260         DoubleMath.roundToLong(Double.POSITIVE_INFINITY, mode);
261         fail("Expected ArithmeticException");
262       } catch (ArithmeticException expected) {
263       }
264       try {
265         DoubleMath.roundToLong(Double.NEGATIVE_INFINITY, mode);
266         fail("Expected ArithmeticException");
267       } catch (ArithmeticException expected) {
268       }
269     }
270   }
271 
272   @GwtIncompatible // DoubleMath.roundToBigInteger(double, RoundingMode)
testRoundIntegralDoubleToBigInteger()273   public void testRoundIntegralDoubleToBigInteger() {
274     for (double d : INTEGRAL_DOUBLE_CANDIDATES) {
275       for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
276         BigDecimal expected = new BigDecimal(d).setScale(0, mode);
277         assertEquals(expected.toBigInteger(), DoubleMath.roundToBigInteger(d, mode));
278       }
279     }
280   }
281 
282   @GwtIncompatible // DoubleMath.roundToBigInteger(double, RoundingMode)
testRoundFractionalDoubleToBigInteger()283   public void testRoundFractionalDoubleToBigInteger() {
284     for (double d : FRACTIONAL_DOUBLE_CANDIDATES) {
285       for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
286         BigDecimal expected = new BigDecimal(d).setScale(0, mode);
287         assertEquals(expected.toBigInteger(), DoubleMath.roundToBigInteger(d, mode));
288       }
289     }
290   }
291 
292   @GwtIncompatible // DoubleMath.roundToBigInteger(double, RoundingMode)
testRoundExactIntegralDoubleToBigInteger()293   public void testRoundExactIntegralDoubleToBigInteger() {
294     for (double d : INTEGRAL_DOUBLE_CANDIDATES) {
295       BigDecimal expected = new BigDecimal(d).setScale(0, UNNECESSARY);
296       assertEquals(expected.toBigInteger(), DoubleMath.roundToBigInteger(d, UNNECESSARY));
297     }
298   }
299 
300   @GwtIncompatible // DoubleMath.roundToBigInteger(double, RoundingMode)
testRoundExactFractionalDoubleToBigIntegerFails()301   public void testRoundExactFractionalDoubleToBigIntegerFails() {
302     for (double d : FRACTIONAL_DOUBLE_CANDIDATES) {
303       try {
304         DoubleMath.roundToBigInteger(d, UNNECESSARY);
305         fail("Expected ArithmeticException");
306       } catch (ArithmeticException expected) {
307       }
308     }
309   }
310 
311   @GwtIncompatible // DoubleMath.roundToBigInteger(double, RoundingMode)
testRoundNaNToBigIntegerAlwaysFails()312   public void testRoundNaNToBigIntegerAlwaysFails() {
313     for (RoundingMode mode : ALL_ROUNDING_MODES) {
314       try {
315         DoubleMath.roundToBigInteger(Double.NaN, mode);
316         fail("Expected ArithmeticException");
317       } catch (ArithmeticException expected) {
318       }
319     }
320   }
321 
322   @GwtIncompatible // DoubleMath.roundToBigInteger(double, RoundingMode)
testRoundInfiniteToBigIntegerAlwaysFails()323   public void testRoundInfiniteToBigIntegerAlwaysFails() {
324     for (RoundingMode mode : ALL_ROUNDING_MODES) {
325       try {
326         DoubleMath.roundToBigInteger(Double.POSITIVE_INFINITY, mode);
327         fail("Expected ArithmeticException");
328       } catch (ArithmeticException expected) {
329       }
330       try {
331         DoubleMath.roundToBigInteger(Double.NEGATIVE_INFINITY, mode);
332         fail("Expected ArithmeticException");
333       } catch (ArithmeticException expected) {
334       }
335     }
336   }
337 
338   @GwtIncompatible // DoubleMath.roundToBigInteger(double, RoundingMode)
testRoundLog2Floor()339   public void testRoundLog2Floor() {
340     for (double d : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
341       int log2 = DoubleMath.log2(d, FLOOR);
342       assertTrue(StrictMath.pow(2.0, log2) <= d);
343       assertTrue(StrictMath.pow(2.0, log2 + 1) > d);
344     }
345   }
346 
347   @GwtIncompatible // DoubleMath.log2(double, RoundingMode), StrictMath
testRoundLog2Ceiling()348   public void testRoundLog2Ceiling() {
349     for (double d : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
350       int log2 = DoubleMath.log2(d, CEILING);
351       assertTrue(StrictMath.pow(2.0, log2) >= d);
352       double z = StrictMath.pow(2.0, log2 - 1);
353       assertTrue(z < d);
354     }
355   }
356 
357   @GwtIncompatible // DoubleMath.log2(double, RoundingMode), StrictMath
358   public void testRoundLog2Down() {
359     for (double d : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
360       int log2 = DoubleMath.log2(d, DOWN);
361       if (d >= 1.0) {
362         assertTrue(log2 >= 0);
363         assertTrue(StrictMath.pow(2.0, log2) <= d);
364         assertTrue(StrictMath.pow(2.0, log2 + 1) > d);
365       } else {
366         assertTrue(log2 <= 0);
367         assertTrue(StrictMath.pow(2.0, log2) >= d);
368         assertTrue(StrictMath.pow(2.0, log2 - 1) < d);
369       }
370     }
371   }
372 
373   @GwtIncompatible // DoubleMath.log2(double, RoundingMode), StrictMath
374   public void testRoundLog2Up() {
375     for (double d : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
376       int log2 = DoubleMath.log2(d, UP);
377       if (d >= 1.0) {
378         assertTrue(log2 >= 0);
379         assertTrue(StrictMath.pow(2.0, log2) >= d);
380         assertTrue(StrictMath.pow(2.0, log2 - 1) < d);
381       } else {
382         assertTrue(log2 <= 0);
383         assertTrue(StrictMath.pow(2.0, log2) <= d);
384         assertTrue(StrictMath.pow(2.0, log2 + 1) > d);
385       }
386     }
387   }
388 
389   @GwtIncompatible // DoubleMath.log2(double, RoundingMode)
390   public void testRoundLog2Half() {
391     // We don't expect perfect rounding accuracy.
392     for (int exp : asList(-1022, -50, -1, 0, 1, 2, 3, 4, 100, 1022, 1023)) {
393       for (RoundingMode mode : asList(HALF_EVEN, HALF_UP, HALF_DOWN)) {
394         double x = Math.scalb(Math.sqrt(2) + 0.001, exp);
395         double y = Math.scalb(Math.sqrt(2) - 0.001, exp);
396         if (exp < 0) {
397           assertEquals(exp + 1, DoubleMath.log2(x, mode));
398           assertEquals(exp, DoubleMath.log2(y, mode));
399         } else {
400           assertEquals(exp + 1, DoubleMath.log2(x, mode));
401           assertEquals(exp, DoubleMath.log2(y, mode));
402         }
403       }
404     }
405   }
406 
407   @GwtIncompatible // DoubleMath.log2(double, RoundingMode)
408   public void testRoundLog2Exact() {
409     for (double x : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
410       boolean isPowerOfTwo = StrictMath.pow(2.0, DoubleMath.log2(x, FLOOR)) == x;
411       try {
412         int log2 = DoubleMath.log2(x, UNNECESSARY);
413         assertEquals(x, Math.scalb(1.0, log2));
414         assertTrue(isPowerOfTwo);
415       } catch (ArithmeticException e) {
416         assertFalse(isPowerOfTwo);
417       }
418     }
419   }
420 
421   @GwtIncompatible // DoubleMath.log2(double, RoundingMode)
422   public void testRoundLog2ThrowsOnZerosInfinitiesAndNaN() {
423     for (RoundingMode mode : ALL_ROUNDING_MODES) {
424       for (double d :
425           asList(0.0, -0.0, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NaN)) {
426         try {
427           DoubleMath.log2(d, mode);
428           fail("Expected IllegalArgumentException");
429         } catch (IllegalArgumentException expected) {
430         }
431       }
432     }
433   }
434 
435   @GwtIncompatible // DoubleMath.log2(double, RoundingMode)
436   public void testRoundLog2ThrowsOnNegative() {
437     for (RoundingMode mode : ALL_ROUNDING_MODES) {
438       for (double d : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
439         try {
440           DoubleMath.log2(-d, mode);
441           fail("Expected IllegalArgumentException");
442         } catch (IllegalArgumentException expected) {
443         }
444       }
445     }
446   }
447 
448   @GwtIncompatible // DoubleMath.isPowerOfTwo, DoubleMath.log2(double, RoundingMode), StrictMath
449   public void testIsPowerOfTwoYes() {
450     for (int i = -1074; i <= 1023; i++) {
451       assertTrue(DoubleMath.isPowerOfTwo(StrictMath.pow(2.0, i)));
452     }
453   }
454 
455   @GwtIncompatible // DoubleMath.isPowerOfTwo, DoubleMath.log2(double, RoundingMode), StrictMath
456   public void testIsPowerOfTwo() {
457     for (double x : ALL_DOUBLE_CANDIDATES) {
458       boolean expected =
459           x > 0
460               && !Double.isInfinite(x)
461               && !Double.isNaN(x)
462               && StrictMath.pow(2.0, DoubleMath.log2(x, FLOOR)) == x;
463       assertEquals(expected, DoubleMath.isPowerOfTwo(x));
464     }
465   }
466 
467   @GwtIncompatible // #trueLog2, Math.ulp
468   public void testLog2Accuracy() {
469     for (double d : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
470       double dmLog2 = DoubleMath.log2(d);
471       double trueLog2 = trueLog2(d);
472       assertTrue(Math.abs(dmLog2 - trueLog2) <= Math.ulp(trueLog2));
473     }
474   }
475 
476   public void testLog2SemiMonotonic() {
477     for (double d : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
478       assertTrue(DoubleMath.log2(d + 0.01) >= DoubleMath.log2(d));
479     }
480   }
481 
482   public void testLog2Negative() {
483     for (double d : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
484       assertTrue(Double.isNaN(DoubleMath.log2(-d)));
485     }
486   }
487 
488   public void testLog2Zero() {
489     assertEquals(Double.NEGATIVE_INFINITY, DoubleMath.log2(0.0));
490     assertEquals(Double.NEGATIVE_INFINITY, DoubleMath.log2(-0.0));
491   }
492 
493   public void testLog2NaNInfinity() {
494     assertEquals(Double.POSITIVE_INFINITY, DoubleMath.log2(Double.POSITIVE_INFINITY));
495     assertTrue(Double.isNaN(DoubleMath.log2(Double.NEGATIVE_INFINITY)));
496     assertTrue(Double.isNaN(DoubleMath.log2(Double.NaN)));
497   }
498 
499   @GwtIncompatible // StrictMath
500   private strictfp double trueLog2(double d) {
501     double trueLog2 = StrictMath.log(d) / StrictMath.log(2);
502     // increment until it's >= the true value
503     while (StrictMath.pow(2.0, trueLog2) < d) {
504       trueLog2 = StrictMath.nextUp(trueLog2);
505     }
506     // decrement until it's <= the true value
507     while (StrictMath.pow(2.0, trueLog2) > d) {
508       trueLog2 = StrictMath.nextAfter(trueLog2, Double.NEGATIVE_INFINITY);
509     }
510     if (StrictMath.abs(StrictMath.pow(2.0, trueLog2) - d)
511         > StrictMath.abs(StrictMath.pow(2.0, StrictMath.nextUp(trueLog2)) - d)) {
512       trueLog2 = StrictMath.nextUp(trueLog2);
513     }
514     return trueLog2;
515   }
516 
517   @GwtIncompatible // DoubleMath.isMathematicalInteger
518   public void testIsMathematicalIntegerIntegral() {
519     for (double d : INTEGRAL_DOUBLE_CANDIDATES) {
520       assertTrue(DoubleMath.isMathematicalInteger(d));
521     }
522   }
523 
524   @GwtIncompatible // DoubleMath.isMathematicalInteger
525   public void testIsMathematicalIntegerFractional() {
526     for (double d : FRACTIONAL_DOUBLE_CANDIDATES) {
527       assertFalse(DoubleMath.isMathematicalInteger(d));
528     }
529   }
530 
531   @GwtIncompatible // DoubleMath.isMathematicalInteger
532   public void testIsMathematicalIntegerNotFinite() {
533     for (double d : Arrays.asList(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NaN)) {
534       assertFalse(DoubleMath.isMathematicalInteger(d));
535     }
536   }
537 
538   @GwtIncompatible // Math.ulp
539   public void testFactorial() {
540     for (int i = 0; i <= DoubleMath.MAX_FACTORIAL; i++) {
541       double actual = BigIntegerMath.factorial(i).doubleValue();
542       double result = DoubleMath.factorial(i);
543       assertEquals(actual, result, Math.ulp(actual));
544     }
545   }
546 
547   public void testFactorialTooHigh() {
548     assertEquals(Double.POSITIVE_INFINITY, DoubleMath.factorial(DoubleMath.MAX_FACTORIAL + 1));
549     assertEquals(Double.POSITIVE_INFINITY, DoubleMath.factorial(DoubleMath.MAX_FACTORIAL + 20));
550   }
551 
552   public void testFactorialNegative() {
553     for (int n : NEGATIVE_INTEGER_CANDIDATES) {
554       try {
555         DoubleMath.factorial(n);
556         fail("Expected IllegalArgumentException");
557       } catch (IllegalArgumentException expected) {
558       }
559     }
560   }
561 
562   private static final ImmutableList<Double> FINITE_TOLERANCE_CANDIDATES =
563       ImmutableList.of(-0.0, 0.0, 1.0, 100.0, 10000.0, Double.MAX_VALUE);
564 
565   private static final Iterable<Double> TOLERANCE_CANDIDATES =
566       Iterables.concat(FINITE_TOLERANCE_CANDIDATES, ImmutableList.of(Double.POSITIVE_INFINITY));
567 
568   private static final List<Double> BAD_TOLERANCE_CANDIDATES =
569       Doubles.asList(
570           -Double.MIN_VALUE,
571           -Double.MIN_NORMAL,
572           -1,
573           -20,
574           Double.NaN,
575           Double.NEGATIVE_INFINITY,
576           -0.001);
577 
testFuzzyEqualsFinite()578   public void testFuzzyEqualsFinite() {
579     for (double a : FINITE_DOUBLE_CANDIDATES) {
580       for (double b : FINITE_DOUBLE_CANDIDATES) {
581         for (double tolerance : FINITE_TOLERANCE_CANDIDATES) {
582           assertEquals(Math.abs(a - b) <= tolerance, DoubleMath.fuzzyEquals(a, b, tolerance));
583         }
584       }
585     }
586   }
587 
testFuzzyInfiniteVersusFiniteWithFiniteTolerance()588   public void testFuzzyInfiniteVersusFiniteWithFiniteTolerance() {
589     for (double inf : INFINITIES) {
590       for (double a : FINITE_DOUBLE_CANDIDATES) {
591         for (double tolerance : FINITE_TOLERANCE_CANDIDATES) {
592           assertFalse(DoubleMath.fuzzyEquals(a, inf, tolerance));
593           assertFalse(DoubleMath.fuzzyEquals(inf, a, tolerance));
594         }
595       }
596     }
597   }
598 
testFuzzyInfiniteVersusInfiniteWithFiniteTolerance()599   public void testFuzzyInfiniteVersusInfiniteWithFiniteTolerance() {
600     for (double inf : INFINITIES) {
601       for (double tolerance : FINITE_TOLERANCE_CANDIDATES) {
602         assertTrue(DoubleMath.fuzzyEquals(inf, inf, tolerance));
603         assertFalse(DoubleMath.fuzzyEquals(inf, -inf, tolerance));
604       }
605     }
606   }
607 
testFuzzyEqualsInfiniteTolerance()608   public void testFuzzyEqualsInfiniteTolerance() {
609     for (double a : DOUBLE_CANDIDATES_EXCEPT_NAN) {
610       for (double b : DOUBLE_CANDIDATES_EXCEPT_NAN) {
611         assertTrue(DoubleMath.fuzzyEquals(a, b, Double.POSITIVE_INFINITY));
612       }
613     }
614   }
615 
testFuzzyEqualsOneNaN()616   public void testFuzzyEqualsOneNaN() {
617     for (double a : DOUBLE_CANDIDATES_EXCEPT_NAN) {
618       for (double tolerance : TOLERANCE_CANDIDATES) {
619         assertFalse(DoubleMath.fuzzyEquals(a, Double.NaN, tolerance));
620         assertFalse(DoubleMath.fuzzyEquals(Double.NaN, a, tolerance));
621       }
622     }
623   }
624 
testFuzzyEqualsTwoNaNs()625   public void testFuzzyEqualsTwoNaNs() {
626     for (double tolerance : TOLERANCE_CANDIDATES) {
627       assertTrue(DoubleMath.fuzzyEquals(Double.NaN, Double.NaN, tolerance));
628     }
629   }
630 
testFuzzyEqualsZeroTolerance()631   public void testFuzzyEqualsZeroTolerance() {
632     // make sure we test -0 tolerance
633     for (double zero : Doubles.asList(0.0, -0.0)) {
634       for (double a : ALL_DOUBLE_CANDIDATES) {
635         for (double b : ALL_DOUBLE_CANDIDATES) {
636           assertEquals(
637               a == b || (Double.isNaN(a) && Double.isNaN(b)), DoubleMath.fuzzyEquals(a, b, zero));
638         }
639       }
640     }
641   }
642 
testFuzzyEqualsBadTolerance()643   public void testFuzzyEqualsBadTolerance() {
644     for (double tolerance : BAD_TOLERANCE_CANDIDATES) {
645       try {
646         DoubleMath.fuzzyEquals(1, 2, tolerance);
647         fail("Expected IllegalArgumentException");
648       } catch (IllegalArgumentException expected) {
649         // success
650       }
651     }
652   }
653 
654   /*
655    * We've split testFuzzyCompare() into multiple tests so that our internal Android test runner has
656    * a better chance of completing each within its per-test-method timeout.
657    */
658 
testFuzzyCompare0()659   public void testFuzzyCompare0() {
660     runTestFuzzyCompare(0);
661   }
662 
testFuzzyCompare1()663   public void testFuzzyCompare1() {
664     runTestFuzzyCompare(1);
665   }
666 
testFuzzyCompare2()667   public void testFuzzyCompare2() {
668     runTestFuzzyCompare(2);
669   }
670 
testFuzzyCompare3()671   public void testFuzzyCompare3() {
672     runTestFuzzyCompare(3);
673   }
674 
testFuzzyCompare4()675   public void testFuzzyCompare4() {
676     runTestFuzzyCompare(4);
677   }
678 
testFuzzyCompare5()679   public void testFuzzyCompare5() {
680     runTestFuzzyCompare(5);
681   }
682 
testFuzzyCompare6()683   public void testFuzzyCompare6() {
684     runTestFuzzyCompare(6);
685   }
686 
testFuzzyCompare7()687   public void testFuzzyCompare7() {
688     assertEquals(7, size(TOLERANCE_CANDIDATES));
689   }
690 
runTestFuzzyCompare(int toleranceIndex)691   private static void runTestFuzzyCompare(int toleranceIndex) {
692     double tolerance = get(TOLERANCE_CANDIDATES, toleranceIndex);
693     for (double a : ALL_DOUBLE_CANDIDATES) {
694       for (double b : ALL_DOUBLE_CANDIDATES) {
695         int expected = DoubleMath.fuzzyEquals(a, b, tolerance) ? 0 : Double.compare(a, b);
696         int actual = DoubleMath.fuzzyCompare(a, b, tolerance);
697         assertEquals(Integer.signum(expected), Integer.signum(actual));
698       }
699     }
700   }
701 
testFuzzyCompareBadTolerance()702   public void testFuzzyCompareBadTolerance() {
703     for (double tolerance : BAD_TOLERANCE_CANDIDATES) {
704       try {
705         DoubleMath.fuzzyCompare(1, 2, tolerance);
706         fail("Expected IllegalArgumentException");
707       } catch (IllegalArgumentException expected) {
708         // success
709       }
710     }
711   }
712 
713   @GwtIncompatible // DoubleMath.mean
testMean_doubleVarargs()714   public void testMean_doubleVarargs() {
715     assertEquals(-1.375, DoubleMath.mean(1.1, -2.2, 4.4, -8.8), 1.0e-10);
716     assertEquals(1.1, DoubleMath.mean(1.1), 1.0e-10);
717     try {
718       DoubleMath.mean(Double.NaN);
719       fail("Expected IllegalArgumentException");
720     } catch (IllegalArgumentException expected) {
721     }
722     try {
723       DoubleMath.mean(Double.POSITIVE_INFINITY);
724       fail("Expected IllegalArgumentException");
725     } catch (IllegalArgumentException expected) {
726     }
727   }
728 
729   @GwtIncompatible // DoubleMath.mean
testMean_intVarargs()730   public void testMean_intVarargs() {
731     assertEquals(-13.75, DoubleMath.mean(11, -22, 44, -88), 1.0e-10);
732     assertEquals(11.0, DoubleMath.mean(11), 1.0e-10);
733   }
734 
735   @GwtIncompatible // DoubleMath.mean
testMean_longVarargs()736   public void testMean_longVarargs() {
737     assertEquals(-13.75, DoubleMath.mean(11L, -22L, 44L, -88L), 1.0e-10);
738     assertEquals(11.0, DoubleMath.mean(11L), 1.0e-10);
739   }
740 
741   @GwtIncompatible // DoubleMath.mean
testMean_emptyVarargs()742   public void testMean_emptyVarargs() {
743     try {
744       DoubleMath.mean();
745       fail("Expected IllegalArgumentException");
746     } catch (IllegalArgumentException expected) {
747     }
748   }
749 
750   @GwtIncompatible // DoubleMath.mean
testMean_doubleIterable()751   public void testMean_doubleIterable() {
752     assertEquals(-1.375, DoubleMath.mean(ImmutableList.of(1.1, -2.2, 4.4, -8.8)), 1.0e-10);
753     assertEquals(1.1, DoubleMath.mean(ImmutableList.of(1.1)), 1.0e-10);
754     try {
755       DoubleMath.mean(ImmutableList.<Double>of());
756       fail("Expected IllegalArgumentException");
757     } catch (IllegalArgumentException expected) {
758     }
759     try {
760       DoubleMath.mean(ImmutableList.of(Double.NaN));
761       fail("Expected IllegalArgumentException");
762     } catch (IllegalArgumentException expected) {
763     }
764     try {
765       DoubleMath.mean(ImmutableList.of(Double.POSITIVE_INFINITY));
766       fail("Expected IllegalArgumentException");
767     } catch (IllegalArgumentException expected) {
768     }
769   }
770 
771   @GwtIncompatible // DoubleMath.mean
testMean_intIterable()772   public void testMean_intIterable() {
773     assertEquals(-13.75, DoubleMath.mean(ImmutableList.of(11, -22, 44, -88)), 1.0e-10);
774     assertEquals(11, DoubleMath.mean(ImmutableList.of(11)), 1.0e-10);
775     try {
776       DoubleMath.mean(ImmutableList.<Integer>of());
777       fail("Expected IllegalArgumentException");
778     } catch (IllegalArgumentException expected) {
779     }
780   }
781 
782   @GwtIncompatible // DoubleMath.mean
testMean_longIterable()783   public void testMean_longIterable() {
784     assertEquals(-13.75, DoubleMath.mean(ImmutableList.of(11L, -22L, 44L, -88L)), 1.0e-10);
785     assertEquals(11, DoubleMath.mean(ImmutableList.of(11L)), 1.0e-10);
786     try {
787       DoubleMath.mean(ImmutableList.<Long>of());
788       fail("Expected IllegalArgumentException");
789     } catch (IllegalArgumentException expected) {
790     }
791   }
792 
793   @GwtIncompatible // DoubleMath.mean
testMean_intIterator()794   public void testMean_intIterator() {
795     assertEquals(-13.75, DoubleMath.mean(ImmutableList.of(11, -22, 44, -88).iterator()), 1.0e-10);
796     assertEquals(11, DoubleMath.mean(ImmutableList.of(11).iterator()), 1.0e-10);
797     try {
798       DoubleMath.mean(ImmutableList.<Integer>of().iterator());
799       fail("Expected IllegalArgumentException");
800     } catch (IllegalArgumentException expected) {
801     }
802   }
803 
804   @GwtIncompatible // DoubleMath.mean
testMean_longIterator()805   public void testMean_longIterator() {
806     assertEquals(
807         -13.75, DoubleMath.mean(ImmutableList.of(11L, -22L, 44L, -88L).iterator()), 1.0e-10);
808     assertEquals(11, DoubleMath.mean(ImmutableList.of(11L).iterator()), 1.0e-10);
809     try {
810       DoubleMath.mean(ImmutableList.<Long>of().iterator());
811       fail("Expected IllegalArgumentException");
812     } catch (IllegalArgumentException expected) {
813     }
814   }
815 
816   @GwtIncompatible // NullPointerTester
testNullPointers()817   public void testNullPointers() {
818     NullPointerTester tester = new NullPointerTester();
819     tester.setDefault(double.class, 3.0);
820     tester.testAllPublicStaticMethods(DoubleMath.class);
821   }
822 }
823