1 /* 2 * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * Shared static test methods for numerical tests. Sharing these 26 * helper test methods avoids repeated functions in the various test 27 * programs. The test methods return 1 for a test failure and 0 for 28 * success. The order of arguments to the test methods is generally 29 * the test name, followed by the test arguments, the computed result, 30 * and finally the expected result. 31 */ 32 package test.java.lang.Math; 33 34 import org.testng.annotations.Test; 35 import org.testng.Assert; 36 37 public class Tests { 38 Tests()39 private Tests() { 40 } 41 42 ; // do not instantiate 43 toHexString(float f)44 public static String toHexString(float f) { 45 if (!Float.isNaN(f)) { 46 return Float.toHexString(f); 47 } else { 48 return "NaN(0x" + Integer.toHexString(Float.floatToRawIntBits(f)) + ")"; 49 } 50 } 51 toHexString(double d)52 public static String toHexString(double d) { 53 if (!Double.isNaN(d)) { 54 return Double.toHexString(d); 55 } else { 56 return "NaN(0x" + Long.toHexString(Double.doubleToRawLongBits(d)) + ")"; 57 } 58 } 59 60 /** 61 * Return the floating-point value next larger in magnitude. 62 */ nextOut(double d)63 public static double nextOut(double d) { 64 if (d > 0.0) { 65 return Math.nextUp(d); 66 } else { 67 return -Math.nextUp(-d); 68 } 69 } 70 71 /** 72 * Returns unbiased exponent of a {@code float}; for subnormal values, the number is treated as 73 * if it were normalized. That is for all finite, non-zero, positive numbers 74 * <i>x</i>, <code>scalb(<i>x</i>, -ilogb(<i>x</i>))</code> is 75 * always in the range [1, 2). 76 * <p> 77 * Special cases: 78 * <ul> 79 * <li> If the argument is NaN, then the result is 2<sup>30</sup>. 80 * <li> If the argument is infinite, then the result is 2<sup>28</sup>. 81 * <li> If the argument is zero, then the result is -(2<sup>28</sup>). 82 * </ul> 83 * 84 * @param d double number which exponent is to be extracted 85 * @return unbiased exponent of the argument. 86 */ ilogb(double d)87 public static int ilogb(double d) { 88 int exponent = Math.getExponent(d); 89 90 switch (exponent) { 91 case Double.MAX_EXPONENT + 1: // NaN or infinity 92 if (Double.isNaN(d)) { 93 return (1 << 30); // 2^30 94 } else // infinite value 95 { 96 return (1 << 28); // 2^28 97 } 98 99 case Double.MIN_EXPONENT - 1: // zero or subnormal 100 if (d == 0.0) { 101 return -(1 << 28); // -(2^28) 102 } else { 103 long transducer = Double.doubleToRawLongBits(d); 104 105 /* 106 * To avoid causing slow arithmetic on subnormals, 107 * the scaling to determine when d's significand 108 * is normalized is done in integer arithmetic. 109 * (there must be at least one "1" bit in the 110 * significand since zero has been screened out. 111 */ 112 113 // isolate significand bits 114 transducer &= DoubleConsts.SIGNIF_BIT_MASK; 115 Assert.assertNotEquals(transducer, 0L); 116 117 // This loop is simple and functional. We might be 118 // able to do something more clever that was faster; 119 // e.g. number of leading zero detection on 120 // (transducer << (# exponent and sign bits). 121 while (transducer < 122 (1L << (DoubleConsts.SIGNIFICAND_WIDTH - 1))) { 123 transducer *= 2; 124 exponent--; 125 } 126 exponent++; 127 Assert.assertTrue(exponent >= 128 Double.MIN_EXPONENT - (DoubleConsts.SIGNIFICAND_WIDTH - 1) && 129 exponent < Double.MIN_EXPONENT); 130 return exponent; 131 } 132 133 default: 134 Assert.assertTrue(exponent >= Double.MIN_EXPONENT && 135 exponent <= Double.MAX_EXPONENT); 136 return exponent; 137 } 138 } 139 140 /** 141 * Returns unbiased exponent of a {@code float}; for subnormal values, the number is treated as 142 * if it were normalized. That is for all finite, non-zero, positive numbers 143 * <i>x</i>, <code>scalb(<i>x</i>, -ilogb(<i>x</i>))</code> is 144 * always in the range [1, 2). 145 * <p> 146 * Special cases: 147 * <ul> 148 * <li> If the argument is NaN, then the result is 2<sup>30</sup>. 149 * <li> If the argument is infinite, then the result is 2<sup>28</sup>. 150 * <li> If the argument is zero, then the result is -(2<sup>28</sup>). 151 * </ul> 152 * 153 * @param f floating-point number whose exponent is to be extracted 154 * @return unbiased exponent of the argument. 155 */ ilogb(float f)156 public static int ilogb(float f) { 157 int exponent = Math.getExponent(f); 158 159 switch (exponent) { 160 case Float.MAX_EXPONENT + 1: // NaN or infinity 161 if (Float.isNaN(f)) { 162 return (1 << 30); // 2^30 163 } else // infinite value 164 { 165 return (1 << 28); // 2^28 166 } 167 168 case Float.MIN_EXPONENT - 1: // zero or subnormal 169 if (f == 0.0f) { 170 return -(1 << 28); // -(2^28) 171 } else { 172 int transducer = Float.floatToRawIntBits(f); 173 174 /* 175 * To avoid causing slow arithmetic on subnormals, 176 * the scaling to determine when f's significand 177 * is normalized is done in integer arithmetic. 178 * (there must be at least one "1" bit in the 179 * significand since zero has been screened out. 180 */ 181 182 // isolate significand bits 183 transducer &= FloatConsts.SIGNIF_BIT_MASK; 184 Assert.assertNotEquals(transducer, 0L); 185 186 // This loop is simple and functional. We might be 187 // able to do something more clever that was faster; 188 // e.g. number of leading zero detection on 189 // (transducer << (# exponent and sign bits). 190 while (transducer < 191 (1 << (FloatConsts.SIGNIFICAND_WIDTH - 1))) { 192 transducer *= 2; 193 exponent--; 194 } 195 exponent++; 196 Assert.assertTrue(exponent >= 197 Float.MIN_EXPONENT - (FloatConsts.SIGNIFICAND_WIDTH - 1) && 198 exponent < Float.MIN_EXPONENT); 199 return exponent; 200 } 201 202 default: 203 Assert.assertTrue(exponent >= Float.MIN_EXPONENT && 204 exponent <= Float.MAX_EXPONENT); 205 return exponent; 206 } 207 } 208 209 /** 210 * Returns {@code true} if the unordered relation holds between the two arguments. When two 211 * floating-point values are unordered, one value is neither less than, equal to, nor greater 212 * than the other. For the unordered relation to be true, at least one argument must be a 213 * {@code NaN}. 214 * 215 * @param arg1 the first argument 216 * @param arg2 the second argument 217 * @return {@code true} if at least one argument is a NaN, {@code false} otherwise. 218 */ isUnordered(float arg1, float arg2)219 public static boolean isUnordered(float arg1, float arg2) { 220 return Float.isNaN(arg1) || Float.isNaN(arg2); 221 } 222 223 /** 224 * Returns {@code true} if the unordered relation holds between the two arguments. When two 225 * floating-point values are unordered, one value is neither less than, equal to, nor greater 226 * than the other. For the unordered relation to be true, at least one argument must be a 227 * {@code NaN}. 228 * 229 * @param arg1 the first argument 230 * @param arg2 the second argument 231 * @return {@code true} if at least one argument is a NaN, {@code false} otherwise. 232 */ isUnordered(double arg1, double arg2)233 public static boolean isUnordered(double arg1, double arg2) { 234 return Double.isNaN(arg1) || Double.isNaN(arg2); 235 } 236 test(String testName, float input, boolean result, boolean expected)237 public static void test(String testName, float input, 238 boolean result, boolean expected) { 239 Assert.assertEquals(result, expected, "Failure for " + testName + ":\n" + 240 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 241 "\texpected " + expected + "\n" + 242 "\tgot " + result + ")."); 243 } 244 test(String testName, double input, boolean result, boolean expected)245 public static void test(String testName, double input, 246 boolean result, boolean expected) { 247 Assert.assertEquals(result, expected, "Failure for " + testName + ":\n" + 248 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 249 "\texpected " + expected + "\n" + 250 "\tgot " + result + ")."); 251 } 252 test(String testName, float input1, float input2, boolean result, boolean expected)253 public static void test(String testName, float input1, float input2, 254 boolean result, boolean expected) { 255 Assert.assertEquals(result, expected, "Failure for " + testName + ":\n" + 256 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 257 + input2 + "\t(" + toHexString(input2) + ")\n" + 258 "\texpected " + expected + "\n" + 259 "\tgot " + result + ")."); 260 } 261 test(String testName, double input1, double input2, boolean result, boolean expected)262 public static void test(String testName, double input1, double input2, 263 boolean result, boolean expected) { 264 Assert.assertEquals(result, expected, "Failure for " + testName + ":\n" + 265 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 266 + input2 + "\t(" + toHexString(input2) + ")\n" + 267 "\texpected " + expected + "\n" + 268 "\tgot " + result + ")."); 269 } 270 test(String testName, float input, int result, int expected)271 public static void test(String testName, float input, 272 int result, int expected) { 273 Assert.assertEquals(result, expected, "Failure for " + testName + ":\n" + 274 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 275 "\texpected " + expected + "\n" + 276 "\tgot " + result + ")."); 277 } 278 test(String testName, double input, int result, int expected)279 public static void test(String testName, double input, 280 int result, int expected) { 281 Assert.assertEquals(result, expected, "Failure for " + testName + ":\n" + 282 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 283 "\texpected " + expected + "\n" + 284 "\tgot " + result + ")."); 285 } 286 test(String testName, float input, float result, float expected)287 public static void test(String testName, float input, 288 float result, float expected) { 289 Assert.assertEquals(result, expected, "Failure for " + testName + ":\n" + 290 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 291 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 292 "\tgot " + result + "\t(" + toHexString(result) + ")."); 293 } 294 295 test(String testName, double input, double result, double expected)296 public static void test(String testName, double input, 297 double result, double expected) { 298 Assert.assertEquals(Double.compare(expected, result), 0, "Failure for " + testName + ":\n" + 299 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 300 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 301 "\tgot " + result + "\t(" + toHexString(result) + ")."); 302 } 303 test(String testName, float input1, double input2, float result, float expected)304 public static void test(String testName, 305 float input1, double input2, 306 float result, float expected) { 307 Assert.assertEquals(Float.compare(expected, result), 0, "Failure for " + testName + ":\n" + 308 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 309 + input2 + "\t(" + toHexString(input2) + ")\n" + 310 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 311 "\tgot " + result + "\t(" + toHexString(result) + ")."); 312 } 313 test(String testName, double input1, double input2, double result, double expected)314 public static void test(String testName, 315 double input1, double input2, 316 double result, double expected) { 317 Assert.assertEquals(Double.compare(expected, result), 0, "Failure for " + testName + ":\n" + 318 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 319 + input2 + "\t(" + toHexString(input2) + ")\n" + 320 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 321 "\tgot " + result + "\t(" + toHexString(result) + ")."); 322 } 323 test(String testName, float input1, int input2, float result, float expected)324 public static void test(String testName, 325 float input1, int input2, 326 float result, float expected) { 327 Assert.assertEquals(Float.compare(expected, result), 0, "Failure for " + testName + ":\n" + 328 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 329 + input2 + "\n" + 330 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 331 "\tgot " + result + "\t(" + toHexString(result) + ")."); 332 } 333 test(String testName, double input1, int input2, double result, double expected)334 public static void test(String testName, 335 double input1, int input2, 336 double result, double expected) { 337 Assert.assertEquals(Double.compare(expected, result), 0, "Failure for " + testName + ":\n" + 338 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 339 + input2 + "\n" + 340 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 341 "\tgot " + result + "\t(" + toHexString(result) + ")."); 342 } 343 test(String testName, float input1, float input2, float input3, float result, float expected)344 public static void test(String testName, 345 float input1, float input2, float input3, 346 float result, float expected) { 347 Assert.assertEquals(Float.compare(expected, result), 0, "Failure for " + testName + ":\n" + 348 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 349 + input2 + "\t(" + toHexString(input2) + ") and" 350 + input3 + "\t(" + toHexString(input3) + ")\n" + 351 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 352 "\tgot " + result + "\t(" + toHexString(result) + ")."); 353 } 354 test(String testName, double input1, double input2, double input3, double result, double expected)355 public static void test(String testName, 356 double input1, double input2, double input3, 357 double result, double expected) { 358 Assert.assertEquals(Double.compare(expected, result), 0, "Failure for " + testName + ":\n" + 359 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 360 + input2 + "\t(" + toHexString(input2) + ") and" 361 + input3 + "\t(" + toHexString(input3) + ")\n" + 362 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 363 "\tgot " + result + "\t(" + toHexString(result) + ")."); 364 } 365 testUlpCore(double result, double expected, double ulps)366 static int testUlpCore(double result, double expected, double ulps) { 367 // We assume we won't be unlucky and have an inexact expected 368 // be nextDown(2^i) when 2^i would be the correctly rounded 369 // answer. This would cause the ulp size to be half as large 370 // as it should be, doubling the measured error). 371 372 if (Double.compare(expected, result) == 0) { 373 return 0; // result and expected are equivalent 374 } else { 375 if (ulps == 0.0) { 376 // Equivalent results required but not found 377 return 1; 378 } else { 379 double difference = expected - result; 380 if (isUnordered(expected, result) || 381 Double.isNaN(difference) || 382 // fail if greater than or unordered 383 !(Math.abs(difference / Math.ulp(expected)) <= Math.abs(ulps))) { 384 return 1; 385 } else { 386 return 0; 387 } 388 } 389 } 390 } 391 392 // One input argument. testUlpDiff(String testName, double input, double result, double expected, double ulps)393 public static void testUlpDiff(String testName, double input, 394 double result, double expected, double ulps) { 395 int code = testUlpCore(result, expected, ulps); 396 Assert.assertEquals(code, 0, "Failure for " + testName + ":\n" + 397 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 398 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 399 "\tgot " + result + "\t(" + toHexString(result) + ");\n" + 400 "\tdifference greater than ulp tolerance " + ulps); 401 } 402 403 // Two input arguments. testUlpDiff(String testName, double input1, double input2, double result, double expected, double ulps)404 public static void testUlpDiff(String testName, double input1, double input2, 405 double result, double expected, double ulps) { 406 int code = testUlpCore(result, expected, ulps); 407 Assert.assertEquals(code, 0, "Failure for " + testName + ":\n" + 408 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 409 + input2 + "\t(" + toHexString(input2) + ")\n" + 410 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 411 "\tgot " + result + "\t(" + toHexString(result) + ");\n" + 412 "\tdifference greater than ulp tolerance " + ulps); 413 } 414 415 // For a successful test, the result must be within the ulp bound of 416 // expected AND the result must have absolute value less than or 417 // equal to absBound. testUlpDiffWithAbsBound(String testName, double input, double result, double expected, double ulps, double absBound)418 public static void testUlpDiffWithAbsBound(String testName, double input, 419 double result, double expected, 420 double ulps, double absBound) { 421 int code = 0; // return code value 422 423 if (!(StrictMath.abs(result) <= StrictMath.abs(absBound)) && 424 !Double.isNaN(expected)) { 425 code = 1; 426 } else { 427 code = testUlpCore(result, expected, ulps); 428 } 429 430 Assert.assertEquals(code, 0, "Failure for " + testName + ":\n" + 431 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 432 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 433 "\tgot " + result + "\t(" + toHexString(result) + ");\n" + 434 "\tdifference greater than ulp tolerance " + ulps + 435 " or the result has larger magnitude than " + absBound); 436 } 437 438 // For a successful test, the result must be within the ulp bound of 439 // expected AND the result must have absolute value greater than 440 // or equal to the lowerBound. testUlpDiffWithLowerBound(String testName, double input, double result, double expected, double ulps, double lowerBound)441 public static void testUlpDiffWithLowerBound(String testName, double input, 442 double result, double expected, 443 double ulps, double lowerBound) { 444 int code = 0; // return code value 445 446 if (!(result >= lowerBound) && !Double.isNaN(expected)) { 447 code = 1; 448 } else { 449 code = testUlpCore(result, expected, ulps); 450 } 451 452 Assert.assertEquals(code, 0, "Failure for " + testName + 453 ":\n" + 454 "\tFor input " + input + "\t(" + toHexString(input) + ")" + 455 "\n\texpected " + expected + "\t(" + toHexString(expected) + ")" + 456 "\n\tgot " + result + "\t(" + toHexString(result) + ");" + 457 "\ndifference greater than ulp tolerance " + ulps + 458 " or result not greater than or equal to the bound " + lowerBound); 459 } 460 testTolerance(String testName, double input, double result, double expected, double tolerance)461 public static void testTolerance(String testName, double input, 462 double result, double expected, double tolerance) { 463 if (Double.compare(expected, result) != 0) { 464 double difference = expected - result; 465 Assert.assertFalse(isUnordered(expected, result) || 466 Double.isNaN(difference) || 467 // fail if greater than or unordered 468 !(Math.abs((difference) / expected) <= StrictMath.pow(10, -tolerance)), 469 "Failure for " + testName + ":\n" + 470 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 471 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 472 "\tgot " + result + "\t(" + toHexString(result) + ");\n" + 473 "\tdifference greater than tolerance 10^-" + tolerance); 474 } 475 } 476 477 // For a successful test, the result must be within the upper and 478 // lower bounds. testBounds(String testName, double input, double result, double bound1, double bound2)479 public static void testBounds(String testName, double input, double result, 480 double bound1, double bound2) { 481 if (!((result >= bound1 && result <= bound2) || (result <= bound1 && result >= bound2))) { 482 double lowerBound = Math.min(bound1, bound2); 483 double upperBound = Math.max(bound1, bound2); 484 Assert.fail("Failure for " + testName + ":\n" + 485 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 486 "\tgot " + result + "\t(" + toHexString(result) + ");\n" + 487 "\toutside of range\n" + 488 "\t[" + lowerBound + "\t(" + toHexString(lowerBound) + "), " + 489 upperBound + "\t(" + toHexString(upperBound) + ")]"); 490 } 491 } 492 } 493