1 /* 2 * Copyright (c) 2003, 2012, 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 &= DoubleUtils.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 << (DoubleUtils.SIGNIFICAND_WIDTH - 1))) { 112 transducer *= 2; 113 exponent--; 114 } 115 exponent++; 116 assert( exponent >= 117 Double.MIN_EXPONENT - (DoubleUtils.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 &= FloatUtils.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 << (FloatUtils.SIGNIFICAND_WIDTH - 1))) { 181 transducer *= 2; 182 exponent--; 183 } 184 exponent++; 185 assert( exponent >= 186 Float.MIN_EXPONENT - (FloatUtils.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 static int testUlpCore(double result, double expected, double ulps) { 395 // We assume we won't be unlucky and have an inexact expected 396 // be nextDown(2^i) when 2^i would be the correctly rounded 397 // answer. This would cause the ulp size to be half as large 398 // as it should be, doubling the measured error). 399 400 if (Double.compare(expected, result) == 0) { 401 return 0; // result and expected are equivalent 402 } else { 403 if( ulps == 0.0) { 404 // Equivalent results required but not found 405 return 1; 406 } else { 407 double difference = expected - result; 408 if (isUnordered(expected, result) || 409 Double.isNaN(difference) || 410 // fail if greater than or unordered 411 !(Math.abs( difference/Math.ulp(expected) ) <= Math.abs(ulps)) ) { 412 return 1; 413 } 414 else 415 return 0; 416 } 417 } 418 } 419 420 // One input argument. 421 public static int testUlpDiff(String testName, double input, 422 double result, double expected, double ulps) { 423 int code = testUlpCore(result, expected, ulps); 424 if (code == 1) { 425 System.err.println("Failure for " + testName + ":\n" + 426 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 427 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 428 "\tgot " + result + "\t(" + toHexString(result) + ");\n" + 429 "\tdifference greater than ulp tolerance " + ulps); 430 } 431 return code; 432 } 433 434 // Two input arguments. 435 public static int testUlpDiff(String testName, double input1, double input2, 436 double result, double expected, double ulps) { 437 int code = testUlpCore(result, expected, ulps); 438 if (code == 1) { 439 System.err.println("Failure for " + testName + ":\n" + 440 "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 441 + input2 + "\t(" + toHexString(input2) + ")\n" + 442 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 443 "\tgot " + result + "\t(" + toHexString(result) + ");\n" + 444 "\tdifference greater than ulp tolerance " + ulps); 445 } 446 return code; 447 } 448 449 // For a successful test, the result must be within the ulp bound of 450 // expected AND the result must have absolute value less than or 451 // equal to absBound. 452 public static int testUlpDiffWithAbsBound(String testName, double input, 453 double result, double expected, 454 double ulps, double absBound) { 455 int code = 0; // return code value 456 457 if (!(StrictMath.abs(result) <= StrictMath.abs(absBound)) && 458 !Double.isNaN(expected)) { 459 code = 1; 460 } else 461 code = testUlpCore(result, expected, ulps); 462 463 if (code == 1) { 464 System.err.println("Failure for " + testName + ":\n" + 465 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 466 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 467 "\tgot " + result + "\t(" + toHexString(result) + ");\n" + 468 "\tdifference greater than ulp tolerance " + ulps + 469 " or the result has larger magnitude than " + absBound); 470 } 471 return code; 472 } 473 474 // For a successful test, the result must be within the ulp bound of 475 // expected AND the result must have absolute value greater than 476 // or equal to the lowerBound. 477 public static int testUlpDiffWithLowerBound(String testName, double input, 478 double result, double expected, 479 double ulps, double lowerBound) { 480 int code = 0; // return code value 481 482 if (!(result >= lowerBound) && !Double.isNaN(expected)) { 483 code = 1; 484 } else 485 code = testUlpCore(result, expected, ulps); 486 487 if (code == 1) { 488 System.err.println("Failure for " + testName + 489 ":\n" + 490 "\tFor input " + input + "\t(" + toHexString(input) + ")" + 491 "\n\texpected " + expected + "\t(" + toHexString(expected) + ")" + 492 "\n\tgot " + result + "\t(" + toHexString(result) + ");" + 493 "\ndifference greater than ulp tolerance " + ulps + 494 " or result not greater than or equal to the bound " + lowerBound); 495 } 496 return code; 497 } 498 499 public static int testTolerance(String testName, double input, 500 double result, double expected, double tolerance) { 501 if (Double.compare(expected, result ) != 0) { 502 double difference = expected - result; 503 if (isUnordered(expected, result) || 504 Double.isNaN(difference) || 505 // fail if greater than or unordered 506 !(Math.abs((difference)/expected) <= StrictMath.pow(10, -tolerance)) ) { 507 System.err.println("Failure for " + testName + ":\n" + 508 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 509 "\texpected " + expected + "\t(" + toHexString(expected) + ")\n" + 510 "\tgot " + result + "\t(" + toHexString(result) + ");\n" + 511 "\tdifference greater than tolerance 10^-" + tolerance); 512 return 1; 513 } 514 return 0; 515 } 516 else 517 return 0; 518 } 519 520 // For a successful test, the result must be within the upper and 521 // lower bounds. 522 public static int testBounds(String testName, double input, double result, 523 double bound1, double bound2) { 524 if ((result >= bound1 && result <= bound2) || 525 (result <= bound1 && result >= bound2)) 526 return 0; 527 else { 528 double lowerBound = Math.min(bound1, bound2); 529 double upperBound = Math.max(bound1, bound2); 530 System.err.println("Failure for " + testName + ":\n" + 531 "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 532 "\tgot " + result + "\t(" + toHexString(result) + ");\n" + 533 "\toutside of range\n" + 534 "\t[" + lowerBound + "\t(" + toHexString(lowerBound) + "), " + 535 upperBound + "\t(" + toHexString(upperBound) + ")]"); 536 return 1; 537 } 538 } 539 }