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 { 34 private Tests(){}; // do not instantiate 35 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 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 */ 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 */ 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 */ 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 */ 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 */ 226 public static boolean isUnordered(double arg1, double arg2) { 227 return Double.isNaN(arg1) || Double.isNaN(arg2); 228 } 229 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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. 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. 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. 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. 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 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. 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 }