Tests.java revision 10532:74078474d9bd
1127668Sbms/* 2127668Sbms * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. 3127668Sbms * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4127668Sbms * 5127668Sbms * This code is free software; you can redistribute it and/or modify it 6127668Sbms * under the terms of the GNU General Public License version 2 only, as 7127668Sbms * published by the Free Software Foundation. 8127668Sbms * 9127668Sbms * This code is distributed in the hope that it will be useful, but WITHOUT 10127668Sbms * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11127668Sbms * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12127668Sbms * version 2 for more details (a copy is included in the LICENSE file that 13127668Sbms * accompanied this code). 14127668Sbms * 15127668Sbms * You should have received a copy of the GNU General Public License version 16127668Sbms * 2 along with this work; if not, write to the Free Software Foundation, 17127668Sbms * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18147899Ssam * 19127668Sbms * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20127668Sbms * or visit www.oracle.com if you need additional information or have any 21127668Sbms * questions. 22127668Sbms */ 23127668Sbms 24127668Sbms/* 25127668Sbms * Shared static test methods for numerical tests. Sharing these 26127668Sbms * helper test methods avoids repeated functions in the various test 27127668Sbms * programs. The test methods return 1 for a test failure and 0 for 28127668Sbms * success. The order of arguments to the test methods is generally 29127668Sbms * the test name, followed by the test arguments, the computed result, 30127668Sbms * and finally the expected result. 31127668Sbms */ 32127668Sbms 33127668Sbmspublic class Tests { 34127668Sbms private Tests(){}; // do not instantiate 35127668Sbms 36127668Sbms public static String toHexString(float f) { 37147899Ssam if (!Float.isNaN(f)) 38127668Sbms return Float.toHexString(f); 39127668Sbms else 40127668Sbms return "NaN(0x" + Integer.toHexString(Float.floatToRawIntBits(f)) + ")"; 41127668Sbms } 42127668Sbms 43127668Sbms public static String toHexString(double d) { 44127668Sbms if (!Double.isNaN(d)) 45127668Sbms return Double.toHexString(d); 46127668Sbms else 47127668Sbms return "NaN(0x" + Long.toHexString(Double.doubleToRawLongBits(d)) + ")"; 48127668Sbms } 49127668Sbms 50127668Sbms /** 51127668Sbms * Return the floating-point value next larger in magnitude. 52127668Sbms */ 53127668Sbms public static double nextOut(double d) { 54127668Sbms if (d > 0.0) 55127668Sbms return Math.nextUp(d); 56147899Ssam else 57147899Ssam return -Math.nextUp(-d); 58147899Ssam } 59147899Ssam 60147899Ssam /** 61147899Ssam * Returns unbiased exponent of a {@code float}; for 62147899Ssam * subnormal values, the number is treated as if it were 63147899Ssam * normalized. That is for all finite, non-zero, positive numbers 64147899Ssam * <i>x</i>, <code>scalb(<i>x</i>, -ilogb(<i>x</i>))</code> is 65147899Ssam * always in the range [1, 2). 66147899Ssam * <p> 67147899Ssam * Special cases: 68147899Ssam * <ul> 69147899Ssam * <li> If the argument is NaN, then the result is 2<sup>30</sup>. 70147899Ssam * <li> If the argument is infinite, then the result is 2<sup>28</sup>. 71147899Ssam * <li> If the argument is zero, then the result is -(2<sup>28</sup>). 72147899Ssam * </ul> 73147899Ssam * 74147899Ssam * @param f floating-point number whose exponent is to be extracted 75147899Ssam * @return unbiased exponent of the argument. 76127668Sbms */ 77127668Sbms public static int ilogb(double d) { 78127668Sbms int exponent = Math.getExponent(d); 79127668Sbms 80127668Sbms switch (exponent) { 81127668Sbms case Double.MAX_EXPONENT+1: // NaN or infinity 82127668Sbms if( Double.isNaN(d) ) 83127668Sbms return (1<<30); // 2^30 84127668Sbms else // infinite value 85127668Sbms return (1<<28); // 2^28 86127668Sbms 87127668Sbms case Double.MIN_EXPONENT-1: // zero or subnormal 88147899Ssam if(d == 0.0) { 89147899Ssam return -(1<<28); // -(2^28) 90147899Ssam } 91147899Ssam else { 92147899Ssam long transducer = Double.doubleToRawLongBits(d); 93147899Ssam 94147899Ssam /* 95147899Ssam * To avoid causing slow arithmetic on subnormals, 96147899Ssam * the scaling to determine when d's significand 97147899Ssam * is normalized is done in integer arithmetic. 98147899Ssam * (there must be at least one "1" bit in the 99147899Ssam * significand since zero has been screened out. 100147899Ssam */ 101147899Ssam 102147899Ssam // isolate significand bits 103147899Ssam transducer &= DoubleConsts.SIGNIF_BIT_MASK; 104147899Ssam assert(transducer != 0L); 105147899Ssam 106147899Ssam // This loop is simple and functional. We might be 107147899Ssam // able to do something more clever that was faster; 108147899Ssam // e.g. number of leading zero detection on 109147899Ssam // (transducer << (# exponent and sign bits). 110147899Ssam while (transducer < 111147899Ssam (1L << (DoubleConsts.SIGNIFICAND_WIDTH - 1))) { 112147899Ssam transducer *= 2; 113147899Ssam exponent--; 114127668Sbms } 115127668Sbms exponent++; 116127668Sbms assert( exponent >= 117127668Sbms Double.MIN_EXPONENT - (DoubleConsts.SIGNIFICAND_WIDTH-1) && 118127668Sbms exponent < Double.MIN_EXPONENT); 119127668Sbms return exponent; 120127668Sbms } 121127668Sbms 122127668Sbms default: 123127668Sbms assert( exponent >= Double.MIN_EXPONENT && 124127668Sbms exponent <= Double.MAX_EXPONENT); 125127668Sbms return exponent; 126127668Sbms } 127127668Sbms } 128127668Sbms 129127668Sbms /** 130127668Sbms * Returns unbiased exponent of a {@code float}; for 131127668Sbms * subnormal values, the number is treated as if it were 132127668Sbms * normalized. That is for all finite, non-zero, positive numbers 133147899Ssam * <i>x</i>, <code>scalb(<i>x</i>, -ilogb(<i>x</i>))</code> is 134127668Sbms * always in the range [1, 2). 135127668Sbms * <p> 136127668Sbms * Special cases: 137147899Ssam * <ul> 138127668Sbms * <li> If the argument is NaN, then the result is 2<sup>30</sup>. 139127668Sbms * <li> If the argument is infinite, then the result is 2<sup>28</sup>. 140127668Sbms * <li> If the argument is zero, then the result is -(2<sup>28</sup>). 141127668Sbms * </ul> 142127668Sbms * 143127668Sbms * @param f floating-point number whose exponent is to be extracted 144127668Sbms * @return unbiased exponent of the argument. 145127668Sbms */ 146127668Sbms public static int ilogb(float f) { 147127668Sbms int exponent = Math.getExponent(f); 148127668Sbms 149147899Ssam switch (exponent) { 150147899Ssam case Float.MAX_EXPONENT+1: // NaN or infinity 151147899Ssam if( Float.isNaN(f) ) 152147899Ssam return (1<<30); // 2^30 153147899Ssam else // infinite value 154147899Ssam return (1<<28); // 2^28 155147899Ssam 156147899Ssam case Float.MIN_EXPONENT-1: // zero or subnormal 157147899Ssam if(f == 0.0f) { 158147899Ssam return -(1<<28); // -(2^28) 159147899Ssam } 160147899Ssam else { 161147899Ssam int transducer = Float.floatToRawIntBits(f); 162147899Ssam 163147899Ssam /* 164147899Ssam * To avoid causing slow arithmetic on subnormals, 165147899Ssam * the scaling to determine when f's significand 166147899Ssam * is normalized is done in integer arithmetic. 167147899Ssam * (there must be at least one "1" bit in the 168147899Ssam * significand since zero has been screened out. 169127668Sbms */ 170127668Sbms 171127668Sbms // isolate significand bits 172127668Sbms transducer &= FloatConsts.SIGNIF_BIT_MASK; 173147899Ssam assert(transducer != 0); 174147899Ssam 175127668Sbms // This loop is simple and functional. We might be 176127668Sbms // able to do something more clever that was faster; 177127668Sbms // e.g. number of leading zero detection on 178147899Ssam // (transducer << (# exponent and sign bits). 179127668Sbms while (transducer < 180147899Ssam (1 << (FloatConsts.SIGNIFICAND_WIDTH - 1))) { 181127668Sbms transducer *= 2; 182147899Ssam exponent--; 183147899Ssam } 184127668Sbms exponent++; 185127668Sbms assert( exponent >= 186127668Sbms Float.MIN_EXPONENT - (FloatConsts.SIGNIFICAND_WIDTH-1) && 187147899Ssam exponent < Float.MIN_EXPONENT); 188127668Sbms return exponent; 189147899Ssam } 190127668Sbms 191127668Sbms default: 192127668Sbms assert( exponent >= Float.MIN_EXPONENT && 193127668Sbms exponent <= Float.MAX_EXPONENT); 194127668Sbms return exponent; 195147899Ssam } 196127668Sbms } 197127668Sbms 198147899Ssam /** 199127668Sbms * Returns {@code true} if the unordered relation holds 200147899Ssam * between the two arguments. When two floating-point values are 201127668Sbms * unordered, one value is neither less than, equal to, nor 202127668Sbms * greater than the other. For the unordered relation to be true, 203127668Sbms * at least one argument must be a {@code NaN}. 204127668Sbms * 205127668Sbms * @param arg1 the first argument 206127668Sbms * @param arg2 the second argument 207127668Sbms * @return {@code true} if at least one argument is a NaN, 208127668Sbms * {@code false} otherwise. 209127668Sbms */ 210127668Sbms public static boolean isUnordered(float arg1, float arg2) { 211127668Sbms return Float.isNaN(arg1) || Float.isNaN(arg2); 212127668Sbms } 213127668Sbms 214127668Sbms /** 215147899Ssam * Returns {@code true} if the unordered relation holds 216147899Ssam * between the two arguments. When two floating-point values are 217147899Ssam * unordered, one value is neither less than, equal to, nor 218147899Ssam * greater than the other. For the unordered relation to be true, 219147899Ssam * at least one argument must be a {@code NaN}. 220147899Ssam * 221147899Ssam * @param arg1 the first argument 222147899Ssam * @param arg2 the second argument 223147899Ssam * @return {@code true} if at least one argument is a NaN, 224147899Ssam * {@code false} otherwise. 225147899Ssam */ 226147899Ssam public static boolean isUnordered(double arg1, double arg2) { 227147899Ssam return Double.isNaN(arg1) || Double.isNaN(arg2); 228147899Ssam } 229147899Ssam 230147899Ssam public static int test(String testName, float input, 231147899Ssam boolean result, boolean expected) { 232147899Ssam if (expected != result) { 233147899Ssam System.err.println("Failure for " + testName + ":\n" + 234147899Ssam "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 235147899Ssam "\texpected " + expected + "\n" + 236147899Ssam "\tgot " + result + ")."); 237147899Ssam return 1; 238147899Ssam } 239147899Ssam else 240147899Ssam return 0; 241127668Sbms } 242147899Ssam 243147899Ssam public static int test(String testName, double input, 244147899Ssam boolean result, boolean expected) { 245147899Ssam if (expected != result) { 246147899Ssam System.err.println("Failure for " + testName + ":\n" + 247147899Ssam "\tFor input " + input + "\t(" + toHexString(input) + ")\n" + 248147899Ssam "\texpected " + expected + "\n" + 249147899Ssam "\tgot " + result + ")."); 250147899Ssam return 1; 251147899Ssam } 252147899Ssam else 253147899Ssam return 0; 254147899Ssam } 255147899Ssam 256147899Ssam public static int test(String testName, float input1, float input2, 257147899Ssam boolean result, boolean expected) { 258147899Ssam if (expected != result) { 259147899Ssam System.err.println("Failure for " + testName + ":\n" + 260147899Ssam "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 261147899Ssam + input2 + "\t(" + toHexString(input2) + ")\n" + 262147899Ssam "\texpected " + expected + "\n" + 263147899Ssam "\tgot " + result + ")."); 264147899Ssam return 1; 265127668Sbms } 266127668Sbms return 0; 267127668Sbms } 268127668Sbms 269127668Sbms public static int test(String testName, double input1, double input2, 270127668Sbms boolean result, boolean expected) { 271127668Sbms if (expected != result) { 272127668Sbms System.err.println("Failure for " + testName + ":\n" + 273127668Sbms "\tFor inputs " + input1 + "\t(" + toHexString(input1) + ") and " 274127668Sbms + input2 + "\t(" + toHexString(input2) + ")\n" + 275127668Sbms "\texpected " + expected + "\n" + 276127668Sbms "\tgot " + result + ")."); 277127668Sbms return 1; 278127668Sbms } 279127668Sbms 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} 540