Example #1
0
 public void testFuzzyEqualsZeroTolerance() {
   // make sure we test -0 tolerance
   for (double zero : Doubles.asList(0.0, -0.0)) {
     for (double a : ALL_DOUBLE_CANDIDATES) {
       for (double b : ALL_DOUBLE_CANDIDATES) {
         assertEquals(
             a == b || (Double.isNaN(a) && Double.isNaN(b)), DoubleMath.fuzzyEquals(a, b, zero));
       }
     }
   }
 }
    static Map<Imt, Map<Gmm, List<Double>>> initValueMaps(Set<Imt> imts, Set<Gmm> gmms, int size) {

      Map<Imt, Map<Gmm, List<Double>>> imtMap = Maps.newEnumMap(Imt.class);
      for (Imt imt : imts) {
        Map<Gmm, List<Double>> gmmMap = Maps.newEnumMap(Gmm.class);
        for (Gmm gmm : gmms) {
          gmmMap.put(gmm, Doubles.asList(new double[size]));
        }
        imtMap.put(imt, gmmMap);
      }
      return imtMap;
    }
 static {
   ImmutableSet.Builder<Double> integralBuilder = ImmutableSet.builder();
   ImmutableSet.Builder<Double> fractionalBuilder = ImmutableSet.builder();
   integralBuilder.addAll(Doubles.asList(0.0, -0.0, Double.MAX_VALUE, -Double.MAX_VALUE));
   // Add small multiples of MIN_VALUE and MIN_NORMAL
   for (int scale = 1; scale <= 4; scale++) {
     for (double d : Doubles.asList(Double.MIN_VALUE, Double.MIN_NORMAL)) {
       fractionalBuilder.add(d * scale).add(-d * scale);
     }
   }
   for (double d :
       Doubles.asList(
           0,
           1,
           2,
           7,
           51,
           102,
           Math.scalb(1.0, 53),
           Integer.MIN_VALUE,
           Integer.MAX_VALUE,
           Long.MIN_VALUE,
           Long.MAX_VALUE)) {
     for (double delta : Doubles.asList(0.0, 1.0, 2.0)) {
       integralBuilder.addAll(Doubles.asList(d + delta, d - delta, -d - delta, -d + delta));
     }
     for (double delta : Doubles.asList(0.01, 0.1, 0.25, 0.499, 0.5, 0.501, 0.7, 0.8)) {
       double x = d + delta;
       if (x != Math.round(x)) {
         fractionalBuilder.add(x);
       }
     }
   }
   INTEGRAL_DOUBLE_CANDIDATES = integralBuilder.build();
   fractionalBuilder.add(1.414).add(1.415).add(Math.sqrt(2));
   fractionalBuilder.add(5.656).add(5.657).add(4 * Math.sqrt(2));
   for (double d : INTEGRAL_DOUBLE_CANDIDATES) {
     double x = 1 / d;
     if (x != Math.rint(x)) {
       fractionalBuilder.add(x);
     }
   }
   FRACTIONAL_DOUBLE_CANDIDATES = fractionalBuilder.build();
   FINITE_DOUBLE_CANDIDATES =
       Iterables.concat(FRACTIONAL_DOUBLE_CANDIDATES, INTEGRAL_DOUBLE_CANDIDATES);
   POSITIVE_FINITE_DOUBLE_CANDIDATES =
       Iterables.filter(
           FINITE_DOUBLE_CANDIDATES,
           new Predicate<Double>() {
             @Override
             public boolean apply(Double input) {
               return input.doubleValue() > 0.0;
             }
           });
   DOUBLE_CANDIDATES_EXCEPT_NAN = Iterables.concat(FINITE_DOUBLE_CANDIDATES, INFINITIES);
   ALL_DOUBLE_CANDIDATES = Iterables.concat(DOUBLE_CANDIDATES_EXCEPT_NAN, asList(Double.NaN));
 }
/**
 * Exhaustive input sets for every integral type.
 *
 * @author Louis Wasserman
 */
@GwtCompatible
public class MathTesting {
  static final ImmutableSet<RoundingMode> ALL_ROUNDING_MODES =
      ImmutableSet.copyOf(RoundingMode.values());

  static final ImmutableList<RoundingMode> ALL_SAFE_ROUNDING_MODES =
      ImmutableList.of(DOWN, UP, FLOOR, CEILING, HALF_EVEN, HALF_UP, HALF_DOWN);

  // Exponents to test for the pow() function.
  static final ImmutableList<Integer> EXPONENTS =
      ImmutableList.of(0, 1, 2, 3, 4, 7, 10, 15, 20, 25, 40, 70);

  /* Helper function to make a Long value from an Integer. */
  private static final Function<Integer, Long> TO_LONG =
      new Function<Integer, Long>() {
        @Override
        public Long apply(Integer n) {
          return Long.valueOf(n);
        }
      };

