Tests.java revision 10532:74078474d9bd
1127668Sbms/*
2127668Sbms * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
3127668Sbms * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4127668Sbms *
5127668Sbms * This code is free software; you can redistribute it and/or modify it
6127668Sbms * under the terms of the GNU General Public License version 2 only, as
7127668Sbms * published by the Free Software Foundation.
8127668Sbms *
9127668Sbms * This code is distributed in the hope that it will be useful, but WITHOUT
10127668Sbms * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11127668Sbms * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12127668Sbms * version 2 for more details (a copy is included in the LICENSE file that
13127668Sbms * accompanied this code).
14127668Sbms *
15127668Sbms * You should have received a copy of the GNU General Public License version
16127668Sbms * 2 along with this work; if not, write to the Free Software Foundation,
17127668Sbms * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18147899Ssam *
19127668Sbms * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20127668Sbms * or visit www.oracle.com if you need additional information or have any
21127668Sbms * questions.
22127668Sbms */
23127668Sbms
24127668Sbms/*
25127668Sbms * Shared static test methods for numerical tests.  Sharing these
26127668Sbms * helper test methods avoids repeated functions in the various test
27127668Sbms * programs.  The test methods return 1 for a test failure and 0 for
28127668Sbms * success.  The order of arguments to the test methods is generally
29127668Sbms * the test name, followed by the test arguments, the computed result,
30127668Sbms * and finally the expected result.
31127668Sbms */
32127668Sbms
33127668Sbmspublic class Tests {
34127668Sbms    private Tests(){}; // do not instantiate
35127668Sbms
36127668Sbms    public static String toHexString(float f) {
37147899Ssam        if (!Float.isNaN(f))
38127668Sbms            return Float.toHexString(f);
39127668Sbms        else
40127668Sbms            return "NaN(0x" + Integer.toHexString(Float.floatToRawIntBits(f)) + ")";
41127668Sbms    }
42127668Sbms
43127668Sbms    public static String toHexString(double d) {
44127668Sbms        if (!Double.isNaN(d))
45127668Sbms            return Double.toHexString(d);
46127668Sbms        else
47127668Sbms            return "NaN(0x" + Long.toHexString(Double.doubleToRawLongBits(d)) + ")";
48127668Sbms    }
49127668Sbms
50127668Sbms    /**
51127668Sbms     * Return the floating-point value next larger in magnitude.
52127668Sbms     */
53127668Sbms    public static double nextOut(double d) {
54127668Sbms        if (d > 0.0)
55127668Sbms            return Math.nextUp(d);
56147899Ssam        else
57147899Ssam            return -Math.nextUp(-d);
58147899Ssam    }
59147899Ssam
60147899Ssam    /**
61147899Ssam     * Returns unbiased exponent of a {@code float}; for
62147899Ssam     * subnormal values, the number is treated as if it were
63147899Ssam     * normalized.  That is for all finite, non-zero, positive numbers
64147899Ssam     * <i>x</i>, <code>scalb(<i>x</i>, -ilogb(<i>x</i>))</code> is
65147899Ssam     * always in the range [1, 2).
66147899Ssam     * <p>
67147899Ssam     * Special cases:
68147899Ssam     * <ul>
69147899Ssam     * <li> If the argument is NaN, then the result is 2<sup>30</sup>.
70147899Ssam     * <li> If the argument is infinite, then the result is 2<sup>28</sup>.
71147899Ssam     * <li> If the argument is zero, then the result is -(2<sup>28</sup>).
72147899Ssam     * </ul>
73147899Ssam     *
74147899Ssam     * @param f floating-point number whose exponent is to be extracted
75147899Ssam     * @return unbiased exponent of the argument.
76127668Sbms     */
77127668Sbms    public static int ilogb(double d) {
78127668Sbms        int exponent = Math.getExponent(d);
79127668Sbms
80127668Sbms        switch (exponent) {
81127668Sbms        case Double.MAX_EXPONENT+1:       // NaN or infinity
82127668Sbms            if( Double.isNaN(d) )
83127668Sbms                return (1<<30);         // 2^30
84127668Sbms            else // infinite value
85127668Sbms                return (1<<28);         // 2^28
86127668Sbms
87127668Sbms        case Double.MIN_EXPONENT-1:       // zero or subnormal
88147899Ssam            if(d == 0.0) {
89147899Ssam                return -(1<<28);        // -(2^28)
90147899Ssam            }
91147899Ssam            else {
92147899Ssam                long transducer = Double.doubleToRawLongBits(d);
93147899Ssam
94147899Ssam                /*
95147899Ssam                 * To avoid causing slow arithmetic on subnormals,
96147899Ssam                 * the scaling to determine when d's significand
97147899Ssam                 * is normalized is done in integer arithmetic.
98147899Ssam                 * (there must be at least one "1" bit in the
99147899Ssam                 * significand since zero has been screened out.
100147899Ssam                 */
101147899Ssam
102147899Ssam                // isolate significand bits
103147899Ssam                transducer &= DoubleConsts.SIGNIF_BIT_MASK;
104147899Ssam                assert(transducer != 0L);
105147899Ssam
106147899Ssam                // This loop is simple and functional. We might be
107147899Ssam                // able to do something more clever that was faster;
108147899Ssam                // e.g. number of leading zero detection on
109147899Ssam                // (transducer << (# exponent and sign bits).
110147899Ssam                while (transducer <
111147899Ssam                       (1L << (DoubleConsts.SIGNIFICAND_WIDTH - 1))) {
112147899Ssam                    transducer *= 2;
113147899Ssam                    exponent--;
114127668Sbms                }
115127668Sbms                exponent++;
116127668Sbms                assert( exponent >=
117127668Sbms                        Double.MIN_EXPONENT - (DoubleConsts.SIGNIFICAND_WIDTH-1) &&
118127668Sbms                        exponent < Double.MIN_EXPONENT);
119127668Sbms                return exponent;
120127668Sbms            }
121127668Sbms
122127668Sbms        default:
123127668Sbms            assert( exponent >= Double.MIN_EXPONENT &&
124127668Sbms                    exponent <= Double.MAX_EXPONENT);
125127668Sbms            return exponent;
126127668Sbms        }
127127668Sbms    }
128127668Sbms
129127668Sbms    /**
130127668Sbms     * Returns unbiased exponent of a {@code float}; for
131127668Sbms     * subnormal values, the number is treated as if it were
132127668Sbms     * normalized.  That is for all finite, non-zero, positive numbers
133147899Ssam     * <i>x</i>, <code>scalb(<i>x</i>, -ilogb(<i>x</i>))</code> is
134127668Sbms     * always in the range [1, 2).
135127668Sbms     * <p>
136127668Sbms     * Special cases:
137147899Ssam     * <ul>
138127668Sbms     * <li> If the argument is NaN, then the result is 2<sup>30</sup>.
139127668Sbms     * <li> If the argument is infinite, then the result is 2<sup>28</sup>.
140127668Sbms     * <li> If the argument is zero, then the result is -(2<sup>28</sup>).
141127668Sbms     * </ul>
142127668Sbms     *
143127668Sbms     * @param f floating-point number whose exponent is to be extracted
144127668Sbms     * @return unbiased exponent of the argument.
145127668Sbms     */
146127668Sbms     public static int ilogb(float f) {
147127668Sbms        int exponent = Math.getExponent(f);
148127668Sbms
149147899Ssam        switch (exponent) {
150147899Ssam        case Float.MAX_EXPONENT+1:        // NaN or infinity
151147899Ssam            if( Float.isNaN(f) )
152147899Ssam                return (1<<30);         // 2^30
153147899Ssam            else // infinite value
154147899Ssam                return (1<<28);         // 2^28
155147899Ssam
156147899Ssam        case Float.MIN_EXPONENT-1:        // zero or subnormal
157147899Ssam            if(f == 0.0f) {
158147899Ssam                return -(1<<28);        // -(2^28)
159147899Ssam            }
160147899Ssam            else {
161147899Ssam                int transducer = Float.floatToRawIntBits(f);
162147899Ssam
163147899Ssam                /*
164147899Ssam                 * To avoid causing slow arithmetic on subnormals,
165147899Ssam                 * the scaling to determine when f's significand
166147899Ssam                 * is normalized is done in integer arithmetic.
167147899Ssam                 * (there must be at least one "1" bit in the
168147899Ssam                 * significand since zero has been screened out.
169127668Sbms                 */
170127668Sbms
171127668Sbms                // isolate significand bits
172127668Sbms                transducer &= FloatConsts.SIGNIF_BIT_MASK;
173147899Ssam                assert(transducer != 0);
174147899Ssam
175127668Sbms                // This loop is simple and functional. We might be
176127668Sbms                // able to do something more clever that was faster;
177127668Sbms                // e.g. number of leading zero detection on
178147899Ssam                // (transducer << (# exponent and sign bits).
179127668Sbms                while (transducer <
180147899Ssam                       (1 << (FloatConsts.SIGNIFICAND_WIDTH - 1))) {
181127668Sbms                    transducer *= 2;
182147899Ssam                    exponent--;
183147899Ssam                }
184127668Sbms                exponent++;
185127668Sbms                assert( exponent >=
186127668Sbms                        Float.MIN_EXPONENT - (FloatConsts.SIGNIFICAND_WIDTH-1) &&
187147899Ssam                        exponent < Float.MIN_EXPONENT);
188127668Sbms                return exponent;
189147899Ssam            }
190127668Sbms
191127668Sbms        default:
192127668Sbms            assert( exponent >= Float.MIN_EXPONENT &&
193127668Sbms                    exponent <= Float.MAX_EXPONENT);
194127668Sbms            return exponent;
195147899Ssam        }
196127668Sbms    }
197127668Sbms
198147899Ssam    /**
199127668Sbms     * Returns {@code true} if the unordered relation holds
200147899Ssam     * between the two arguments.  When two floating-point values are
201127668Sbms     * unordered, one value is neither less than, equal to, nor
202127668Sbms     * greater than the other.  For the unordered relation to be true,
203127668Sbms     * at least one argument must be a {@code NaN}.
204127668Sbms     *
205127668Sbms     * @param arg1      the first argument
206127668Sbms     * @param arg2      the second argument
207127668Sbms     * @return {@code true} if at least one argument is a NaN,
208127668Sbms     * {@code false} otherwise.
209127668Sbms     */
210127668Sbms     public static boolean isUnordered(float arg1, float arg2) {
211127668Sbms        return Float.isNaN(arg1) || Float.isNaN(arg2);
212127668Sbms    }
213127668Sbms
214127668Sbms    /**
215147899Ssam     * Returns {@code true} if the unordered relation holds
216147899Ssam     * between the two arguments.  When two floating-point values are
217147899Ssam     * unordered, one value is neither less than, equal to, nor
218147899Ssam     * greater than the other.  For the unordered relation to be true,
219147899Ssam     * at least one argument must be a {@code NaN}.
220147899Ssam     *
221147899Ssam     * @param arg1      the first argument
222147899Ssam     * @param arg2      the second argument
223147899Ssam     * @return {@code true} if at least one argument is a NaN,
224147899Ssam     * {@code false} otherwise.
225147899Ssam     */
226147899Ssam    public static boolean isUnordered(double arg1, double arg2) {
227147899Ssam        return Double.isNaN(arg1) || Double.isNaN(arg2);
228147899Ssam    }
229147899Ssam
230147899Ssam    public static int test(String testName, float input,
231147899Ssam                           boolean result, boolean expected) {
232147899Ssam        if (expected != result) {
233147899Ssam            System.err.println("Failure for " + testName + ":\n" +
234147899Ssam                               "\tFor input " + input    + "\t(" + toHexString(input) + ")\n" +
235147899Ssam                               "\texpected  " + expected + "\n"  +
236147899Ssam                               "\tgot       " + result   + ").");
237147899Ssam            return 1;
238147899Ssam        }
239147899Ssam        else
240147899Ssam            return 0;
241127668Sbms    }
242147899Ssam
243147899Ssam    public static int test(String testName, double input,
244147899Ssam                           boolean result, boolean expected) {
245147899Ssam        if (expected != result) {
246147899Ssam            System.err.println("Failure for " + testName + ":\n" +
247147899Ssam                               "\tFor input " + input    + "\t(" + toHexString(input) + ")\n" +
248147899Ssam                               "\texpected  " + expected + "\n"  +
249147899Ssam                               "\tgot       " + result   + ").");
250147899Ssam            return 1;
251147899Ssam        }
252147899Ssam        else
253147899Ssam            return 0;
254147899Ssam    }
255147899Ssam
256147899Ssam    public static int test(String testName, float input1, float input2,
257147899Ssam                           boolean result, boolean expected) {
258147899Ssam        if (expected != result) {
259147899Ssam            System.err.println("Failure for "  + testName + ":\n" +
260147899Ssam                               "\tFor inputs " + input1   + "\t(" + toHexString(input1) + ") and "
261147899Ssam                                               + input2   + "\t(" + toHexString(input2) + ")\n" +
262147899Ssam                               "\texpected  "  + expected + "\n"  +
263147899Ssam                               "\tgot       "  + result   + ").");
264147899Ssam            return 1;
265127668Sbms        }
266127668Sbms        return 0;
267127668Sbms    }
268127668Sbms
269127668Sbms    public static int test(String testName, double input1, double input2,
270127668Sbms                           boolean result, boolean expected) {
271127668Sbms        if (expected != result) {
272127668Sbms            System.err.println("Failure for "  + testName + ":\n" +
273127668Sbms                               "\tFor inputs " + input1   + "\t(" + toHexString(input1) + ") and "
274127668Sbms                                               + input2   + "\t(" + toHexString(input2) + ")\n" +
275127668Sbms                               "\texpected  "  + expected + "\n"  +
276127668Sbms                               "\tgot       "  + result   + ").");
277127668Sbms            return 1;
278127668Sbms        }
279127668Sbms        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    static int testUlpCore(double result, double expected, double ulps) {
395        // We assume we won't be unlucky and have an inexact expected
396        // be nextDown(2^i) when 2^i would be the correctly rounded
397        // answer.  This would cause the ulp size to be half as large
398        // as it should be, doubling the measured error).
399
400        if (Double.compare(expected, result) == 0) {
401            return 0;   // result and expected are equivalent
402        } else {
403            if( ulps == 0.0) {
404                // Equivalent results required but not found
405                return 1;
406            } else {
407                double difference = expected - result;
408                if (isUnordered(expected, result) ||
409                    Double.isNaN(difference) ||
410                    // fail if greater than or unordered
411                    !(Math.abs( difference/Math.ulp(expected) ) <= Math.abs(ulps)) ) {
412                    return 1;
413                }
414                else
415                    return 0;
416            }
417        }
418    }
419
420    // One input argument.
421    public static int testUlpDiff(String testName, double input,
422                                  double result, double expected, double ulps) {
423        int code = testUlpCore(result, expected, ulps);
424        if (code == 1) {
425            System.err.println("Failure for " + testName + ":\n" +
426                               "\tFor input " + input    + "\t(" + toHexString(input) + ")\n" +
427                               "\texpected  " + expected + "\t(" + toHexString(expected) + ")\n" +
428                               "\tgot       " + result   + "\t(" + toHexString(result) + ");\n" +
429                               "\tdifference greater than ulp tolerance " + ulps);
430        }
431        return code;
432    }
433
434    // Two input arguments.
435    public static int testUlpDiff(String testName, double input1, double input2,
436                                  double result, double expected, double ulps) {
437        int code = testUlpCore(result, expected, ulps);
438        if (code == 1) {
439            System.err.println("Failure for "  + testName + ":\n" +
440                               "\tFor inputs " + input1   + "\t(" + toHexString(input1) + ") and "
441                                               + input2   + "\t(" + toHexString(input2) + ")\n" +
442                               "\texpected  "  + expected + "\t(" + toHexString(expected) + ")\n" +
443                               "\tgot       "  + result   + "\t(" + toHexString(result) + ");\n" +
444                               "\tdifference greater than ulp tolerance " + ulps);
445        }
446        return code;
447    }
448
449    // For a successful test, the result must be within the ulp bound of
450    // expected AND the result must have absolute value less than or
451    // equal to absBound.
452    public static int testUlpDiffWithAbsBound(String testName, double input,
453                                              double result, double expected,
454                                              double ulps, double absBound) {
455        int code = 0;   // return code value
456
457        if (!(StrictMath.abs(result) <= StrictMath.abs(absBound)) &&
458            !Double.isNaN(expected)) {
459            code = 1;
460        } else
461            code = testUlpCore(result, expected, ulps);
462
463        if (code == 1) {
464            System.err.println("Failure for " + testName + ":\n" +
465                               "\tFor input " + input    + "\t(" + toHexString(input) + ")\n" +
466                               "\texpected  " + expected + "\t(" + toHexString(expected) + ")\n" +
467                               "\tgot       " + result   + "\t(" + toHexString(result) + ");\n" +
468                               "\tdifference greater than ulp tolerance " + ulps +
469                               " or the result has larger magnitude than " + absBound);
470        }
471        return code;
472    }
473
474    // For a successful test, the result must be within the ulp bound of
475    // expected AND the result must have absolute value greater than
476    // or equal to the lowerBound.
477    public static int testUlpDiffWithLowerBound(String testName, double input,
478                                                double result, double expected,
479                                                double ulps, double lowerBound) {
480        int code = 0;   // return code value
481
482        if (!(result >= lowerBound) && !Double.isNaN(expected)) {
483            code = 1;
484        } else
485            code = testUlpCore(result, expected, ulps);
486
487        if (code == 1) {
488            System.err.println("Failure for " + testName +
489                               ":\n" +
490                               "\tFor input "   + input    + "\t(" + toHexString(input) + ")" +
491                               "\n\texpected  " + expected + "\t(" + toHexString(expected) + ")" +
492                               "\n\tgot       " + result   + "\t(" + toHexString(result) + ");" +
493                               "\ndifference greater than ulp tolerance " + ulps +
494                               " or result not greater than or equal to the bound " + lowerBound);
495        }
496        return code;
497    }
498
499    public static int testTolerance(String testName, double input,
500                                    double result, double expected, double tolerance) {
501        if (Double.compare(expected, result ) != 0) {
502            double difference = expected - result;
503            if (isUnordered(expected, result) ||
504                Double.isNaN(difference) ||
505                // fail if greater than or unordered
506                !(Math.abs((difference)/expected) <= StrictMath.pow(10, -tolerance)) ) {
507                System.err.println("Failure for " + testName + ":\n" +
508                                   "\tFor input " + input    + "\t(" + toHexString(input) + ")\n" +
509                                   "\texpected  " + expected + "\t(" + toHexString(expected) + ")\n" +
510                                   "\tgot       " + result   + "\t(" + toHexString(result) + ");\n" +
511                                   "\tdifference greater than tolerance 10^-" + tolerance);
512                return 1;
513            }
514            return 0;
515        }
516        else
517            return 0;
518    }
519
520    // For a successful test, the result must be within the upper and
521    // lower bounds.
522    public static int testBounds(String testName, double input, double result,
523                                 double bound1, double bound2) {
524        if ((result >= bound1 && result <= bound2) ||
525            (result <= bound1 && result >= bound2))
526            return 0;
527        else {
528            double lowerBound = Math.min(bound1, bound2);
529            double upperBound = Math.max(bound1, bound2);
530            System.err.println("Failure for " + testName + ":\n" +
531                               "\tFor input " + input    + "\t(" + toHexString(input) + ")\n" +
532                               "\tgot       " + result   + "\t(" + toHexString(result) + ");\n" +
533                               "\toutside of range\n" +
534                               "\t[" + lowerBound    + "\t(" + toHexString(lowerBound) + "), " +
535                               upperBound    + "\t(" + toHexString(upperBound) + ")]");
536            return 1;
537        }
538    }
539}
540