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