  /* Helper function to make a BigInteger value from a Long. */
  private static final Function<Long, BigInteger> TO_BIGINTEGER =
      new Function<Long, BigInteger>() {
        @Override
        public BigInteger apply(Long n) {
          return BigInteger.valueOf(n);
        }
      };

  private static final Function<Integer, Integer> NEGATE_INT =
      new Function<Integer, Integer>() {
        @Override
        public Integer apply(Integer x) {
          return -x;
        }
      };

  private static final Function<Long, Long> NEGATE_LONG =
      new Function<Long, Long>() {
        @Override
        public Long apply(Long x) {
          return -x;
        }
      };

  private static final Function<BigInteger, BigInteger> NEGATE_BIGINT =
      new Function<BigInteger, BigInteger>() {
        @Override
        public BigInteger apply(BigInteger x) {
          return x.negate();
        }
      };

  /*
   * This list contains values that attempt to provoke overflow in integer operations. It contains
   * positive values on or near 2^N for N near multiples of 8 (near byte boundaries).
   */
  static final ImmutableSet<Integer> POSITIVE_INTEGER_CANDIDATES;

  static final Iterable<Integer> NEGATIVE_INTEGER_CANDIDATES;

  static final Iterable<Integer> NONZERO_INTEGER_CANDIDATES;

  static final Iterable<Integer> ALL_INTEGER_CANDIDATES;

  static {
    ImmutableSet.Builder<Integer> intValues = ImmutableSet.builder();
    // Add boundary values manually to avoid over/under flow (this covers 2^N for 0 and 31).
    intValues.add(Integer.MAX_VALUE - 1, Integer.MAX_VALUE);
    // Add values up to 40. This covers cases like "square of a prime" and such.
    for (int i = 1; i <= 40; i++) {
      intValues.add(i);
    }
    // Now add values near 2^N for lots of values of N.
    for (int exponent : asList(2, 3, 4, 9, 15, 16, 17, 24, 25, 30)) {
      int x = 1 << exponent;
      intValues.add(x, x + 1, x - 1);
    }
    intValues.add(9999).add(10000).add(10001).add(1000000); // near powers of 10
    intValues.add(5792).add(5793); // sqrt(2^25) rounded up and down
    POSITIVE_INTEGER_CANDIDATES = intValues.build();
    NEGATIVE_INTEGER_CANDIDATES =
        ImmutableList.copyOf(
            Iterables.concat(
                Iterables.transform(POSITIVE_INTEGER_CANDIDATES, NEGATE_INT),
                ImmutableList.of(Integer.MIN_VALUE)));
    NONZERO_INTEGER_CANDIDATES =
        ImmutableList.copyOf(
            Iterables.concat(POSITIVE_INTEGER_CANDIDATES, NEGATIVE_INTEGER_CANDIDATES));
    ALL_INTEGER_CANDIDATES = Iterables.concat(NONZERO_INTEGER_CANDIDATES, ImmutableList.of(0));
  }

  /*
   * This list contains values that attempt to provoke overflow in long operations. It contains
   * positive values on or near 2^N for N near multiples of 8 (near byte boundaries). This list is
   * a superset of POSITIVE_INTEGER_CANDIDATES.
   */
  static final ImmutableSet<Long> POSITIVE_LONG_CANDIDATES;

  static final Iterable<Long> NEGATIVE_LONG_CANDIDATES;

  static final Iterable<Long> NONZERO_LONG_CANDIDATES;

  static final Iterable<Long> ALL_LONG_CANDIDATES;

  static {
    ImmutableSet.Builder<Long> longValues = ImmutableSet.builder();
    // First of all add all the integer candidate values.
    longValues.addAll(Iterables.transform(POSITIVE_INTEGER_CANDIDATES, TO_LONG));
    // Add boundary values manually to avoid over/under flow (this covers 2^N for 31 and 63).
    longValues.add(Integer.MAX_VALUE + 1L, Long.MAX_VALUE - 1L, Long.MAX_VALUE);
    // Now add values near 2^N for lots of values of N.
    for (int exponent : asList(32, 33, 39, 40, 41, 47, 48, 49, 55, 56, 57)) {
      long x = 1L << exponent;
      longValues.add(x, x + 1, x - 1);
    }
    longValues.add(194368031998L).add(194368031999L); // sqrt(2^75) rounded up and down
    POSITIVE_LONG_CANDIDATES = longValues.build();
    NEGATIVE_LONG_CANDIDATES =
        Iterables.concat(
            Iterables.transform(POSITIVE_LONG_CANDIDATES, NEGATE_LONG),
            ImmutableList.of(Long.MIN_VALUE));
    NONZERO_LONG_CANDIDATES = Iterables.concat(POSITIVE_LONG_CANDIDATES, NEGATIVE_LONG_CANDIDATES);
    ALL_LONG_CANDIDATES = Iterables.concat(NONZERO_LONG_CANDIDATES, ImmutableList.of(0L));
  }

