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