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