  /*
   * This list contains values that attempt to provoke overflow in big integer operations. It
   * contains positive values on or near 2^N for N near multiples of 8 (near byte boundaries). This
   * list is a superset of POSITIVE_LONG_CANDIDATES.
   */
  static final ImmutableSet<BigInteger> POSITIVE_BIGINTEGER_CANDIDATES;

  static final Iterable<BigInteger> NEGATIVE_BIGINTEGER_CANDIDATES;

  static final Iterable<BigInteger> NONZERO_BIGINTEGER_CANDIDATES;

  static final Iterable<BigInteger> ALL_BIGINTEGER_CANDIDATES;

  static {
    ImmutableSet.Builder<BigInteger> bigValues = ImmutableSet.builder();
    // First of all add all the long candidate values.
    bigValues.addAll(Iterables.transform(POSITIVE_LONG_CANDIDATES, TO_BIGINTEGER));
    // Add boundary values manually to avoid over/under flow.
    bigValues.add(BigInteger.valueOf(Long.MAX_VALUE).add(ONE));
    // Now add values near 2^N for lots of values of N.
    for (int exponent :
        asList(
            64,
            65,
            71,
            72,
            73,
            79,
            80,
            81,
            255,
            256,
            257,
            511,
            512,
            513,
            Double.MAX_EXPONENT - 1,
            Double.MAX_EXPONENT,
            Double.MAX_EXPONENT + 1)) {
      BigInteger x = ONE.shiftLeft(exponent);
      bigValues.add(x, x.add(ONE), x.subtract(ONE));
    }
    bigValues.add(new BigInteger("218838949120258359057546633")); // sqrt(2^175) rounded up and
    // down
    bigValues.add(new BigInteger("218838949120258359057546634"));
    POSITIVE_BIGINTEGER_CANDIDATES = bigValues.build();
    NEGATIVE_BIGINTEGER_CANDIDATES =
        Iterables.transform(POSITIVE_BIGINTEGER_CANDIDATES, NEGATE_BIGINT);
    NONZERO_BIGINTEGER_CANDIDATES =
        Iterables.concat(POSITIVE_BIGINTEGER_CANDIDATES, NEGATIVE_BIGINTEGER_CANDIDATES);
    ALL_BIGINTEGER_CANDIDATES =
        Iterables.concat(NONZERO_BIGINTEGER_CANDIDATES, ImmutableList.of(ZERO));
  }

  static final ImmutableSet<Double> INTEGRAL_DOUBLE_CANDIDATES;
  static final ImmutableSet<Double> FRACTIONAL_DOUBLE_CANDIDATES;
  static final Iterable<Double> INFINITIES =
      Doubles.asList(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY);
  static final Iterable<Double> FINITE_DOUBLE_CANDIDATES;
  static final Iterable<Double> POSITIVE_FINITE_DOUBLE_CANDIDATES;
  static final Iterable<Double> ALL_DOUBLE_CANDIDATES;
  static final Iterable<Double> DOUBLE_CANDIDATES_EXCEPT_NAN;

  static {
    ImmutableSet.Builder<Double> integralBuilder = ImmutableSet.builder();
    ImmutableSet.Builder<Double> fractionalBuilder = ImmutableSet.builder();
    integralBuilder.addAll(Doubles.asList(0.0, -0.0, Double.MAX_VALUE, -Double.MAX_VALUE));
    // Add small multiples of MIN_VALUE and MIN_NORMAL
    for (int scale = 1; scale <= 4; scale++) {
      for (double d : Doubles.asList(Double.MIN_VALUE, Double.MIN_NORMAL)) {
        fractionalBuilder.add(d * scale).add(-d * scale);
      }
    }
    for (double d :
        Doubles.asList(
            0,
            1,
            2,
            7,
            51,
            102,
            Math.scalb(1.0, 53),
            Integer.MIN_VALUE,
            Integer.MAX_VALUE,
            Long.MIN_VALUE,
            Long.MAX_VALUE)) {
      for (double delta : Doubles.asList(0.0, 1.0, 2.0)) {
        integralBuilder.addAll(Doubles.asList(d + delta, d - delta, -d - delta, -d + delta));
      }
      for (double delta : Doubles.asList(0.01, 0.1, 0.25, 0.499, 0.5, 0.501, 0.7, 0.8)) {
        double x = d + delta;
        if (x != Math.round(x)) {
          fractionalBuilder.add(x);
        }
      }
    }
    INTEGRAL_DOUBLE_CANDIDATES = integralBuilder.build();
    fractionalBuilder.add(1.414).add(1.415).add(Math.sqrt(2));
    fractionalBuilder.add(5.656).add(5.657).add(4 * Math.sqrt(2));
    for (double d : INTEGRAL_DOUBLE_CANDIDATES) {
      double x = 1 / d;
      if (x != Math.rint(x)) {
        fractionalBuilder.add(x);
      }
    }
    FRACTIONAL_DOUBLE_CANDIDATES = fractionalBuilder.build();
    FINITE_DOUBLE_CANDIDATES =
        Iterables.concat(FRACTIONAL_DOUBLE_CANDIDATES, INTEGRAL_DOUBLE_CANDIDATES);
    POSITIVE_FINITE_DOUBLE_CANDIDATES =
        Iterables.filter(
            FINITE_DOUBLE_CANDIDATES,
            new Predicate<Double>() {
              @Override
              public boolean apply(Double input) {
                return input.doubleValue() > 0.0;
              }
            });
    DOUBLE_CANDIDATES_EXCEPT_NAN = Iterables.concat(FINITE_DOUBLE_CANDIDATES, INFINITIES);
    ALL_DOUBLE_CANDIDATES = Iterables.concat(DOUBLE_CANDIDATES_EXCEPT_NAN, asList(Double.NaN));
  }
}
Example #5
0
/**
 * Tests for {@code DoubleMath}.
 *
 * @author Louis Wasserman
 */
