1 /*
   2  * Copyright (c) 2003, 2011 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.FpUtils;
  34 
  35 public class Tests {
  36     private Tests(){}; // do not instantiate
  37 
  38     public static String toHexString(float f) {
  39         if (!Float.isNaN(f))
  40             return Float.toHexString(f);
  41         else
  42             return "NaN(0x" + Integer.toHexString(Float.floatToRawIntBits(f)) + ")";
  43     }
  44 
  45     public static String toHexString(double d) {
  46         if (!Double.isNaN(d))
  47             return Double.toHexString(d);
  48         else
  49             return "NaN(0x" + Long.toHexString(Double.doubleToRawLongBits(d)) + ")";
  50     }
  51 
  52     /**
  53      * Return the floating-point value next larger in magnitude.
  54      */
  55     public static double nextOut(double d) {
  56         if (d > 0.0)
  57             return Math.nextUp(d);
  58         else
  59             return -Math.nextUp(-d);
  60     }
  61 
  62     public static int test(String testName, float input,
  63                            boolean result, boolean expected) {
  64         if (expected != result) {
  65             System.err.println("Failure for " + testName + ":\n" +
  66                                "\tFor input " + input    + "\t(" + toHexString(input) + ")\n" +
  67                                "\texpected  " + expected + "\n"  +
  68                                "\tgot       " + result   + ").");
  69             return 1;
  70         }
  71         else
  72             return 0;
  73     }
  74 
  75     public static int test(String testName, double input,
  76                            boolean result, boolean expected) {
  77         if (expected != result) {
  78             System.err.println("Failure for " + testName + ":\n" +
  79                                "\tFor input " + input    + "\t(" + toHexString(input) + ")\n" +
  80                                "\texpected  " + expected + "\n"  +
  81                                "\tgot       " + result   + ").");
  82             return 1;
  83         }
  84         else
  85             return 0;
  86     }
  87 
  88     public static int test(String testName, float input1, float input2,
  89                            boolean result, boolean expected) {
  90         if (expected != result) {
  91             System.err.println("Failure for "  + testName + ":\n" +
  92                                "\tFor inputs " + input1   + "\t(" + toHexString(input1) + ") and "
  93                                                + input2   + "\t(" + toHexString(input2) + ")\n" +
  94                                "\texpected  "  + expected + "\n"  +
  95                                "\tgot       "  + result   + ").");
  96             return 1;
  97         }
  98         return 0;
  99     }
 100 
 101     public static int test(String testName, double input1, double input2,
 102                            boolean result, boolean expected) {
 103         if (expected != result) {
 104             System.err.println("Failure for "  + testName + ":\n" +
 105                                "\tFor inputs " + input1   + "\t(" + toHexString(input1) + ") and "
 106                                                + input2   + "\t(" + toHexString(input2) + ")\n" +
 107                                "\texpected  "  + expected + "\n"  +
 108                                "\tgot       "  + result   + ").");
 109             return 1;
 110         }
 111         return 0;
 112     }
 113 
 114     public static int test(String testName, float input,
 115                            int result, int expected) {
 116         if (expected != result) {
 117             System.err.println("Failure for " + testName + ":\n" +
 118                                "\tFor input " + input    + "\t(" + toHexString(input) + ")\n" +
 119                                "\texpected  " + expected + "\n" +
 120                                "\tgot       " + result    + ").");
 121             return 1;
 122         }
 123         return 0;
 124     }
 125 
 126     public  static int test(String testName, double input,
 127                             int result, int expected) {
 128         if (expected != result) {
 129             System.err.println("Failure for " + testName + ":\n" +
 130                                "\tFor input " + input    + "\t(" + toHexString(input) + ")\n" +
 131                                "\texpected  " + expected + "\n"  +
 132                                "\tgot       " + result   + ").");
 133             return 1;
 134         }
 135         else
 136             return 0;
 137     }
 138 
 139     public static int test(String testName, float input,
 140                            float result, float expected) {
 141         if (Float.compare(expected, result) != 0 ) {
 142             System.err.println("Failure for " + testName + ":\n" +
 143                                "\tFor input " + input    + "\t(" + toHexString(input) + ")\n" +
 144                                "\texpected  " + expected + "\t(" + toHexString(expected) + ")\n" +
 145                                "\tgot       " + result   + "\t(" + toHexString(result) + ").");
 146             return 1;
 147         }
 148         else
 149             return 0;
 150     }
 151 
 152 
 153     public static int test(String testName, double input,
 154                            double result, double expected) {
 155         if (Double.compare(expected, result ) != 0) {
 156             System.err.println("Failure for " + testName + ":\n" +
 157                                "\tFor input " + input    + "\t(" + toHexString(input) + ")\n" +
 158                                "\texpected  " + expected + "\t(" + toHexString(expected) + ")\n" +
 159                                "\tgot       " + result   + "\t(" + toHexString(result) + ").");
 160             return 1;
 161         }
 162         else
 163             return 0;
 164     }
 165 
 166     public static int test(String testName,
 167                            float input1, double input2,
 168                            float result, float expected) {
 169         if (Float.compare(expected, result ) != 0) {
 170             System.err.println("Failure for "  + testName + ":\n" +
 171                                "\tFor inputs " + input1   + "\t(" + toHexString(input1) + ") and "
 172                                                + input2   + "\t(" + toHexString(input2) + ")\n" +
 173                                "\texpected  "  + expected + "\t(" + toHexString(expected) + ")\n" +
 174                                "\tgot       "  + result   + "\t(" + toHexString(result) + ").");
 175             return 1;
 176         }
 177         else
 178             return 0;
 179     }
 180 
 181     public static int test(String testName,
 182                            double input1, double input2,
 183                            double result, double expected) {
 184         if (Double.compare(expected, result ) != 0) {
 185             System.err.println("Failure for "  + testName + ":\n" +
 186                                "\tFor inputs " + input1   + "\t(" + toHexString(input1) + ") and "
 187                                                + input2   + "\t(" + toHexString(input2) + ")\n" +
 188                                "\texpected  "  + expected + "\t(" + toHexString(expected) + ")\n" +
 189                                "\tgot       "  + result   + "\t(" + toHexString(result) + ").");
 190             return 1;
 191         }
 192         else
 193             return 0;
 194     }
 195 
 196     public static int test(String testName,
 197                            float input1, int input2,
 198                            float result, float expected) {
 199         if (Float.compare(expected, result ) != 0) {
 200             System.err.println("Failure for "  + testName + ":\n" +
 201                                "\tFor inputs " + input1   + "\t(" + toHexString(input1) + ") and "
 202                                                + input2   + "\n"  +
 203                                "\texpected  "  + expected + "\t(" + toHexString(expected) + ")\n" +
 204                                "\tgot       "  + result   + "\t(" + toHexString(result) + ").");
 205             return 1;
 206         }
 207         else
 208             return 0;
 209     }
 210 
 211     public static int test(String testName,
 212                            double input1, int input2,
 213                            double result, double expected) {
 214         if (Double.compare(expected, result ) != 0) {
 215             System.err.println("Failure for "  + testName + ":\n" +
 216                                "\tFor inputs " + input1   + "\t(" + toHexString(input1) + ") and "
 217                                                + input2   + "\n"  +
 218                                "\texpected  "  + expected + "\t(" + toHexString(expected) + ")\n" +
 219                                "\tgot       "  + result   + "\t(" + toHexString(result) + ").");
 220             return 1;
 221         }
 222         else
 223             return 0;
 224     }
 225 
 226     static int testUlpCore(double result, double expected, double ulps) {
 227         // We assume we won't be unlucky and have an inexact expected
 228         // be nextDown(2^i) when 2^i would be the correctly rounded
 229         // answer.  This would cause the ulp size to be half as large
 230         // as it should be, doubling the measured error).
 231 
 232         if (Double.compare(expected, result) == 0) {
 233             return 0;   // result and expected are equivalent
 234         } else {
 235             if( ulps == 0.0) {
 236                 // Equivalent results required but not found
 237                 return 1;
 238             } else {
 239                 double difference = expected - result;
 240                 if (FpUtils.isUnordered(expected, result) ||
 241                     Double.isNaN(difference) ||
 242                     // fail if greater than or unordered
 243                     !(Math.abs( difference/Math.ulp(expected) ) <= Math.abs(ulps)) ) {
 244                     return 1;
 245                 }
 246                 else
 247                     return 0;
 248             }
 249         }
 250     }
 251 
 252     // One input argument.
 253     public static int testUlpDiff(String testName, double input,
 254                                   double result, double expected, double ulps) {
 255         int code = testUlpCore(result, expected, ulps);
 256         if (code == 1) {
 257             System.err.println("Failure for " + testName + ":\n" +
 258                                "\tFor input " + input    + "\t(" + toHexString(input) + ")\n" +
 259                                "\texpected  " + expected + "\t(" + toHexString(expected) + ")\n" +
 260                                "\tgot       " + result   + "\t(" + toHexString(result) + ");\n" +
 261                                "\tdifference greater than ulp tolerance " + ulps);
 262         }
 263         return code;
 264     }
 265 
 266     // Two input arguments.
 267     public static int testUlpDiff(String testName, double input1, double input2,
 268                                   double result, double expected, double ulps) {
 269         int code = testUlpCore(result, expected, ulps);
 270         if (code == 1) {
 271             System.err.println("Failure for "  + testName + ":\n" +
 272                                "\tFor inputs " + input1   + "\t(" + toHexString(input1) + ") and "
 273                                                + input2   + "\t(" + toHexString(input2) + ")\n" +
 274                                "\texpected  "  + expected + "\t(" + toHexString(expected) + ")\n" +
 275                                "\tgot       "  + result   + "\t(" + toHexString(result) + ");\n" +
 276                                "\tdifference greater than ulp tolerance " + ulps);
 277         }
 278         return code;
 279     }
 280 
 281     // For a successful test, the result must be within the ulp bound of
 282     // expected AND the result must have absolute value less than or
 283     // equal to absBound.
 284     public static int testUlpDiffWithAbsBound(String testName, double input,
 285                                               double result, double expected,
 286                                               double ulps, double absBound) {
 287         int code = 0;   // return code value
 288 
 289         if (!(StrictMath.abs(result) <= StrictMath.abs(absBound)) &&
 290             !Double.isNaN(expected)) {
 291             code = 1;
 292         } else
 293             code = testUlpCore(result, expected, ulps);
 294 
 295         if (code == 1) {
 296             System.err.println("Failure for " + testName + ":\n" +
 297                                "\tFor input " + input    + "\t(" + toHexString(input) + ")\n" +
 298                                "\texpected  " + expected + "\t(" + toHexString(expected) + ")\n" +
 299                                "\tgot       " + result   + "\t(" + toHexString(result) + ");\n" +
 300                                "\tdifference greater than ulp tolerance " + ulps +
 301                                " or the result has larger magnitude than " + absBound);
 302         }
 303         return code;
 304     }
 305 
 306     // For a successful test, the result must be within the ulp bound of
 307     // expected AND the result must have absolute value greater than
 308     // or equal to the lowerBound.
 309     public static int testUlpDiffWithLowerBound(String testName, double input,
 310                                                 double result, double expected,
 311                                                 double ulps, double lowerBound) {
 312         int code = 0;   // return code value
 313 
 314         if (!(result >= lowerBound) && !Double.isNaN(expected)) {
 315             code = 1;
 316         } else
 317             code = testUlpCore(result, expected, ulps);
 318 
 319         if (code == 1) {
 320             System.err.println("Failure for " + testName +
 321                                ":\n" +
 322                                "\tFor input "   + input    + "\t(" + toHexString(input) + ")" +
 323                                "\n\texpected  " + expected + "\t(" + toHexString(expected) + ")" +
 324                                "\n\tgot       " + result   + "\t(" + toHexString(result) + ");" +
 325                                "\ndifference greater than ulp tolerance " + ulps +
 326                                " or result not greater than or equal to the bound " + lowerBound);
 327         }
 328         return code;
 329     }
 330 
 331     public static int testTolerance(String testName, double input,
 332                                     double result, double expected, double tolerance) {
 333         if (Double.compare(expected, result ) != 0) {
 334             double difference = expected - result;
 335             if (FpUtils.isUnordered(expected, result) ||
 336                 Double.isNaN(difference) ||
 337                 // fail if greater than or unordered
 338                 !(Math.abs((difference)/expected) <= StrictMath.pow(10, -tolerance)) ) {
 339                 System.err.println("Failure for " + testName + ":\n" +
 340                                    "\tFor input " + input    + "\t(" + toHexString(input) + ")\n" +
 341                                    "\texpected  " + expected + "\t(" + toHexString(expected) + ")\n" +
 342                                    "\tgot       " + result   + "\t(" + toHexString(result) + ");\n" +
 343                                    "\tdifference greater than tolerance 10^-" + tolerance);
 344                 return 1;
 345             }
 346             return 0;
 347         }
 348         else
 349             return 0;
 350     }
 351 
 352     // For a successful test, the result must be within the upper and
 353     // lower bounds.
 354     public static int testBounds(String testName, double input, double result,
 355                                  double bound1, double bound2) {
 356         if ((result >= bound1 && result <= bound2) ||
 357             (result <= bound1 && result >= bound2))
 358             return 0;
 359         else {
 360             double lowerBound = Math.min(bound1, bound2);
 361             double upperBound = Math.max(bound1, bound2);
 362             System.err.println("Failure for " + testName + ":\n" +
 363                                "\tFor input " + input    + "\t(" + toHexString(input) + ")\n" +
 364                                "\tgot       " + result   + "\t(" + toHexString(result) + ");\n" +
 365                                "\toutside of range\n" +
 366                                "\t[" + lowerBound    + "\t(" + toHexString(lowerBound) + "), " +
 367                                upperBound    + "\t(" + toHexString(upperBound) + ")]");
 368             return 1;
 369         }
 370     }
 371 }