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
33public 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}
572