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 }