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 {
Tests()34     private Tests(){}; // do not instantiate
35 
toHexString(float f)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 
toHexString(double d)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      */
nextOut(double d)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      */
ilogb(double d)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      */
ilogb(float f)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      */
isUnordered(float arg1, float arg2)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      */
isUnordered(double arg1, double arg2)226     public static boolean isUnordered(double arg1, double arg2) {
227         return Double.isNaN(arg1) || Double.isNaN(arg2);
228     }
229 
test(String testName, float input, boolean result, boolean expected)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 
test(String testName, double input, boolean result, boolean expected)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 
test(String testName, float input1, float input2, boolean result, boolean expected)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 
test(String testName, double input1, double input2, boolean result, boolean expected)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 
test(String testName, float input, int result, int expected)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 
test(String testName, double input, int result, int expected)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 
test(String testName, float input, float result, float expected)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 
test(String testName, double input, double result, double expected)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 
test(String testName, float input1, double input2, float result, float expected)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 
test(String testName, double input1, double input2, double result, double expected)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 
test(String testName, float input1, int input2, float result, float expected)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 
test(String testName, double input1, int input2, double result, double expected)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 
test(String testName, float input1, float input2, float input3, float result, float expected)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 
test(String testName, double input1, double input2, double input3, double result, double expected)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 
testUlpCore(double result, double expected, double ulps)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.
testUlpDiff(String testName, double input, double result, double expected, double ulps)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.
testUlpDiff(String testName, double input1, double input2, double result, double expected, double ulps)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.
testUlpDiffWithAbsBound(String testName, double input, double result, double expected, double ulps, double 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.
testUlpDiffWithLowerBound(String testName, double input, double result, double expected, double ulps, double 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 
testTolerance(String testName, double input, double result, double expected, double tolerance)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.
testBounds(String testName, double input, double result, double bound1, double bound2)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 }
572