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 33 public class Tests { Tests()34 private Tests(){}; // do not instantiate 35 toHexString(float f)36 public static String toHexString(float f) { 37 if (!Float.isNaN(f)) 38 return Float.toHexString(f); 39 else 40 return "NaN(0x" + Integer.toHexString(Float.floatToRawIntBits(f)) + ")"; 41 } 42 toHexString(double d)43 public static String toHexString(double d) { 44 if (!Double.isNaN(d)) 45 return Double.toHexString(d); 46 else 47 return "NaN(0x" + Long.toHexString(Double.doubleToRawLongBits(d)) + ")"; 48 } 49 50 /** 51 * Return the floating-point value next larger in magnitude. 52 */ nextOut(double d)53 public static double nextOut(double d) { 54 if (d > 0.0) 55 return Math.nextUp(d); 56 else 57 return -Math.nextUp(-d); 58 } 59 60 /** 61 * Returns unbiased exponent of a {@code float}; for 62 * subnormal values, the number is treated as if it were 63 * normalized. That is for all finite, non-zero, positive numbers 64 * <i>x</i>, <code>scalb(<i>x</i>, -ilogb(<i>x</i>))</code> is 65 * always in the range [1, 2). 66 * <p> 67 * Special cases: 68 * <ul> 69 * <li> If the argument is NaN, then the result is 2<sup>30</sup>. 70 * <li> If the argument is infinite, then the result is 2<sup>28</sup>. 71 * <li> If the argument is zero, then the result is -(2<sup>28</sup>). 72 * </ul> 73 * 74 * @param f floating-point number whose exponent is to be extracted 75 * @return unbiased exponent of the argument. 76 */ ilogb(double d)77 public static int ilogb(double d) { 78 int exponent = Math.getExponent(d); 79 80 switch (exponent) { 81 case Double.MAX_EXPONENT+1: // NaN or infinity 82 if( Double.isNaN(d) ) 83 return (1<<30); // 2^30 84 else // infinite value 85 return (1<<28); // 2^28 86 87 case Double.MIN_EXPONENT-1: // zero or subnormal 88 if(d == 0.0) { 89 return -(1<<28); // -(2^28) 90 } 91 else { 92 long transducer = Double.doubleToRawLongBits(d); 93 94 /* 95 * To avoid causing slow arithmetic on subnormals, 96 * the scaling to determine when d's significand 97 * is normalized is done in integer arithmetic. 98 * (there must be at least one "1" bit in the 99 * significand since zero has been screened out. 100 */ 101 102 // isolate significand bits 103 transducer &= DoubleConsts.SIGNIF_BIT_MASK; 104 assert(transducer != 0L); 105 106 // This loop is simple and functional. We might be 107 // able to do something more clever that was faster; 108 // e.g. number of leading zero detection on 109 // (transducer << (# exponent and sign bits). 110 while (transducer < 111 (1L << (DoubleConsts.SIGNIFICAND_WIDTH - 1))) { 112 transducer *= 2; 113 exponent--; 114 } 115 exponent++; 116 assert( exponent >= 117 Double.MIN_EXPONENT - (DoubleConsts.SIGNIFICAND_WIDTH-1) && 118 exponent < Double.MIN_EXPONENT); 119 return exponent; 120 } 121 122 default: 123 assert( exponent >= Double.MIN_EXPONENT && 124 exponent <= Double.MAX_EXPONENT); 125 return exponent; 126 } 127 } 128 129 /** 130 * Returns unbiased exponent of a {@code float}; for 131 * subnormal values, the number is treated as if it were 132 * normalized. That is for all finite, non-zero, positive numbers 133 * <i>x</i>, <code>scalb(<i>x</i>, -ilogb(<i>x</i>))</code> is 134 * always in the range [1, 2). 135 * <p> 136 * Special cases: 137 * <ul> 138 * <li> If the argument is NaN, then the result is 2<sup>30</sup>. 139 * <li> If the argument is infinite, then the result is 2<sup>28</sup>. 140 * <li> If the argument is zero, then the result is -(2<sup>28</sup>). 141 * </ul> 142 * 143 * @param f floating-point number whose exponent is to be extracted 144 * @return unbiased exponent of the argument. 145 */ ilogb(float f)146 public static int ilogb(float f) { 147 int exponent = Math.getExponent(f); 148 149 switch (exponent) { 150 case Float.MAX_EXPONENT+1: // NaN or infinity 151 if( Float.isNaN(f) ) 152 return (1<<30); // 2^30 153 else // infinite value 154 return (1<<28); // 2^28 155 156 case Float.MIN_EXPONENT-1: // zero or subnormal 157 if(f == 0.0f) { 158 return -(1<<28); // -(2^28) 159 } 160 else { 161 int transducer = Float.floatToRawIntBits(f); 162 163 /* 164 * To avoid causing slow arithmetic on subnormals, 165 * the scaling to determine when f's significand 166 * is normalized is done in integer arithmetic. 167 * (there must be at least one "1" bit in the 168 * significand since zero has been screened out. 169 */ 170 171 // isolate significand bits 172 transducer &= FloatConsts.SIGNIF_BIT_MASK; 173 assert(transducer != 0); 174 175 // This loop is simple and functional. We might be 176 // able to do something more clever that was faster; 177 // e.g. number of leading zero detection on 178 // (transducer << (# exponent and sign bits). 179 while (transducer < 180 (1 << (FloatConsts.SIGNIFICAND_WIDTH - 1))) { 181 transducer *= 2; 182 exponent--; 183 } 184 exponent++; 185 assert( exponent >= 186 Float.MIN_EXPONENT - (FloatConsts.SIGNIFICAND_WIDTH-1) && 187 exponent < Float.MIN_EXPONENT); 188 return exponent; 189 } 190 191 default: 192 assert( exponent >= Float.MIN_EXPONENT && 193 exponent <= Float.MAX_EXPONENT); 194 return exponent; 195 } 196 } 197 198 /** 199 * Returns {@code true} if the unordered relation holds 200 * between the two arguments. When two floating-point values are 201 * unordered, one value is neither less than, equal to, nor 202 * greater than the other. For the unordered relation to be true, 203 * at least one argument must be a {@code NaN}. 204 * 205 * @param arg1 the first argument 206 * @param arg2 the second argument 207 * @return {@code true} if at least one argument is a NaN, 208 * {@code false} otherwise. 209 */ isUnordered(float arg1, float arg2)210 public static boolean isUnordered(float arg1, float arg2) { 211 return Float.isNaN(arg1) || Float.isNaN(arg2); 212 } 213 214 /** 215 * Returns {@code true} if the unordered relation holds 216 * between the two arguments. When two floating-point values are 217 * unordered, one value is neither less than, equal to, nor 218 * greater than the other. For the unordered relation to be true, 219 * at least one argument must be a {@code NaN}. 220 * 221 * @param arg1 the first argument 222 * @param arg2 the second argument 223 * @return {@code true} if at least one argument is a NaN, 224 * {@code false} otherwise. 225 */ isUnordered(double arg1, double arg2)226 public static boolean isUnordered(double arg1, double arg2) { 227 return Double.isNaN(arg1) || Double.isNaN(arg2); 228 } 229 test(String testName, float input, boolean result, boolean expected)230 public static int test(String testName, float input, 231 boolean result, boolean expected) { 232 if (expected != result) { 233 System.err.println("Failure for " + testName + ":\n" + 234 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 235 "\texpected " + expected + "\n" + 236 "\tgot " + result + ")."); 237 return 1; 238 } 239 else 240 return 0; 241 } 242 test(String testName, double input, boolean result, boolean expected)243 public static int test(String testName, double input, 244 boolean result, boolean expected) { 245 if (expected != result) { 246 System.err.println("Failure for " + testName + ":\n" + 247 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 248 "\texpected " + expected + "\n" + 249 "\tgot " + result + ")."); 250 return 1; 251 } 252 else 253 return 0; 254 } 255 test(String testName, float input1, float input2, boolean result, boolean expected)256 public static int test(String testName, float input1, float input2, 257 boolean result, boolean expected) { 258 if (expected != result) { 259 System.err.println("Failure for " + testName + ":\n" + 260 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 261 + input2 + "\t(" + toHexString(input2) + ")\n" + 262 "\texpected " + expected + "\n" + 263 "\tgot " + result + ")."); 264 return 1; 265 } 266 return 0; 267 } 268 test(String testName, double input1, double input2, boolean result, boolean expected)269 public static int test(String testName, double input1, double input2, 270 boolean result, boolean expected) { 271 if (expected != result) { 272 System.err.println("Failure for " + testName + ":\n" + 273 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 274 + input2 + "\t(" + toHexString(input2) + ")\n" + 275 "\texpected " + expected + "\n" + 276 "\tgot " + result + ")."); 277 return 1; 278 } 279 return 0; 280 } 281 test(String testName, float input, int result, int expected)282 public static int test(String testName, float input, 283 int result, int expected) { 284 if (expected != result) { 285 System.err.println("Failure for " + testName + ":\n" + 286 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 287 "\texpected " + expected + "\n" + 288 "\tgot " + result + ")."); 289 return 1; 290 } 291 return 0; 292 } 293 test(String testName, double input, int result, int expected)294 public static int test(String testName, double input, 295 int result, int expected) { 296 if (expected != result) { 297 System.err.println("Failure for " + testName + ":\n" + 298 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 299 "\texpected " + expected + "\n" + 300 "\tgot " + result + ")."); 301 return 1; 302 } 303 else 304 return 0; 305 } 306 test(String testName, float input, float result, float expected)307 public static int test(String testName, float input, 308 float result, float expected) { 309 if (Float.compare(expected, result) != 0 ) { 310 System.err.println("Failure for " + testName + ":\n" + 311 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 312 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 313 "\tgot " + result + "\t(" + toHexString(result) + ")."); 314 return 1; 315 } 316 else 317 return 0; 318 } 319 320 test(String testName, double input, double result, double expected)321 public static int test(String testName, double input, 322 double result, double expected) { 323 if (Double.compare(expected, result ) != 0) { 324 System.err.println("Failure for " + testName + ":\n" + 325 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 326 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 327 "\tgot " + result + "\t(" + toHexString(result) + ")."); 328 return 1; 329 } 330 else 331 return 0; 332 } 333 test(String testName, float input1, double input2, float result, float expected)334 public static int test(String testName, 335 float input1, double input2, 336 float result, float expected) { 337 if (Float.compare(expected, result ) != 0) { 338 System.err.println("Failure for " + testName + ":\n" + 339 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 340 + input2 + "\t(" + toHexString(input2) + ")\n" + 341 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 342 "\tgot " + result + "\t(" + toHexString(result) + ")."); 343 return 1; 344 } 345 else 346 return 0; 347 } 348 test(String testName, double input1, double input2, double result, double expected)349 public static int test(String testName, 350 double input1, double input2, 351 double result, double expected) { 352 if (Double.compare(expected, result ) != 0) { 353 System.err.println("Failure for " + testName + ":\n" + 354 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 355 + input2 + "\t(" + toHexString(input2) + ")\n" + 356 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 357 "\tgot " + result + "\t(" + toHexString(result) + ")."); 358 return 1; 359 } 360 else 361 return 0; 362 } 363 test(String testName, float input1, int input2, float result, float expected)364 public static int test(String testName, 365 float input1, int input2, 366 float result, float expected) { 367 if (Float.compare(expected, result ) != 0) { 368 System.err.println("Failure for " + testName + ":\n" + 369 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 370 + input2 + "\n" + 371 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 372 "\tgot " + result + "\t(" + toHexString(result) + ")."); 373 return 1; 374 } 375 else 376 return 0; 377 } 378 test(String testName, double input1, int input2, double result, double expected)379 public static int test(String testName, 380 double input1, int input2, 381 double result, double expected) { 382 if (Double.compare(expected, result ) != 0) { 383 System.err.println("Failure for " + testName + ":\n" + 384 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 385 + input2 + "\n" + 386 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 387 "\tgot " + result + "\t(" + toHexString(result) + ")."); 388 return 1; 389 } 390 else 391 return 0; 392 } 393 test(String testName, float input1, float input2, float input3, float result, float expected)394 public static int test(String testName, 395 float input1, float input2, float input3, 396 float result, float expected) { 397 if (Float.compare(expected, result ) != 0) { 398 System.err.println("Failure for " + testName + ":\n" + 399 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 400 + input2 + "\t(" + toHexString(input2) + ") and" 401 + input3 + "\t(" + toHexString(input3) + ")\n" + 402 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 403 "\tgot " + result + "\t(" + toHexString(result) + ")."); 404 return 1; 405 } 406 else 407 return 0; 408 } 409 test(String testName, double input1, double input2, double input3, double result, double expected)410 public static int test(String testName, 411 double input1, double input2, double input3, 412 double result, double expected) { 413 if (Double.compare(expected, result ) != 0) { 414 System.err.println("Failure for " + testName + ":\n" + 415 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 416 + input2 + "\t(" + toHexString(input2) + ") and" 417 + input3 + "\t(" + toHexString(input3) + ")\n" + 418 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 419 "\tgot " + result + "\t(" + toHexString(result) + ")."); 420 return 1; 421 } 422 else 423 return 0; 424 } 425 testUlpCore(double result, double expected, double ulps)426 static int testUlpCore(double result, double expected, double ulps) { 427 // We assume we won't be unlucky and have an inexact expected 428 // be nextDown(2^i) when 2^i would be the correctly rounded 429 // answer. This would cause the ulp size to be half as large 430 // as it should be, doubling the measured error). 431 432 if (Double.compare(expected, result) == 0) { 433 return 0; // result and expected are equivalent 434 } else { 435 if( ulps == 0.0) { 436 // Equivalent results required but not found 437 return 1; 438 } else { 439 double difference = expected - result; 440 if (isUnordered(expected, result) || 441 Double.isNaN(difference) || 442 // fail if greater than or unordered 443 !(Math.abs( difference/Math.ulp(expected) ) <= Math.abs(ulps)) ) { 444 return 1; 445 } 446 else 447 return 0; 448 } 449 } 450 } 451 452 // One input argument. testUlpDiff(String testName, double input, double result, double expected, double ulps)453 public static int testUlpDiff(String testName, double input, 454 double result, double expected, double ulps) { 455 int code = testUlpCore(result, expected, ulps); 456 if (code == 1) { 457 System.err.println("Failure for " + testName + ":\n" + 458 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 459 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 460 "\tgot " + result + "\t(" + toHexString(result) + ");\n" + 461 "\tdifference greater than ulp tolerance " + ulps); 462 } 463 return code; 464 } 465 466 // Two input arguments. testUlpDiff(String testName, double input1, double input2, double result, double expected, double ulps)467 public static int testUlpDiff(String testName, double input1, double input2, 468 double result, double expected, double ulps) { 469 int code = testUlpCore(result, expected, ulps); 470 if (code == 1) { 471 System.err.println("Failure for " + testName + ":\n" + 472 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 473 + input2 + "\t(" + toHexString(input2) + ")\n" + 474 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 475 "\tgot " + result + "\t(" + toHexString(result) + ");\n" + 476 "\tdifference greater than ulp tolerance " + ulps); 477 } 478 return code; 479 } 480 481 // For a successful test, the result must be within the ulp bound of 482 // expected AND the result must have absolute value less than or 483 // equal to absBound. testUlpDiffWithAbsBound(String testName, double input, double result, double expected, double ulps, double absBound)484 public static int testUlpDiffWithAbsBound(String testName, double input, 485 double result, double expected, 486 double ulps, double absBound) { 487 int code = 0; // return code value 488 489 if (!(StrictMath.abs(result) <= StrictMath.abs(absBound)) && 490 !Double.isNaN(expected)) { 491 code = 1; 492 } else 493 code = testUlpCore(result, expected, ulps); 494 495 if (code == 1) { 496 System.err.println("Failure for " + testName + ":\n" + 497 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 498 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 499 "\tgot " + result + "\t(" + toHexString(result) + ");\n" + 500 "\tdifference greater than ulp tolerance " + ulps + 501 " or the result has larger magnitude than " + absBound); 502 } 503 return code; 504 } 505 506 // For a successful test, the result must be within the ulp bound of 507 // expected AND the result must have absolute value greater than 508 // or equal to the lowerBound. testUlpDiffWithLowerBound(String testName, double input, double result, double expected, double ulps, double lowerBound)509 public static int testUlpDiffWithLowerBound(String testName, double input, 510 double result, double expected, 511 double ulps, double lowerBound) { 512 int code = 0; // return code value 513 514 if (!(result >= lowerBound) && !Double.isNaN(expected)) { 515 code = 1; 516 } else 517 code = testUlpCore(result, expected, ulps); 518 519 if (code == 1) { 520 System.err.println("Failure for " + testName + 521 ":\n" + 522 "\tFor input " + input + "\t(" + toHexString(input) + ")" + 523 "\n\texpected " + expected + "\t(" + toHexString(expected) + ")" + 524 "\n\tgot " + result + "\t(" + toHexString(result) + ");" + 525 "\ndifference greater than ulp tolerance " + ulps + 526 " or result not greater than or equal to the bound " + lowerBound); 527 } 528 return code; 529 } 530 testTolerance(String testName, double input, double result, double expected, double tolerance)531 public static int testTolerance(String testName, double input, 532 double result, double expected, double tolerance) { 533 if (Double.compare(expected, result ) != 0) { 534 double difference = expected - result; 535 if (isUnordered(expected, result) || 536 Double.isNaN(difference) || 537 // fail if greater than or unordered 538 !(Math.abs((difference)/expected) <= StrictMath.pow(10, -tolerance)) ) { 539 System.err.println("Failure for " + testName + ":\n" + 540 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 541 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 542 "\tgot " + result + "\t(" + toHexString(result) + ");\n" + 543 "\tdifference greater than tolerance 10^-" + tolerance); 544 return 1; 545 } 546 return 0; 547 } 548 else 549 return 0; 550 } 551 552 // For a successful test, the result must be within the upper and 553 // lower bounds. testBounds(String testName, double input, double result, double bound1, double bound2)554 public static int testBounds(String testName, double input, double result, 555 double bound1, double bound2) { 556 if ((result >= bound1 && result <= bound2) || 557 (result <= bound1 && result >= bound2)) 558 return 0; 559 else { 560 double lowerBound = Math.min(bound1, bound2); 561 double upperBound = Math.max(bound1, bound2); 562 System.err.println("Failure for " + testName + ":\n" + 563 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 564 "\tgot " + result + "\t(" + toHexString(result) + ");\n" + 565 "\toutside of range\n" + 566 "\t[" + lowerBound + "\t(" + toHexString(lowerBound) + "), " + 567 upperBound + "\t(" + toHexString(upperBound) + ")]"); 568 return 1; 569 } 570 } 571 } 572