public class DoubleMathTest extends TestCase {

  private static final BigDecimal MAX_INT_AS_BIG_DECIMAL = BigDecimal.valueOf(Integer.MAX_VALUE);
  private static final BigDecimal MIN_INT_AS_BIG_DECIMAL = BigDecimal.valueOf(Integer.MIN_VALUE);

  private static final BigDecimal MAX_LONG_AS_BIG_DECIMAL = BigDecimal.valueOf(Long.MAX_VALUE);
  private static final BigDecimal MIN_LONG_AS_BIG_DECIMAL = BigDecimal.valueOf(Long.MIN_VALUE);

  public void testConstantsMaxFactorial() {
    BigInteger MAX_DOUBLE_VALUE = BigDecimal.valueOf(Double.MAX_VALUE).toBigInteger();
    assertTrue(BigIntegerMath.factorial(DoubleMath.MAX_FACTORIAL).compareTo(MAX_DOUBLE_VALUE) <= 0);
    assertTrue(
        BigIntegerMath.factorial(DoubleMath.MAX_FACTORIAL + 1).compareTo(MAX_DOUBLE_VALUE) > 0);
  }

  public void testConstantsEverySixteenthFactorial() {
    for (int i = 0, n = 0; n <= DoubleMath.MAX_FACTORIAL; i++, n += 16) {
      assertEquals(
          BigIntegerMath.factorial(n).doubleValue(), DoubleMath.EVERY_SIXTEENTH_FACTORIAL[i]);
    }
  }

