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