  public void testRoundIntegralDoubleToInt() {
    for (double d : INTEGRAL_DOUBLE_CANDIDATES) {
      for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
        BigDecimal expected = new BigDecimal(d).setScale(0, mode);
        boolean isInBounds =
            expected.compareTo(MAX_INT_AS_BIG_DECIMAL) <= 0
                & expected.compareTo(MIN_INT_AS_BIG_DECIMAL) >= 0;

        try {
          assertEquals(expected.intValue(), DoubleMath.roundToInt(d, mode));
          assertTrue(isInBounds);
        } catch (ArithmeticException e) {
          assertFalse(isInBounds);
        }
      }
    }
  }

  public void testRoundFractionalDoubleToInt() {
    for (double d : FRACTIONAL_DOUBLE_CANDIDATES) {
      for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
        BigDecimal expected = new BigDecimal(d).setScale(0, mode);
        boolean isInBounds =
            expected.compareTo(MAX_INT_AS_BIG_DECIMAL) <= 0
                & expected.compareTo(MIN_INT_AS_BIG_DECIMAL) >= 0;

        try {
          assertEquals(expected.intValue(), DoubleMath.roundToInt(d, mode));
          assertTrue(isInBounds);
        } catch (ArithmeticException e) {
          assertFalse(isInBounds);
        }
      }
    }
  }

  public void testRoundExactIntegralDoubleToInt() {
    for (double d : INTEGRAL_DOUBLE_CANDIDATES) {
      BigDecimal expected = new BigDecimal(d).setScale(0, UNNECESSARY);
      boolean isInBounds =
          expected.compareTo(MAX_INT_AS_BIG_DECIMAL) <= 0
              & expected.compareTo(MIN_INT_AS_BIG_DECIMAL) >= 0;

      try {
        assertEquals(expected.intValue(), DoubleMath.roundToInt(d, UNNECESSARY));
        assertTrue(isInBounds);
      } catch (ArithmeticException e) {
        assertFalse(isInBounds);
      }
    }
  }

  public void testRoundExactFractionalDoubleToIntFails() {
    for (double d : FRACTIONAL_DOUBLE_CANDIDATES) {
      try {
        DoubleMath.roundToInt(d, UNNECESSARY);
        fail("Expected ArithmeticException");
      } catch (ArithmeticException expected) {
      }
    }
  }

  public void testRoundNaNToIntAlwaysFails() {
    for (RoundingMode mode : ALL_ROUNDING_MODES) {
      try {
        DoubleMath.roundToInt(Double.NaN, mode);
        fail("Expected ArithmeticException");
      } catch (ArithmeticException expected) {
      }
    }
  }

  public void testRoundInfiniteToIntAlwaysFails() {
    for (RoundingMode mode : ALL_ROUNDING_MODES) {
      try {
        DoubleMath.roundToInt(Double.POSITIVE_INFINITY, mode);
        fail("Expected ArithmeticException");
      } catch (ArithmeticException expected) {
      }
      try {
        DoubleMath.roundToInt(Double.NEGATIVE_INFINITY, mode);
        fail("Expected ArithmeticException");
      } catch (ArithmeticException expected) {
      }
    }
  }

  public void testRoundIntegralDoubleToLong() {
    for (double d : INTEGRAL_DOUBLE_CANDIDATES) {
      for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
        BigDecimal expected = new BigDecimal(d).setScale(0, mode);
        boolean isInBounds =
            expected.compareTo(MAX_LONG_AS_BIG_DECIMAL) <= 0
                & expected.compareTo(MIN_LONG_AS_BIG_DECIMAL) >= 0;

        try {
          assertEquals(expected.longValue(), DoubleMath.roundToLong(d, mode));
          assertTrue(isInBounds);
        } catch (ArithmeticException e) {
          assertFalse(isInBounds);
        }
      }
    }
  }

  public void testRoundFractionalDoubleToLong() {
    for (double d : FRACTIONAL_DOUBLE_CANDIDATES) {
      for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
        BigDecimal expected = new BigDecimal(d).setScale(0, mode);
        boolean isInBounds =
            expected.compareTo(MAX_LONG_AS_BIG_DECIMAL) <= 0
                & expected.compareTo(MIN_LONG_AS_BIG_DECIMAL) >= 0;

        try {
          assertEquals(expected.longValue(), DoubleMath.roundToLong(d, mode));
          assertTrue(isInBounds);
        } catch (ArithmeticException e) {
          assertFalse(isInBounds);
        }
      }
    }
  }

  public void testRoundExactIntegralDoubleToLong() {
    for (double d : INTEGRAL_DOUBLE_CANDIDATES) {
      // every mode except UNNECESSARY
      BigDecimal expected = new BigDecimal(d).setScale(0, UNNECESSARY);
      boolean isInBounds =
          expected.compareTo(MAX_LONG_AS_BIG_DECIMAL) <= 0
              & expected.compareTo(MIN_LONG_AS_BIG_DECIMAL) >= 0;

      try {
        assertEquals(expected.longValue(), DoubleMath.roundToLong(d, UNNECESSARY));
        assertTrue(isInBounds);
      } catch (ArithmeticException e) {
        assertFalse(isInBounds);
      }
    }
  }

  public void testRoundExactFractionalDoubleToLongFails() {
    for (double d : FRACTIONAL_DOUBLE_CANDIDATES) {
      try {
        DoubleMath.roundToLong(d, UNNECESSARY);
        fail("Expected ArithmeticException");
      } catch (ArithmeticException expected) {
      }
    }
  }

  public void testRoundNaNToLongAlwaysFails() {
    for (RoundingMode mode : ALL_ROUNDING_MODES) {
      try {
        DoubleMath.roundToLong(Double.NaN, mode);
        fail("Expected ArithmeticException");
      } catch (ArithmeticException expected) {
      }
    }
  }

  public void testRoundInfiniteToLongAlwaysFails() {
    for (RoundingMode mode : ALL_ROUNDING_MODES) {
      try {
        DoubleMath.roundToLong(Double.POSITIVE_INFINITY, mode);
        fail("Expected ArithmeticException");
      } catch (ArithmeticException expected) {
      }
      try {
        DoubleMath.roundToLong(Double.NEGATIVE_INFINITY, mode);
        fail("Expected ArithmeticException");
      } catch (ArithmeticException expected) {
      }
    }
  }

  public void testRoundIntegralDoubleToBigInteger() {
    for (double d : INTEGRAL_DOUBLE_CANDIDATES) {
      for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
        BigDecimal expected = new BigDecimal(d).setScale(0, mode);
        assertEquals(expected.toBigInteger(), DoubleMath.roundToBigInteger(d, mode));
      }
    }
  }

  public void testRoundFractionalDoubleToBigInteger() {
    for (double d : FRACTIONAL_DOUBLE_CANDIDATES) {
      for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
        BigDecimal expected = new BigDecimal(d).setScale(0, mode);
        assertEquals(expected.toBigInteger(), DoubleMath.roundToBigInteger(d, mode));
      }
    }
  }

  public void testRoundExactIntegralDoubleToBigInteger() {
    for (double d : INTEGRAL_DOUBLE_CANDIDATES) {
      BigDecimal expected = new BigDecimal(d).setScale(0, UNNECESSARY);
      assertEquals(expected.toBigInteger(), DoubleMath.roundToBigInteger(d, UNNECESSARY));
    }
  }

  public void testRoundExactFractionalDoubleToBigIntegerFails() {
    for (double d : FRACTIONAL_DOUBLE_CANDIDATES) {
      try {
        DoubleMath.roundToBigInteger(d, UNNECESSARY);
        fail("Expected ArithmeticException");
      } catch (ArithmeticException expected) {
      }
    }
  }

  public void testRoundNaNToBigIntegerAlwaysFails() {
    for (RoundingMode mode : ALL_ROUNDING_MODES) {
      try {
        DoubleMath.roundToBigInteger(Double.NaN, mode);
        fail("Expected ArithmeticException");
      } catch (ArithmeticException expected) {
      }
    }
  }

  public void testRoundInfiniteToBigIntegerAlwaysFails() {
    for (RoundingMode mode : ALL_ROUNDING_MODES) {
      try {
        DoubleMath.roundToBigInteger(Double.POSITIVE_INFINITY, mode);
        fail("Expected ArithmeticException");
      } catch (ArithmeticException expected) {
      }
      try {
        DoubleMath.roundToBigInteger(Double.NEGATIVE_INFINITY, mode);
        fail("Expected ArithmeticException");
      } catch (ArithmeticException expected) {
      }
    }
  }

  public void testRoundLog2Floor() {
    for (double d : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
      int log2 = DoubleMath.log2(d, FLOOR);
      assertTrue(StrictMath.pow(2.0, log2) <= d);
      assertTrue(StrictMath.pow(2.0, log2 + 1) > d);
    }
  }

  public void testRoundLog2Ceiling() {
    for (double d : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
      int log2 = DoubleMath.log2(d, CEILING);
      assertTrue(StrictMath.pow(2.0, log2) >= d);
      double z = StrictMath.pow(2.0, log2 - 1);
      assertTrue(z < d);
    }
  }

  public void testRoundLog2Down() {
    for (double d : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
      int log2 = DoubleMath.log2(d, DOWN);
      if (d >= 1.0) {
        assertTrue(log2 >= 0);
        assertTrue(StrictMath.pow(2.0, log2) <= d);
        assertTrue(StrictMath.pow(2.0, log2 + 1) > d);
      } else {
        assertTrue(log2 <= 0);
        assertTrue(StrictMath.pow(2.0, log2) >= d);
        assertTrue(StrictMath.pow(2.0, log2 - 1) < d);
      }
    }
  }

  public void testRoundLog2Up() {
    for (double d : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
      int log2 = DoubleMath.log2(d, UP);
      if (d >= 1.0) {
        assertTrue(log2 >= 0);
        assertTrue(StrictMath.pow(2.0, log2) >= d);
        assertTrue(StrictMath.pow(2.0, log2 - 1) < d);
      } else {
        assertTrue(log2 <= 0);
        assertTrue(StrictMath.pow(2.0, log2) <= d);
        assertTrue(StrictMath.pow(2.0, log2 + 1) > d);
      }
    }
  }

  public void testRoundLog2Half() {
    // We don't expect perfect rounding accuracy.
    for (int exp : asList(-1022, -50, -1, 0, 1, 2, 3, 4, 100, 1022, 1023)) {
      for (RoundingMode mode : asList(HALF_EVEN, HALF_UP, HALF_DOWN)) {
        double x = Math.scalb(Math.sqrt(2) + 0.001, exp);
        double y = Math.scalb(Math.sqrt(2) - 0.001, exp);
        if (exp < 0) {
          assertEquals(exp + 1, DoubleMath.log2(x, mode));
          assertEquals(exp, DoubleMath.log2(y, mode));
        } else {
          assertEquals(exp + 1, DoubleMath.log2(x, mode));
          assertEquals(exp, DoubleMath.log2(y, mode));
        }
      }
    }
  }

  public void testRoundLog2Exact() {
    for (double x : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
      boolean isPowerOfTwo = StrictMath.pow(2.0, DoubleMath.log2(x, FLOOR)) == x;
      try {
        int log2 = DoubleMath.log2(x, UNNECESSARY);
        assertEquals(x, Math.scalb(1.0, log2));
        assertTrue(isPowerOfTwo);
      } catch (ArithmeticException e) {
        assertFalse(isPowerOfTwo);
      }
    }
  }

  public void testRoundLog2ThrowsOnZerosInfinitiesAndNaN() {
    for (RoundingMode mode : ALL_ROUNDING_MODES) {
      for (double d :
          asList(0.0, -0.0, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NaN)) {
        try {
          DoubleMath.log2(d, mode);
          fail("Expected IllegalArgumentException");
        } catch (IllegalArgumentException e) {
        }
      }
    }
  }

  public void testRoundLog2ThrowsOnNegative() {
    for (RoundingMode mode : ALL_ROUNDING_MODES) {
      for (double d : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
        try {
          DoubleMath.log2(-d, mode);
          fail("Expected IllegalArgumentException");
        } catch (IllegalArgumentException e) {
        }
      }
    }
  }

  public void testIsPowerOfTwoYes() {
    for (int i = -1074; i <= 1023; i++) {
      assertTrue(DoubleMath.isPowerOfTwo(StrictMath.pow(2.0, i)));
    }
  }

  public void testIsPowerOfTwo() {
    for (double x : ALL_DOUBLE_CANDIDATES) {
      boolean expected =
          x > 0
              && !Double.isInfinite(x)
              && !Double.isNaN(x)
              && StrictMath.pow(2.0, DoubleMath.log2(x, FLOOR)) == x;
      assertEquals(expected, DoubleMath.isPowerOfTwo(x));
    }
  }

  public void testLog2Accuracy() {
    for (double d : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
      double dmLog2 = DoubleMath.log2(d);
      double trueLog2 = trueLog2(d);
      assertTrue(Math.abs(dmLog2 - trueLog2) <= Math.ulp(trueLog2));
    }
  }

  public void testLog2SemiMonotonic() {
    for (double d : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
      assertTrue(DoubleMath.log2(d + 0.01) >= DoubleMath.log2(d));
    }
  }

  public void testLog2Negative() {
    for (double d : POSITIVE_FINITE_DOUBLE_CANDIDATES) {
      assertTrue(Double.isNaN(DoubleMath.log2(-d)));
    }
  }

  public void testLog2Zero() {
    assertEquals(Double.NEGATIVE_INFINITY, DoubleMath.log2(0.0));
    assertEquals(Double.NEGATIVE_INFINITY, DoubleMath.log2(-0.0));
  }

  public void testLog2NaNInfinity() {
    assertEquals(Double.POSITIVE_INFINITY, DoubleMath.log2(Double.POSITIVE_INFINITY));
    assertTrue(Double.isNaN(DoubleMath.log2(Double.NEGATIVE_INFINITY)));
    assertTrue(Double.isNaN(DoubleMath.log2(Double.NaN)));
  }

  private strictfp double trueLog2(double d) {
    double trueLog2 = StrictMath.log(d) / StrictMath.log(2);
    // increment until it's >= the true value
    while (StrictMath.pow(2.0, trueLog2) < d) {
      trueLog2 = StrictMath.nextUp(trueLog2);
    }
    // decrement until it's <= the true value
    while (StrictMath.pow(2.0, trueLog2) > d) {
      trueLog2 = StrictMath.nextAfter(trueLog2, Double.NEGATIVE_INFINITY);
    }
    if (StrictMath.abs(StrictMath.pow(2.0, trueLog2) - d)
        > StrictMath.abs(StrictMath.pow(2.0, StrictMath.nextUp(trueLog2)) - d)) {
      trueLog2 = StrictMath.nextUp(trueLog2);
    }
    return trueLog2;
  }

  public void testIsMathematicalIntegerIntegral() {
    for (double d : INTEGRAL_DOUBLE_CANDIDATES) {
      assertTrue(DoubleMath.isMathematicalInteger(d));
    }
  }

  public void testIsMathematicalIntegerFractional() {
    for (double d : FRACTIONAL_DOUBLE_CANDIDATES) {
      assertFalse(DoubleMath.isMathematicalInteger(d));
    }
  }

  public void testIsMathematicalIntegerNotFinite() {
    for (double d : Arrays.asList(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NaN)) {
      assertFalse(DoubleMath.isMathematicalInteger(d));
    }
  }

  public void testFactorial() {
    for (int i = 0; i <= DoubleMath.MAX_FACTORIAL; i++) {
      double actual = BigIntegerMath.factorial(i).doubleValue();
      double result = DoubleMath.factorial(i);
      assertEquals(actual, result, Math.ulp(actual));
    }
  }

  public void testFactorialTooHigh() {
    assertEquals(Double.POSITIVE_INFINITY, DoubleMath.factorial(DoubleMath.MAX_FACTORIAL + 1));
    assertEquals(Double.POSITIVE_INFINITY, DoubleMath.factorial(DoubleMath.MAX_FACTORIAL + 20));
  }

  public void testFactorialNegative() {
    for (int n : NEGATIVE_INTEGER_CANDIDATES) {
      try {
        DoubleMath.factorial(n);
        fail("Expected IllegalArgumentException");
      } catch (IllegalArgumentException expected) {
      }
    }
  }

  private static final ImmutableList<Double> FINITE_TOLERANCE_CANDIDATES =
      ImmutableList.of(-0.0, 0.0, 1.0, 100.0, 10000.0, Double.MAX_VALUE);

  private static final Iterable<Double> TOLERANCE_CANDIDATES =
      Iterables.concat(FINITE_TOLERANCE_CANDIDATES, ImmutableList.of(Double.POSITIVE_INFINITY));

  private static final List<Double> BAD_TOLERANCE_CANDIDATES =
      Doubles.asList(
          -Double.MIN_VALUE,
          -Double.MIN_NORMAL,
          -1,
          -20,
          Double.NaN,
          Double.NEGATIVE_INFINITY,
          -0.001);

  public void testFuzzyEqualsFinite() {
    for (double a : FINITE_DOUBLE_CANDIDATES) {
      for (double b : FINITE_DOUBLE_CANDIDATES) {
        for (double tolerance : FINITE_TOLERANCE_CANDIDATES) {
          assertEquals(Math.abs(a - b) <= tolerance, DoubleMath.fuzzyEquals(a, b, tolerance));
        }
      }
    }
  }

  public void testFuzzyInfiniteVersusFiniteWithFiniteTolerance() {
    for (double inf : INFINITIES) {
      for (double a : FINITE_DOUBLE_CANDIDATES) {
        for (double tolerance : FINITE_TOLERANCE_CANDIDATES) {
          assertFalse(DoubleMath.fuzzyEquals(a, inf, tolerance));
          assertFalse(DoubleMath.fuzzyEquals(inf, a, tolerance));
        }
      }
    }
  }

  public void testFuzzyInfiniteVersusInfiniteWithFiniteTolerance() {
    for (double inf : INFINITIES) {
      for (double tolerance : FINITE_TOLERANCE_CANDIDATES) {
        assertTrue(DoubleMath.fuzzyEquals(inf, inf, tolerance));
        assertFalse(DoubleMath.fuzzyEquals(inf, -inf, tolerance));
      }
    }
  }

  public void testFuzzyEqualsInfiniteTolerance() {
    for (double a : DOUBLE_CANDIDATES_EXCEPT_NAN) {
      for (double b : DOUBLE_CANDIDATES_EXCEPT_NAN) {
        assertTrue(DoubleMath.fuzzyEquals(a, b, Double.POSITIVE_INFINITY));
      }
    }
  }

  public void testFuzzyEqualsOneNaN() {
    for (double a : DOUBLE_CANDIDATES_EXCEPT_NAN) {
      for (double tolerance : TOLERANCE_CANDIDATES) {
        assertFalse(DoubleMath.fuzzyEquals(a, Double.NaN, tolerance));
        assertFalse(DoubleMath.fuzzyEquals(Double.NaN, a, tolerance));
      }
    }
  }

  public void testFuzzyEqualsTwoNaNs() {
    for (double tolerance : TOLERANCE_CANDIDATES) {
      assertTrue(DoubleMath.fuzzyEquals(Double.NaN, Double.NaN, tolerance));
    }
  }

  public void testFuzzyEqualsZeroTolerance() {
    // make sure we test -0 tolerance
    for (double zero : Doubles.asList(0.0, -0.0)) {
      for (double a : ALL_DOUBLE_CANDIDATES) {
        for (double b : ALL_DOUBLE_CANDIDATES) {
          assertEquals(
              a == b || (Double.isNaN(a) && Double.isNaN(b)), DoubleMath.fuzzyEquals(a, b, zero));
        }
      }
    }
  }

  public void testFuzzyEqualsBadTolerance() {
    for (double tolerance : BAD_TOLERANCE_CANDIDATES) {
      try {
        DoubleMath.fuzzyEquals(1, 2, tolerance);
        fail("Expected IllegalArgumentException");
      } catch (IllegalArgumentException expected) {
        // success
      }
    }
  }

  public void testFuzzyCompare() {
    for (double a : ALL_DOUBLE_CANDIDATES) {
      for (double b : ALL_DOUBLE_CANDIDATES) {
        for (double tolerance : TOLERANCE_CANDIDATES) {
          int expected = DoubleMath.fuzzyEquals(a, b, tolerance) ? 0 : Double.compare(a, b);
          int actual = DoubleMath.fuzzyCompare(a, b, tolerance);
          assertEquals(Integer.signum(expected), Integer.signum(actual));
        }
      }
    }
  }

  public void testFuzzyCompareBadTolerance() {
    for (double tolerance : BAD_TOLERANCE_CANDIDATES) {
      try {
        DoubleMath.fuzzyCompare(1, 2, tolerance);
        fail("Expected IllegalArgumentException");
      } catch (IllegalArgumentException expected) {
        // success
      }
    }
  }

  public void testNullPointers() {
    NullPointerTester tester = new NullPointerTester();
    tester.setDefault(RoundingMode.class, FLOOR);
    tester.setDefault(double.class, 3.0);
    tester.testAllPublicStaticMethods(DoubleMath.class);
  }
}
 private static ImmutableList<Double> values(double... values) {
   return ImmutableList.copyOf(Doubles.asList(values));
 }