alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (IeeeRecommendedTests.java)

This example Java source code file (IeeeRecommendedTests.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

double_max_subnormal, double_max_subnormalmm, double_max_valuemm, exponent, float_max_subnormal, float_max_subnormalmm, float_max_valuemm, ieeerecommendedtests, max_scale, max_scale\+1, max_scale\-1, nand, nanf, nans

The IeeeRecommendedTests.java Java example source code

/*
 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/*
 * @test
 * @bug 4860891 4826732 4780454 4939441 4826652
 * @summary Tests for IEEE 754[R] recommended functions and similar methods
 * @author Joseph D. Darcy
 */

import sun.misc.FpUtils;
import sun.misc.DoubleConsts;
import sun.misc.FloatConsts;

public class IeeeRecommendedTests {
    private IeeeRecommendedTests(){}

    static final float  NaNf = Float.NaN;
    static final double NaNd = Double.NaN;
    static final float  infinityF = Float.POSITIVE_INFINITY;
    static final double infinityD = Double.POSITIVE_INFINITY;

    static final float  Float_MAX_VALUEmm       = 0x1.fffffcP+127f;
    static final float  Float_MAX_SUBNORMAL     = 0x0.fffffeP-126f;
    static final float  Float_MAX_SUBNORMALmm   = 0x0.fffffcP-126f;

    static final double Double_MAX_VALUEmm      = 0x1.ffffffffffffeP+1023;
    static final double Double_MAX_SUBNORMAL    = 0x0.fffffffffffffP-1022;
    static final double Double_MAX_SUBNORMALmm  = 0x0.ffffffffffffeP-1022;

    // Initialize shared random number generator
    static java.util.Random rand = new java.util.Random();

    /**
     * Returns a floating-point power of two in the normal range.
     */
    static double powerOfTwoD(int n) {
        return Double.longBitsToDouble((((long)n + (long)DoubleConsts.MAX_EXPONENT) <<
                                        (DoubleConsts.SIGNIFICAND_WIDTH-1))
                                       & DoubleConsts.EXP_BIT_MASK);
    }

    /**
     * Returns a floating-point power of two in the normal range.
     */
    static float powerOfTwoF(int n) {
        return Float.intBitsToFloat(((n + FloatConsts.MAX_EXPONENT) <<
                                     (FloatConsts.SIGNIFICAND_WIDTH-1))
                                    & FloatConsts.EXP_BIT_MASK);
    }

    /* ******************** getExponent tests ****************************** */

    /*
     * The tests for getExponent should test the special values (NaN, +/-
     * infinity, etc.), test the endpoints of each binade (set of
     * floating-point values with the same exponent), and for good
     * measure, test some random values within each binade.  Testing
     * the endpoints of each binade includes testing both positive and
     * negative numbers.  Subnormal values with different normalized
     * exponents should be tested too.  Both Math and StrictMath
     * methods should return the same results.
     */

    /*
     * Test Math.getExponent and StrictMath.getExponent with +d and -d.
     */
    static int testGetExponentCase(float f, int expected) {
        float minus_f = -f;
        int failures=0;

        failures+=Tests.test("Math.getExponent(float)", f,
                             Math.getExponent(f), expected);
        failures+=Tests.test("Math.getExponent(float)", minus_f,
                             Math.getExponent(minus_f), expected);

        failures+=Tests.test("StrictMath.getExponent(float)", f,
                             StrictMath.getExponent(f), expected);
        failures+=Tests.test("StrictMath.getExponent(float)", minus_f,
                             StrictMath.getExponent(minus_f), expected);
        return failures;
    }

    /*
     * Test Math.getExponent and StrictMath.getExponent with +d and -d.
     */
    static int testGetExponentCase(double d, int expected) {
        double minus_d = -d;
        int failures=0;

        failures+=Tests.test("Math.getExponent(double)", d,
                             Math.getExponent(d), expected);
        failures+=Tests.test("Math.getExponent(double)", minus_d,
                             Math.getExponent(minus_d), expected);

        failures+=Tests.test("StrictMath.getExponent(double)", d,
                             StrictMath.getExponent(d), expected);
        failures+=Tests.test("StrictMath.getExponent(double)", minus_d,
                             StrictMath.getExponent(minus_d), expected);
        return failures;
    }

    public static int testFloatGetExponent() {
        int failures = 0;
        float [] specialValues = {NaNf,
                                   Float.POSITIVE_INFINITY,
                                   +0.0f,
                                  +1.0f,
                                  +2.0f,
                                  +16.0f,
                                  +Float.MIN_VALUE,
                                  +Float_MAX_SUBNORMAL,
                                  +FloatConsts.MIN_NORMAL,
                                  +Float.MAX_VALUE
        };

        int [] specialResults = {Float.MAX_EXPONENT + 1, // NaN results
                                 Float.MAX_EXPONENT + 1, // Infinite results
                                 Float.MIN_EXPONENT - 1, // Zero results
                                 0,
                                 1,
                                 4,
                                 FloatConsts.MIN_EXPONENT - 1,
                                 -FloatConsts.MAX_EXPONENT,
                                 FloatConsts.MIN_EXPONENT,
                                 FloatConsts.MAX_EXPONENT
        };

        // Special value tests
        for(int i = 0; i < specialValues.length; i++) {
            failures += testGetExponentCase(specialValues[i], specialResults[i]);
        }


        // Normal exponent tests
        for(int i = FloatConsts.MIN_EXPONENT; i <= FloatConsts.MAX_EXPONENT; i++) {
            int result;

            // Create power of two
            float po2 = powerOfTwoF(i);

            failures += testGetExponentCase(po2, i);

            // Generate some random bit patterns for the significand
            for(int j = 0; j < 10; j++) {
                int randSignif = rand.nextInt();
                float randFloat;

                randFloat = Float.intBitsToFloat( // Exponent
                                                 (Float.floatToIntBits(po2)&
                                                  (~FloatConsts.SIGNIF_BIT_MASK)) |
                                                 // Significand
                                                 (randSignif &
                                                  FloatConsts.SIGNIF_BIT_MASK) );

                failures += testGetExponentCase(randFloat, i);
            }

            if (i > FloatConsts.MIN_EXPONENT) {
                float po2minus = Math.nextAfter(po2,
                                                 Float.NEGATIVE_INFINITY);
                failures += testGetExponentCase(po2minus, i-1);
            }
        }

        // Subnormal exponent tests

        /*
         * Start with MIN_VALUE, left shift, test high value, low
         * values, and random in between.
         *
         * Use nextAfter to calculate, high value of previous binade,
         * loop count i will indicate how many random bits, if any are
         * needed.
         */

        float top=Float.MIN_VALUE;
        for( int i = 1;
            i < FloatConsts.SIGNIFICAND_WIDTH;
            i++, top *= 2.0f) {

            failures += testGetExponentCase(top,
                                            FloatConsts.MIN_EXPONENT - 1);

            // Test largest value in next smaller binade
            if (i >= 3) {// (i == 1) would test 0.0;
                         // (i == 2) would just retest MIN_VALUE
                testGetExponentCase(Math.nextAfter(top, 0.0f),
                                    FloatConsts.MIN_EXPONENT - 1);

                if( i >= 10) {
                    // create a bit mask with (i-1) 1's in the low order
                    // bits
                    int mask = ~((~0)<<(i-1));
                    float randFloat = Float.intBitsToFloat( // Exponent
                                                 Float.floatToIntBits(top) |
                                                 // Significand
                                                 (rand.nextInt() & mask ) ) ;

                    failures += testGetExponentCase(randFloat,
                                                    FloatConsts.MIN_EXPONENT - 1);
                }
            }
        }

        return failures;
    }


    public static int testDoubleGetExponent() {
        int failures = 0;
        double [] specialValues = {NaNd,
                                   infinityD,
                                   +0.0,
                                   +1.0,
                                   +2.0,
                                   +16.0,
                                   +Double.MIN_VALUE,
                                   +Double_MAX_SUBNORMAL,
                                   +DoubleConsts.MIN_NORMAL,
                                   +Double.MAX_VALUE
        };

        int [] specialResults = {Double.MAX_EXPONENT + 1, // NaN results
                                 Double.MAX_EXPONENT + 1, // Infinite results
                                 Double.MIN_EXPONENT - 1, // Zero results
                                 0,
                                 1,
                                 4,
                                 DoubleConsts.MIN_EXPONENT - 1,
                                 -DoubleConsts.MAX_EXPONENT,
                                 DoubleConsts.MIN_EXPONENT,
                                 DoubleConsts.MAX_EXPONENT
        };

        // Special value tests
        for(int i = 0; i < specialValues.length; i++) {
            failures += testGetExponentCase(specialValues[i], specialResults[i]);
        }


        // Normal exponent tests
        for(int i = DoubleConsts.MIN_EXPONENT; i <= DoubleConsts.MAX_EXPONENT; i++) {
            int result;

            // Create power of two
            double po2 = powerOfTwoD(i);

            failures += testGetExponentCase(po2, i);

            // Generate some random bit patterns for the significand
            for(int j = 0; j < 10; j++) {
                long randSignif = rand.nextLong();
                double randFloat;

                randFloat = Double.longBitsToDouble( // Exponent
                                                 (Double.doubleToLongBits(po2)&
                                                  (~DoubleConsts.SIGNIF_BIT_MASK)) |
                                                 // Significand
                                                 (randSignif &
                                                  DoubleConsts.SIGNIF_BIT_MASK) );

                failures += testGetExponentCase(randFloat, i);
            }

            if (i > DoubleConsts.MIN_EXPONENT) {
                double po2minus = Math.nextAfter(po2,
                                                    Double.NEGATIVE_INFINITY);
                failures += testGetExponentCase(po2minus, i-1);
            }
        }

        // Subnormal exponent tests

        /*
         * Start with MIN_VALUE, left shift, test high value, low
         * values, and random in between.
         *
         * Use nextAfter to calculate, high value of previous binade;
         * loop count i will indicate how many random bits, if any are
         * needed.
         */

        double top=Double.MIN_VALUE;
        for( int i = 1;
            i < DoubleConsts.SIGNIFICAND_WIDTH;
            i++, top *= 2.0f) {

            failures += testGetExponentCase(top,
                                            DoubleConsts.MIN_EXPONENT - 1);

            // Test largest value in next smaller binade
            if (i >= 3) {// (i == 1) would test 0.0;
                         // (i == 2) would just retest MIN_VALUE
                testGetExponentCase(Math.nextAfter(top, 0.0),
                                    DoubleConsts.MIN_EXPONENT - 1);

                if( i >= 10) {
                    // create a bit mask with (i-1) 1's in the low order
                    // bits
                    long mask = ~((~0L)<<(i-1));
                    double randFloat = Double.longBitsToDouble( // Exponent
                                                 Double.doubleToLongBits(top) |
                                                 // Significand
                                                 (rand.nextLong() & mask ) ) ;

                    failures += testGetExponentCase(randFloat,
                                                    DoubleConsts.MIN_EXPONENT - 1);
                }
            }
        }

        return failures;
    }


    /* ******************** nextAfter tests ****************************** */

    static int testNextAfterCase(float start, double direction, float expected) {
        int failures=0;
        float minus_start = -start;
        double minus_direction = -direction;
        float minus_expected = -expected;

        failures+=Tests.test("Math.nextAfter(float,double)", start, direction,
                             Math.nextAfter(start, direction), expected);
        failures+=Tests.test("Math.nextAfter(float,double)", minus_start, minus_direction,
                             Math.nextAfter(minus_start, minus_direction), minus_expected);

        failures+=Tests.test("StrictMath.nextAfter(float,double)", start, direction,
                             StrictMath.nextAfter(start, direction), expected);
        failures+=Tests.test("StrictMath.nextAfter(float,double)", minus_start, minus_direction,
                             StrictMath.nextAfter(minus_start, minus_direction), minus_expected);
        return failures;
    }

    static int testNextAfterCase(double start, double direction, double expected) {
        int failures=0;

        double minus_start = -start;
        double minus_direction = -direction;
        double minus_expected = -expected;

        failures+=Tests.test("Math.nextAfter(double,double)", start, direction,
                             Math.nextAfter(start, direction), expected);
        failures+=Tests.test("Math.nextAfter(double,double)", minus_start, minus_direction,
                             Math.nextAfter(minus_start, minus_direction), minus_expected);

        failures+=Tests.test("StrictMath.nextAfter(double,double)", start, direction,
                             StrictMath.nextAfter(start, direction), expected);
        failures+=Tests.test("StrictMath.nextAfter(double,double)", minus_start, minus_direction,
                             StrictMath.nextAfter(minus_start, minus_direction), minus_expected);
        return failures;
    }

    public static int testFloatNextAfter() {
        int failures=0;

        /*
         * Each row of the testCases matrix represents one test case
         * for nexAfter; given the input of the first two columns, the
         * result in the last column is expected.
         */
        float [][] testCases  = {
            {NaNf,              NaNf,                   NaNf},
            {NaNf,              0.0f,                   NaNf},
            {0.0f,              NaNf,                   NaNf},
            {NaNf,              infinityF,              NaNf},
            {infinityF,         NaNf,                   NaNf},

            {infinityF,         infinityF,              infinityF},
            {infinityF,         -infinityF,             Float.MAX_VALUE},
            {infinityF,         0.0f,                   Float.MAX_VALUE},

            {Float.MAX_VALUE,   infinityF,              infinityF},
            {Float.MAX_VALUE,   -infinityF,             Float_MAX_VALUEmm},
            {Float.MAX_VALUE,   Float.MAX_VALUE,        Float.MAX_VALUE},
            {Float.MAX_VALUE,   0.0f,                   Float_MAX_VALUEmm},

            {Float_MAX_VALUEmm, Float.MAX_VALUE,        Float.MAX_VALUE},
            {Float_MAX_VALUEmm, infinityF,              Float.MAX_VALUE},
            {Float_MAX_VALUEmm, Float_MAX_VALUEmm,      Float_MAX_VALUEmm},

            {FloatConsts.MIN_NORMAL,    infinityF,              FloatConsts.MIN_NORMAL+
                                                                Float.MIN_VALUE},
            {FloatConsts.MIN_NORMAL,    -infinityF,             Float_MAX_SUBNORMAL},
            {FloatConsts.MIN_NORMAL,    1.0f,                   FloatConsts.MIN_NORMAL+
                                                                Float.MIN_VALUE},
            {FloatConsts.MIN_NORMAL,    -1.0f,                  Float_MAX_SUBNORMAL},
            {FloatConsts.MIN_NORMAL,    FloatConsts.MIN_NORMAL, FloatConsts.MIN_NORMAL},

            {Float_MAX_SUBNORMAL,       FloatConsts.MIN_NORMAL, FloatConsts.MIN_NORMAL},
            {Float_MAX_SUBNORMAL,       Float_MAX_SUBNORMAL,    Float_MAX_SUBNORMAL},
            {Float_MAX_SUBNORMAL,       0.0f,                   Float_MAX_SUBNORMALmm},

            {Float_MAX_SUBNORMALmm,     Float_MAX_SUBNORMAL,    Float_MAX_SUBNORMAL},
            {Float_MAX_SUBNORMALmm,     0.0f,                   Float_MAX_SUBNORMALmm-Float.MIN_VALUE},
            {Float_MAX_SUBNORMALmm,     Float_MAX_SUBNORMALmm,  Float_MAX_SUBNORMALmm},

            {Float.MIN_VALUE,   0.0f,                   0.0f},
            {-Float.MIN_VALUE,  0.0f,                   -0.0f},
            {Float.MIN_VALUE,   Float.MIN_VALUE,        Float.MIN_VALUE},
            {Float.MIN_VALUE,   1.0f,                   2*Float.MIN_VALUE},

            // Make sure zero behavior is tested
            {0.0f,              0.0f,                   0.0f},
            {0.0f,              -0.0f,                  -0.0f},
            {-0.0f,             0.0f,                   0.0f},
            {-0.0f,             -0.0f,                  -0.0f},
            {0.0f,              infinityF,              Float.MIN_VALUE},
            {0.0f,              -infinityF,             -Float.MIN_VALUE},
            {-0.0f,             infinityF,              Float.MIN_VALUE},
            {-0.0f,             -infinityF,             -Float.MIN_VALUE},
            {0.0f,              Float.MIN_VALUE,        Float.MIN_VALUE},
            {0.0f,              -Float.MIN_VALUE,       -Float.MIN_VALUE},
            {-0.0f,             Float.MIN_VALUE,        Float.MIN_VALUE},
            {-0.0f,             -Float.MIN_VALUE,       -Float.MIN_VALUE}
        };

        for(int i = 0; i < testCases.length; i++) {
            failures += testNextAfterCase(testCases[i][0], testCases[i][1],
                                          testCases[i][2]);
        }

        return failures;
    }

    public static int testDoubleNextAfter() {
        int failures =0;

        /*
         * Each row of the testCases matrix represents one test case
         * for nexAfter; given the input of the first two columns, the
         * result in the last column is expected.
         */
        double [][] testCases  = {
            {NaNd,              NaNd,                   NaNd},
            {NaNd,              0.0d,                   NaNd},
            {0.0d,              NaNd,                   NaNd},
            {NaNd,              infinityD,              NaNd},
            {infinityD,         NaNd,                   NaNd},

            {infinityD,         infinityD,              infinityD},
            {infinityD,         -infinityD,             Double.MAX_VALUE},
            {infinityD,         0.0d,                   Double.MAX_VALUE},

            {Double.MAX_VALUE,  infinityD,              infinityD},
            {Double.MAX_VALUE,  -infinityD,             Double_MAX_VALUEmm},
            {Double.MAX_VALUE,  Double.MAX_VALUE,       Double.MAX_VALUE},
            {Double.MAX_VALUE,  0.0d,                   Double_MAX_VALUEmm},

            {Double_MAX_VALUEmm,        Double.MAX_VALUE,       Double.MAX_VALUE},
            {Double_MAX_VALUEmm,        infinityD,              Double.MAX_VALUE},
            {Double_MAX_VALUEmm,        Double_MAX_VALUEmm,     Double_MAX_VALUEmm},

            {DoubleConsts.MIN_NORMAL,   infinityD,              DoubleConsts.MIN_NORMAL+
                                                                Double.MIN_VALUE},
            {DoubleConsts.MIN_NORMAL,   -infinityD,             Double_MAX_SUBNORMAL},
            {DoubleConsts.MIN_NORMAL,   1.0f,                   DoubleConsts.MIN_NORMAL+
                                                                Double.MIN_VALUE},
            {DoubleConsts.MIN_NORMAL,   -1.0f,                  Double_MAX_SUBNORMAL},
            {DoubleConsts.MIN_NORMAL,   DoubleConsts.MIN_NORMAL,DoubleConsts.MIN_NORMAL},

            {Double_MAX_SUBNORMAL,      DoubleConsts.MIN_NORMAL,DoubleConsts.MIN_NORMAL},
            {Double_MAX_SUBNORMAL,      Double_MAX_SUBNORMAL,   Double_MAX_SUBNORMAL},
            {Double_MAX_SUBNORMAL,      0.0d,                   Double_MAX_SUBNORMALmm},

            {Double_MAX_SUBNORMALmm,    Double_MAX_SUBNORMAL,   Double_MAX_SUBNORMAL},
            {Double_MAX_SUBNORMALmm,    0.0d,                   Double_MAX_SUBNORMALmm-Double.MIN_VALUE},
            {Double_MAX_SUBNORMALmm,    Double_MAX_SUBNORMALmm, Double_MAX_SUBNORMALmm},

            {Double.MIN_VALUE,  0.0d,                   0.0d},
            {-Double.MIN_VALUE, 0.0d,                   -0.0d},
            {Double.MIN_VALUE,  Double.MIN_VALUE,       Double.MIN_VALUE},
            {Double.MIN_VALUE,  1.0f,                   2*Double.MIN_VALUE},

            // Make sure zero behavior is tested
            {0.0d,              0.0d,                   0.0d},
            {0.0d,              -0.0d,                  -0.0d},
            {-0.0d,             0.0d,                   0.0d},
            {-0.0d,             -0.0d,                  -0.0d},
            {0.0d,              infinityD,              Double.MIN_VALUE},
            {0.0d,              -infinityD,             -Double.MIN_VALUE},
            {-0.0d,             infinityD,              Double.MIN_VALUE},
            {-0.0d,             -infinityD,             -Double.MIN_VALUE},
            {0.0d,              Double.MIN_VALUE,       Double.MIN_VALUE},
            {0.0d,              -Double.MIN_VALUE,      -Double.MIN_VALUE},
            {-0.0d,             Double.MIN_VALUE,       Double.MIN_VALUE},
            {-0.0d,             -Double.MIN_VALUE,      -Double.MIN_VALUE}
        };

        for(int i = 0; i < testCases.length; i++) {
            failures += testNextAfterCase(testCases[i][0], testCases[i][1],
                                          testCases[i][2]);
        }
        return failures;
    }

    /* ******************** nextUp tests ********************************* */

    public static int testFloatNextUp() {
        int failures=0;

        /*
         * Each row of testCases represents one test case for nextUp;
         * the first column is the input and the second column is the
         * expected result.
         */
        float testCases [][] = {
            {NaNf,                      NaNf},
            {-infinityF,                -Float.MAX_VALUE},
            {-Float.MAX_VALUE,          -Float_MAX_VALUEmm},
            {-FloatConsts.MIN_NORMAL,   -Float_MAX_SUBNORMAL},
            {-Float_MAX_SUBNORMAL,      -Float_MAX_SUBNORMALmm},
            {-Float.MIN_VALUE,          -0.0f},
            {-0.0f,                     Float.MIN_VALUE},
            {+0.0f,                     Float.MIN_VALUE},
            {Float.MIN_VALUE,           Float.MIN_VALUE*2},
            {Float_MAX_SUBNORMALmm,     Float_MAX_SUBNORMAL},
            {Float_MAX_SUBNORMAL,       FloatConsts.MIN_NORMAL},
            {FloatConsts.MIN_NORMAL,    FloatConsts.MIN_NORMAL+Float.MIN_VALUE},
            {Float_MAX_VALUEmm,         Float.MAX_VALUE},
            {Float.MAX_VALUE,           infinityF},
            {infinityF,                 infinityF}
        };

        for(int i = 0; i < testCases.length; i++) {
            failures+=Tests.test("Math.nextUp(float)",
                                 testCases[i][0], Math.nextUp(testCases[i][0]), testCases[i][1]);

            failures+=Tests.test("StrictMath.nextUp(float)",
                                 testCases[i][0], StrictMath.nextUp(testCases[i][0]), testCases[i][1]);
        }

        return failures;
    }


    public static int testDoubleNextUp() {
        int failures=0;

        /*
         * Each row of testCases represents one test case for nextUp;
         * the first column is the input and the second column is the
         * expected result.
         */
        double testCases [][] = {
            {NaNd,                      NaNd},
            {-infinityD,                -Double.MAX_VALUE},
            {-Double.MAX_VALUE,         -Double_MAX_VALUEmm},
            {-DoubleConsts.MIN_NORMAL,  -Double_MAX_SUBNORMAL},
            {-Double_MAX_SUBNORMAL,     -Double_MAX_SUBNORMALmm},
            {-Double.MIN_VALUE,         -0.0d},
            {-0.0d,                     Double.MIN_VALUE},
            {+0.0d,                     Double.MIN_VALUE},
            {Double.MIN_VALUE,          Double.MIN_VALUE*2},
            {Double_MAX_SUBNORMALmm,    Double_MAX_SUBNORMAL},
            {Double_MAX_SUBNORMAL,      DoubleConsts.MIN_NORMAL},
            {DoubleConsts.MIN_NORMAL,   DoubleConsts.MIN_NORMAL+Double.MIN_VALUE},
            {Double_MAX_VALUEmm,        Double.MAX_VALUE},
            {Double.MAX_VALUE,          infinityD},
            {infinityD,                 infinityD}
        };

        for(int i = 0; i < testCases.length; i++) {
            failures+=Tests.test("Math.nextUp(double)",
                                 testCases[i][0], Math.nextUp(testCases[i][0]), testCases[i][1]);

            failures+=Tests.test("StrictMath.nextUp(double)",
                                 testCases[i][0], StrictMath.nextUp(testCases[i][0]), testCases[i][1]);
        }

        return failures;
    }

    /* ******************** nextDown tests ********************************* */

    public static int testFloatNextDown() {
        int failures=0;

        /*
         * Each row of testCases represents one test case for nextDown;
         * the first column is the input and the second column is the
         * expected result.
         */
        float testCases [][] = {
            {NaNf,                      NaNf},
            {-infinityF,                -infinityF},
            {-Float.MAX_VALUE,          -infinityF},
            {-Float_MAX_VALUEmm,        -Float.MAX_VALUE},
            {-Float_MAX_SUBNORMAL,      -FloatConsts.MIN_NORMAL},
            {-Float_MAX_SUBNORMALmm,    -Float_MAX_SUBNORMAL},
            {-0.0f,                     -Float.MIN_VALUE},
            {+0.0f,                     -Float.MIN_VALUE},
            {Float.MIN_VALUE,           0.0f},
            {Float.MIN_VALUE*2,         Float.MIN_VALUE},
            {Float_MAX_SUBNORMAL,       Float_MAX_SUBNORMALmm},
            {FloatConsts.MIN_NORMAL,    Float_MAX_SUBNORMAL},
            {FloatConsts.MIN_NORMAL+
             Float.MIN_VALUE,           FloatConsts.MIN_NORMAL},
            {Float.MAX_VALUE,           Float_MAX_VALUEmm},
            {infinityF,                 Float.MAX_VALUE},
        };

        for(int i = 0; i < testCases.length; i++) {
            failures+=Tests.test("Math.nextDown(float)",
                                 testCases[i][0], Math.nextDown(testCases[i][0]), testCases[i][1]);

            failures+=Tests.test("StrictMath.nextDown(float)",
                                 testCases[i][0], StrictMath.nextDown(testCases[i][0]), testCases[i][1]);
        }

        return failures;
    }


    public static int testDoubleNextDown() {
        int failures=0;

        /*
         * Each row of testCases represents one test case for nextDown;
         * the first column is the input and the second column is the
         * expected result.
         */
        double testCases [][] = {
            {NaNd,                      NaNd},
            {-infinityD,                -infinityD},
            {-Double.MAX_VALUE,         -infinityD},
            {-Double_MAX_VALUEmm,       -Double.MAX_VALUE},
            {-Double_MAX_SUBNORMAL,     -DoubleConsts.MIN_NORMAL},
            {-Double_MAX_SUBNORMALmm,   -Double_MAX_SUBNORMAL},
            {-0.0d,                     -Double.MIN_VALUE},
            {+0.0d,                     -Double.MIN_VALUE},
            {Double.MIN_VALUE,          0.0d},
            {Double.MIN_VALUE*2,        Double.MIN_VALUE},
            {Double_MAX_SUBNORMAL,      Double_MAX_SUBNORMALmm},
            {DoubleConsts.MIN_NORMAL,   Double_MAX_SUBNORMAL},
            {DoubleConsts.MIN_NORMAL+
             Double.MIN_VALUE,          DoubleConsts.MIN_NORMAL},
            {Double.MAX_VALUE,          Double_MAX_VALUEmm},
            {infinityD,                 Double.MAX_VALUE},
        };

        for(int i = 0; i < testCases.length; i++) {
            failures+=Tests.test("Math.nextDown(double)",
                                 testCases[i][0], Math.nextDown(testCases[i][0]), testCases[i][1]);

            failures+=Tests.test("StrictMath.nextDown(double)",
                                 testCases[i][0], StrictMath.nextDown(testCases[i][0]), testCases[i][1]);
        }

        return failures;
    }


    /* ********************** boolean tests ****************************** */

    /*
     * Combined tests for boolean functions, isFinite, isInfinite,
     * isNaN, isUnordered.
     */

    public static int testFloatBooleanMethods() {
        int failures = 0;

        float testCases [] = {
            NaNf,
            -infinityF,
            infinityF,
            -Float.MAX_VALUE,
            -3.0f,
            -1.0f,
            -FloatConsts.MIN_NORMAL,
            -Float_MAX_SUBNORMALmm,
            -Float_MAX_SUBNORMAL,
            -Float.MIN_VALUE,
            -0.0f,
            +0.0f,
            Float.MIN_VALUE,
            Float_MAX_SUBNORMALmm,
            Float_MAX_SUBNORMAL,
            FloatConsts.MIN_NORMAL,
            1.0f,
            3.0f,
            Float_MAX_VALUEmm,
            Float.MAX_VALUE
        };

        for(int i = 0; i < testCases.length; i++) {
            // isNaN
            failures+=Tests.test("FpUtils.isNaN(float)", testCases[i],
                                 FpUtils.isNaN(testCases[i]), (i ==0));

            // isFinite
            failures+=Tests.test("Float.isFinite(float)", testCases[i],
                                 Float.isFinite(testCases[i]), (i >= 3));

            // isInfinite
            failures+=Tests.test("FpUtils.isInfinite(float)", testCases[i],
                                 FpUtils.isInfinite(testCases[i]), (i==1 || i==2));

            // isUnorderd
            for(int j = 0; j < testCases.length; j++) {
                failures+=Tests.test("FpUtils.isUnordered(float, float)", testCases[i],testCases[j],
                                     FpUtils.isUnordered(testCases[i],testCases[j]), (i==0 || j==0));
            }
        }

        return failures;
    }

    public static int testDoubleBooleanMethods() {
        int failures = 0;
        boolean result = false;

        double testCases [] = {
            NaNd,
            -infinityD,
            infinityD,
            -Double.MAX_VALUE,
            -3.0d,
            -1.0d,
            -DoubleConsts.MIN_NORMAL,
            -Double_MAX_SUBNORMALmm,
            -Double_MAX_SUBNORMAL,
            -Double.MIN_VALUE,
            -0.0d,
            +0.0d,
            Double.MIN_VALUE,
            Double_MAX_SUBNORMALmm,
            Double_MAX_SUBNORMAL,
            DoubleConsts.MIN_NORMAL,
            1.0d,
            3.0d,
            Double_MAX_VALUEmm,
            Double.MAX_VALUE
        };

        for(int i = 0; i < testCases.length; i++) {
            // isNaN
            failures+=Tests.test("FpUtils.isNaN(double)", testCases[i],
                                 FpUtils.isNaN(testCases[i]), (i ==0));

            // isFinite
            failures+=Tests.test("Double.isFinite(double)", testCases[i],
                                 Double.isFinite(testCases[i]), (i >= 3));

            // isInfinite
            failures+=Tests.test("FpUtils.isInfinite(double)", testCases[i],
                                 FpUtils.isInfinite(testCases[i]), (i==1 || i==2));

            // isUnorderd
            for(int j = 0; j < testCases.length; j++) {
                failures+=Tests.test("FpUtils.isUnordered(double, double)", testCases[i],testCases[j],
                                     FpUtils.isUnordered(testCases[i],testCases[j]), (i==0 || j==0));
            }
        }

        return failures;
    }

    /* ******************** copySign tests******************************** */

   public static int testFloatCopySign() {
        int failures = 0;

        // testCases[0] are logically positive numbers;
        // testCases[1] are negative numbers.
        float testCases [][] = {
            {+0.0f,
             Float.MIN_VALUE,
             Float_MAX_SUBNORMALmm,
             Float_MAX_SUBNORMAL,
             FloatConsts.MIN_NORMAL,
             1.0f,
             3.0f,
             Float_MAX_VALUEmm,
             Float.MAX_VALUE,
             infinityF,
            },
            {-infinityF,
             -Float.MAX_VALUE,
             -3.0f,
             -1.0f,
             -FloatConsts.MIN_NORMAL,
             -Float_MAX_SUBNORMALmm,
             -Float_MAX_SUBNORMAL,
             -Float.MIN_VALUE,
             -0.0f}
        };

        float NaNs[] = {Float.intBitsToFloat(0x7fc00000),       // "positive" NaN
                        Float.intBitsToFloat(0xFfc00000)};      // "negative" NaN

        // Tests shared between raw and non-raw versions
        for(int i = 0; i < 2; i++) {
            for(int j = 0; j < 2; j++) {
                for(int m = 0; m < testCases[i].length; m++) {
                    for(int n = 0; n < testCases[j].length; n++) {
                        // copySign(magnitude, sign)
                        failures+=Tests.test("Math.copySign(float,float)",
                                             testCases[i][m],testCases[j][n],
                                             Math.copySign(testCases[i][m], testCases[j][n]),
                                             (j==0?1.0f:-1.0f)*Math.abs(testCases[i][m]) );

                        failures+=Tests.test("StrictMath.copySign(float,float)",
                                             testCases[i][m],testCases[j][n],
                                             StrictMath.copySign(testCases[i][m], testCases[j][n]),
                                             (j==0?1.0f:-1.0f)*Math.abs(testCases[i][m]) );
                    }
                }
            }
        }

        // For rawCopySign, NaN may effectively have either sign bit
        // while for copySign NaNs are treated as if they always have
        // a zero sign bit (i.e. as positive numbers)
        for(int i = 0; i < 2; i++) {
            for(int j = 0; j < NaNs.length; j++) {
                for(int m = 0; m < testCases[i].length; m++) {
                    // copySign(magnitude, sign)

                    failures += (Math.abs(Math.copySign(testCases[i][m], NaNs[j])) ==
                                 Math.abs(testCases[i][m])) ? 0:1;


                    failures+=Tests.test("StrictMath.copySign(float,float)",
                                         testCases[i][m], NaNs[j],
                                         StrictMath.copySign(testCases[i][m], NaNs[j]),
                                         Math.abs(testCases[i][m]) );
                }
            }
        }

        return failures;
    }

    public static int testDoubleCopySign() {
        int failures = 0;

        // testCases[0] are logically positive numbers;
        // testCases[1] are negative numbers.
        double testCases [][] = {
            {+0.0d,
             Double.MIN_VALUE,
             Double_MAX_SUBNORMALmm,
             Double_MAX_SUBNORMAL,
             DoubleConsts.MIN_NORMAL,
             1.0d,
             3.0d,
             Double_MAX_VALUEmm,
             Double.MAX_VALUE,
             infinityD,
            },
            {-infinityD,
             -Double.MAX_VALUE,
             -3.0d,
             -1.0d,
             -DoubleConsts.MIN_NORMAL,
             -Double_MAX_SUBNORMALmm,
             -Double_MAX_SUBNORMAL,
             -Double.MIN_VALUE,
             -0.0d}
        };

        double NaNs[] = {Double.longBitsToDouble(0x7ff8000000000000L),  // "positive" NaN
                         Double.longBitsToDouble(0xfff8000000000000L),  // "negative" NaN
                         Double.longBitsToDouble(0x7FF0000000000001L),
                         Double.longBitsToDouble(0xFFF0000000000001L),
                         Double.longBitsToDouble(0x7FF8555555555555L),
                         Double.longBitsToDouble(0xFFF8555555555555L),
                         Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL),
                         Double.longBitsToDouble(0xFFFFFFFFFFFFFFFFL),
                         Double.longBitsToDouble(0x7FFDeadBeef00000L),
                         Double.longBitsToDouble(0xFFFDeadBeef00000L),
                         Double.longBitsToDouble(0x7FFCafeBabe00000L),
                         Double.longBitsToDouble(0xFFFCafeBabe00000L)};

        // Tests shared between Math and StrictMath versions
        for(int i = 0; i < 2; i++) {
            for(int j = 0; j < 2; j++) {
                for(int m = 0; m < testCases[i].length; m++) {
                    for(int n = 0; n < testCases[j].length; n++) {
                        // copySign(magnitude, sign)
                        failures+=Tests.test("MathcopySign(double,double)",
                                             testCases[i][m],testCases[j][n],
                                             Math.copySign(testCases[i][m], testCases[j][n]),
                                             (j==0?1.0f:-1.0f)*Math.abs(testCases[i][m]) );

                        failures+=Tests.test("StrictMath.copySign(double,double)",
                                             testCases[i][m],testCases[j][n],
                                             StrictMath.copySign(testCases[i][m], testCases[j][n]),
                                             (j==0?1.0f:-1.0f)*Math.abs(testCases[i][m]) );
                    }
                }
            }
        }

        // For Math.copySign, NaN may effectively have either sign bit
        // while for StrictMath.copySign NaNs are treated as if they
        // always have a zero sign bit (i.e. as positive numbers)
        for(int i = 0; i < 2; i++) {
            for(int j = 0; j < NaNs.length; j++) {
                for(int m = 0; m < testCases[i].length; m++) {
                    // copySign(magnitude, sign)

                    failures += (Math.abs(Math.copySign(testCases[i][m], NaNs[j])) ==
                                 Math.abs(testCases[i][m])) ? 0:1;


                    failures+=Tests.test("StrictMath.copySign(double,double)",
                                         testCases[i][m], NaNs[j],
                                         StrictMath.copySign(testCases[i][m], NaNs[j]),
                                         Math.abs(testCases[i][m]) );
                }
            }
        }


        return failures;
    }

    /* ************************ scalb tests ******************************* */

    static int testScalbCase(float value, int scale_factor, float expected) {
        int failures=0;

        failures+=Tests.test("Math.scalb(float,int)",
                             value, scale_factor,
                             Math.scalb(value, scale_factor), expected);

        failures+=Tests.test("Math.scalb(float,int)",
                             -value, scale_factor,
                             Math.scalb(-value, scale_factor), -expected);

        failures+=Tests.test("StrictMath.scalb(float,int)",
                             value, scale_factor,
                             StrictMath.scalb(value, scale_factor), expected);

        failures+=Tests.test("StrictMath.scalb(float,int)",
                             -value, scale_factor,
                             StrictMath.scalb(-value, scale_factor), -expected);
        return failures;
    }

    public static int testFloatScalb() {
        int failures=0;
        int MAX_SCALE = FloatConsts.MAX_EXPONENT + -FloatConsts.MIN_EXPONENT +
                        FloatConsts.SIGNIFICAND_WIDTH + 1;


        // Arguments x, where scalb(x,n) is x for any n.
        float [] identityTestCases = {NaNf,
                                      -0.0f,
                                      +0.0f,
                                      infinityF,
                                      -infinityF
        };

        float [] subnormalTestCases = {
            Float.MIN_VALUE,
            3.0f*Float.MIN_VALUE,
            Float_MAX_SUBNORMALmm,
            Float_MAX_SUBNORMAL
        };

        float [] someTestCases = {
            Float.MIN_VALUE,
            3.0f*Float.MIN_VALUE,
            Float_MAX_SUBNORMALmm,
            Float_MAX_SUBNORMAL,
            FloatConsts.MIN_NORMAL,
            1.0f,
            2.0f,
            3.0f,
            (float)Math.PI,
            Float_MAX_VALUEmm,
            Float.MAX_VALUE
        };

        int [] oneMultiplyScalingFactors = {
            FloatConsts.MIN_EXPONENT,
            FloatConsts.MIN_EXPONENT+1,
            -3,
            -2,
            -1,
            0,
            1,
            2,
            3,
            FloatConsts.MAX_EXPONENT-1,
            FloatConsts.MAX_EXPONENT
        };

        int [] manyScalingFactors = {
            Integer.MIN_VALUE,
            Integer.MIN_VALUE+1,
            -MAX_SCALE -1,
            -MAX_SCALE,
            -MAX_SCALE+1,

            2*FloatConsts.MIN_EXPONENT-1,       // -253
            2*FloatConsts.MIN_EXPONENT,         // -252
            2*FloatConsts.MIN_EXPONENT+1,       // -251

            FpUtils.ilogb(Float.MIN_VALUE)-1,   // -150
            FpUtils.ilogb(Float.MIN_VALUE),     // -149
            -FloatConsts.MAX_EXPONENT,          // -127
            FloatConsts.MIN_EXPONENT,           // -126

            -2,
            -1,
            0,
            1,
            2,

            FloatConsts.MAX_EXPONENT-1,         // 126
            FloatConsts.MAX_EXPONENT,           // 127
            FloatConsts.MAX_EXPONENT+1,         // 128

            2*FloatConsts.MAX_EXPONENT-1,       // 253
            2*FloatConsts.MAX_EXPONENT,         // 254
            2*FloatConsts.MAX_EXPONENT+1,       // 255

            MAX_SCALE-1,
            MAX_SCALE,
            MAX_SCALE+1,
            Integer.MAX_VALUE-1,
            Integer.MAX_VALUE
        };

        // Test cases where scaling is always a no-op
        for(int i=0; i < identityTestCases.length; i++) {
            for(int j=0; j < manyScalingFactors.length; j++) {
                failures += testScalbCase(identityTestCases[i],
                                          manyScalingFactors[j],
                                          identityTestCases[i]);
            }
        }

        // Test cases where result is 0.0 or infinity due to magnitude
        // of the scaling factor
        for(int i=0; i < someTestCases.length; i++) {
            for(int j=0; j < manyScalingFactors.length; j++) {
                int scaleFactor = manyScalingFactors[j];
                if (Math.abs(scaleFactor) >= MAX_SCALE) {
                    float value = someTestCases[i];
                    failures+=testScalbCase(value,
                                            scaleFactor,
                                            Math.copySign( (scaleFactor>0?infinityF:0.0f), value) );
                }
            }
        }

        // Test cases that could be done with one floating-point
        // multiply.
        for(int i=0; i < someTestCases.length; i++) {
            for(int j=0; j < oneMultiplyScalingFactors.length; j++) {
                int scaleFactor = oneMultiplyScalingFactors[j];
                    float value = someTestCases[i];

                    failures+=testScalbCase(value,
                                            scaleFactor,
                                            value*powerOfTwoF(scaleFactor));
            }
        }

        // Create 2^MAX_EXPONENT
        float twoToTheMaxExp = 1.0f; // 2^0
        for(int i = 0; i < FloatConsts.MAX_EXPONENT; i++)
            twoToTheMaxExp *=2.0f;

        // Scale-up subnormal values until they all overflow
        for(int i=0; i < subnormalTestCases.length; i++) {
            float scale = 1.0f; // 2^j
            float value = subnormalTestCases[i];

            for(int j=FloatConsts.MAX_EXPONENT*2; j < MAX_SCALE; j++) { // MAX_SCALE -1 should cause overflow
                int scaleFactor = j;

                failures+=testScalbCase(value,
                                        scaleFactor,
                                        (FpUtils.ilogb(value) +j > FloatConsts.MAX_EXPONENT ) ?
                                        Math.copySign(infinityF, value) : // overflow
                                        // calculate right answer
                                        twoToTheMaxExp*(twoToTheMaxExp*(scale*value)) );
                scale*=2.0f;
            }
        }

        // Scale down a large number until it underflows.  By scaling
        // down MAX_NORMALmm, the first subnormal result will be exact
        // but the next one will round -- all those results can be
        // checked by halving a separate value in the loop.  Actually,
        // we can keep halving and checking until the product is zero
        // since:
        //
        // 1. If the scalb of MAX_VALUEmm is subnormal and *not* exact
        // it will round *up*
        //
        // 2. When rounding first occurs in the expected product, it
        // too rounds up, to 2^-MAX_EXPONENT.
        //
        // Halving expected after rounding happends to give the same
        // result as the scalb operation.
        float expected = Float_MAX_VALUEmm *0.5f;
        for(int i = -1; i > -MAX_SCALE; i--) {
            failures+=testScalbCase(Float_MAX_VALUEmm, i, expected);

            expected *= 0.5f;
        }

        // Tricky rounding tests:
        // Scale down a large number into subnormal range such that if
        // scalb is being implemented with multiple floating-point
        // multiplies, the value would round twice if the multiplies
        // were done in the wrong order.

        float value = 0x8.0000bP-5f;
        expected = 0x1.00001p-129f;

        for(int i = 0; i < 129; i++) {
            failures+=testScalbCase(value,
                                    -127-i,
                                    expected);
            value *=2.0f;
        }

        return failures;
    }

    static int testScalbCase(double value, int scale_factor, double expected) {
        int failures=0;

        failures+=Tests.test("Math.scalb(double,int)",
                             value, scale_factor,
                             Math.scalb(value, scale_factor), expected);

        failures+=Tests.test("Math.scalb(double,int)",
                             -value, scale_factor,
                             Math.scalb(-value, scale_factor), -expected);

        failures+=Tests.test("StrictMath.scalb(double,int)",
                             value, scale_factor,
                             StrictMath.scalb(value, scale_factor), expected);

        failures+=Tests.test("StrictMath.scalb(double,int)",
                             -value, scale_factor,
                             StrictMath.scalb(-value, scale_factor), -expected);

        return failures;
    }

    public static int testDoubleScalb() {
        int failures=0;
        int MAX_SCALE = DoubleConsts.MAX_EXPONENT + -DoubleConsts.MIN_EXPONENT +
                        DoubleConsts.SIGNIFICAND_WIDTH + 1;


        // Arguments x, where scalb(x,n) is x for any n.
        double [] identityTestCases = {NaNd,
                                      -0.0,
                                      +0.0,
                                      infinityD,
        };

        double [] subnormalTestCases = {
            Double.MIN_VALUE,
            3.0d*Double.MIN_VALUE,
            Double_MAX_SUBNORMALmm,
            Double_MAX_SUBNORMAL
        };

        double [] someTestCases = {
            Double.MIN_VALUE,
            3.0d*Double.MIN_VALUE,
            Double_MAX_SUBNORMALmm,
            Double_MAX_SUBNORMAL,
            DoubleConsts.MIN_NORMAL,
            1.0d,
            2.0d,
            3.0d,
            Math.PI,
            Double_MAX_VALUEmm,
            Double.MAX_VALUE
        };

        int [] oneMultiplyScalingFactors = {
            DoubleConsts.MIN_EXPONENT,
            DoubleConsts.MIN_EXPONENT+1,
            -3,
            -2,
            -1,
            0,
            1,
            2,
            3,
            DoubleConsts.MAX_EXPONENT-1,
            DoubleConsts.MAX_EXPONENT
        };

        int [] manyScalingFactors = {
            Integer.MIN_VALUE,
            Integer.MIN_VALUE+1,
            -MAX_SCALE -1,
            -MAX_SCALE,
            -MAX_SCALE+1,

            2*DoubleConsts.MIN_EXPONENT-1,      // -2045
            2*DoubleConsts.MIN_EXPONENT,        // -2044
            2*DoubleConsts.MIN_EXPONENT+1,      // -2043

            FpUtils.ilogb(Double.MIN_VALUE)-1,  // -1076
            FpUtils.ilogb(Double.MIN_VALUE),    // -1075
            -DoubleConsts.MAX_EXPONENT,         // -1023
            DoubleConsts.MIN_EXPONENT,          // -1022

            -2,
            -1,
            0,
            1,
            2,

            DoubleConsts.MAX_EXPONENT-1,        // 1022
            DoubleConsts.MAX_EXPONENT,          // 1023
            DoubleConsts.MAX_EXPONENT+1,        // 1024

            2*DoubleConsts.MAX_EXPONENT-1,      // 2045
            2*DoubleConsts.MAX_EXPONENT,        // 2046
            2*DoubleConsts.MAX_EXPONENT+1,      // 2047

            MAX_SCALE-1,
            MAX_SCALE,
            MAX_SCALE+1,
            Integer.MAX_VALUE-1,
            Integer.MAX_VALUE
        };

        // Test cases where scaling is always a no-op
        for(int i=0; i < identityTestCases.length; i++) {
            for(int j=0; j < manyScalingFactors.length; j++) {
                failures += testScalbCase(identityTestCases[i],
                                          manyScalingFactors[j],
                                          identityTestCases[i]);
            }
        }

        // Test cases where result is 0.0 or infinity due to magnitude
        // of the scaling factor
        for(int i=0; i < someTestCases.length; i++) {
            for(int j=0; j < manyScalingFactors.length; j++) {
                int scaleFactor = manyScalingFactors[j];
                if (Math.abs(scaleFactor) >= MAX_SCALE) {
                    double value = someTestCases[i];
                    failures+=testScalbCase(value,
                                            scaleFactor,
                                            Math.copySign( (scaleFactor>0?infinityD:0.0), value) );
                }
            }
        }

        // Test cases that could be done with one floating-point
        // multiply.
        for(int i=0; i < someTestCases.length; i++) {
            for(int j=0; j < oneMultiplyScalingFactors.length; j++) {
                int scaleFactor = oneMultiplyScalingFactors[j];
                    double value = someTestCases[i];

                    failures+=testScalbCase(value,
                                            scaleFactor,
                                            value*powerOfTwoD(scaleFactor));
            }
        }

        // Create 2^MAX_EXPONENT
        double twoToTheMaxExp = 1.0; // 2^0
        for(int i = 0; i < DoubleConsts.MAX_EXPONENT; i++)
            twoToTheMaxExp *=2.0;

        // Scale-up subnormal values until they all overflow
        for(int i=0; i < subnormalTestCases.length; i++) {
            double scale = 1.0; // 2^j
            double value = subnormalTestCases[i];

            for(int j=DoubleConsts.MAX_EXPONENT*2; j < MAX_SCALE; j++) { // MAX_SCALE -1 should cause overflow
                int scaleFactor = j;

                failures+=testScalbCase(value,
                                        scaleFactor,
                                        (FpUtils.ilogb(value) +j > DoubleConsts.MAX_EXPONENT ) ?
                                        Math.copySign(infinityD, value) : // overflow
                                        // calculate right answer
                                        twoToTheMaxExp*(twoToTheMaxExp*(scale*value)) );
                scale*=2.0;
            }
        }

        // Scale down a large number until it underflows.  By scaling
        // down MAX_NORMALmm, the first subnormal result will be exact
        // but the next one will round -- all those results can be
        // checked by halving a separate value in the loop.  Actually,
        // we can keep halving and checking until the product is zero
        // since:
        //
        // 1. If the scalb of MAX_VALUEmm is subnormal and *not* exact
        // it will round *up*
        //
        // 2. When rounding first occurs in the expected product, it
        // too rounds up, to 2^-MAX_EXPONENT.
        //
        // Halving expected after rounding happends to give the same
        // result as the scalb operation.
        double expected = Double_MAX_VALUEmm *0.5f;
        for(int i = -1; i > -MAX_SCALE; i--) {
            failures+=testScalbCase(Double_MAX_VALUEmm, i, expected);

            expected *= 0.5;
        }

        // Tricky rounding tests:
        // Scale down a large number into subnormal range such that if
        // scalb is being implemented with multiple floating-point
        // multiplies, the value would round twice if the multiplies
        // were done in the wrong order.

        double value = 0x1.000000000000bP-1;
        expected     = 0x0.2000000000001P-1022;
        for(int i = 0; i < DoubleConsts.MAX_EXPONENT+2; i++) {
            failures+=testScalbCase(value,
                                    -1024-i,
                                    expected);
            value *=2.0;
        }

        return failures;
    }

    /* ************************* ulp tests ******************************* */


    /*
     * Test Math.ulp and StrictMath.ulp with +d and -d.
     */
    static int testUlpCase(float f, float expected) {
        float minus_f = -f;
        int failures=0;

        failures+=Tests.test("Math.ulp(float)", f,
                             Math.ulp(f), expected);
        failures+=Tests.test("Math.ulp(float)", minus_f,
                             Math.ulp(minus_f), expected);
        failures+=Tests.test("StrictMath.ulp(float)", f,
                             StrictMath.ulp(f), expected);
        failures+=Tests.test("StrictMath.ulp(float)", minus_f,
                             StrictMath.ulp(minus_f), expected);
        return failures;
    }

    static int testUlpCase(double d, double expected) {
        double minus_d = -d;
        int failures=0;

        failures+=Tests.test("Math.ulp(double)", d,
                             Math.ulp(d), expected);
        failures+=Tests.test("Math.ulp(double)", minus_d,
                             Math.ulp(minus_d), expected);
        failures+=Tests.test("StrictMath.ulp(double)", d,
                             StrictMath.ulp(d), expected);
        failures+=Tests.test("StrictMath.ulp(double)", minus_d,
                             StrictMath.ulp(minus_d), expected);
        return failures;
    }

    public static int testFloatUlp() {
        int failures = 0;
        float [] specialValues = {NaNf,
                                  Float.POSITIVE_INFINITY,
                                  +0.0f,
                                  +1.0f,
                                  +2.0f,
                                  +16.0f,
                                  +Float.MIN_VALUE,
                                  +Float_MAX_SUBNORMAL,
                                  +FloatConsts.MIN_NORMAL,
                                  +Float.MAX_VALUE
        };

        float [] specialResults = {NaNf,
                                   Float.POSITIVE_INFINITY,
                                   Float.MIN_VALUE,
                                   powerOfTwoF(-23),
                                   powerOfTwoF(-22),
                                   powerOfTwoF(-19),
                                   Float.MIN_VALUE,
                                   Float.MIN_VALUE,
                                   Float.MIN_VALUE,
                                   powerOfTwoF(104)
        };

        // Special value tests
        for(int i = 0; i < specialValues.length; i++) {
            failures += testUlpCase(specialValues[i], specialResults[i]);
        }


        // Normal exponent tests
        for(int i = FloatConsts.MIN_EXPONENT; i <= FloatConsts.MAX_EXPONENT; i++) {
            float expected;

            // Create power of two
            float po2 = powerOfTwoF(i);
            expected = Math.scalb(1.0f, i - (FloatConsts.SIGNIFICAND_WIDTH-1));

            failures += testUlpCase(po2, expected);

            // Generate some random bit patterns for the significand
            for(int j = 0; j < 10; j++) {
                int randSignif = rand.nextInt();
                float randFloat;

                randFloat = Float.intBitsToFloat( // Exponent
                                                 (Float.floatToIntBits(po2)&
                                                  (~FloatConsts.SIGNIF_BIT_MASK)) |
                                                 // Significand
                                                 (randSignif &
                                                  FloatConsts.SIGNIF_BIT_MASK) );

                failures += testUlpCase(randFloat, expected);
            }

            if (i > FloatConsts.MIN_EXPONENT) {
                float po2minus = Math.nextAfter(po2,
                                                   Float.NEGATIVE_INFINITY);
                failures += testUlpCase(po2minus, expected/2.0f);
            }
        }

        // Subnormal tests

        /*
         * Start with MIN_VALUE, left shift, test high value, low
         * values, and random in between.
         *
         * Use nextAfter to calculate, high value of previous binade,
         * loop count i will indicate how many random bits, if any are
         * needed.
         */

        float top=Float.MIN_VALUE;
        for( int i = 1;
            i < FloatConsts.SIGNIFICAND_WIDTH;
            i++, top *= 2.0f) {

            failures += testUlpCase(top, Float.MIN_VALUE);

            // Test largest value in next smaller binade
            if (i >= 3) {// (i == 1) would test 0.0;
                         // (i == 2) would just retest MIN_VALUE
                testUlpCase(Math.nextAfter(top, 0.0f),
                            Float.MIN_VALUE);

                if( i >= 10) {
                    // create a bit mask with (i-1) 1's in the low order
                    // bits
                    int mask = ~((~0)<<(i-1));
                    float randFloat = Float.intBitsToFloat( // Exponent
                                                 Float.floatToIntBits(top) |
                                                 // Significand
                                                 (rand.nextInt() & mask ) ) ;

                    failures += testUlpCase(randFloat, Float.MIN_VALUE);
                }
            }
        }

        return failures;
    }

    public static int testDoubleUlp() {
        int failures = 0;
        double [] specialValues = {NaNd,
                                  Double.POSITIVE_INFINITY,
                                  +0.0d,
                                  +1.0d,
                                  +2.0d,
                                  +16.0d,
                                  +Double.MIN_VALUE,
                                  +Double_MAX_SUBNORMAL,
                                  +DoubleConsts.MIN_NORMAL,
                                  +Double.MAX_VALUE
        };

        double [] specialResults = {NaNf,
                                   Double.POSITIVE_INFINITY,
                                   Double.MIN_VALUE,
                                   powerOfTwoD(-52),
                                   powerOfTwoD(-51),
                                   powerOfTwoD(-48),
                                   Double.MIN_VALUE,
                                   Double.MIN_VALUE,
                                   Double.MIN_VALUE,
                                   powerOfTwoD(971)
        };

        // Special value tests
        for(int i = 0; i < specialValues.length; i++) {
            failures += testUlpCase(specialValues[i], specialResults[i]);
        }


        // Normal exponent tests
        for(int i = DoubleConsts.MIN_EXPONENT; i <= DoubleConsts.MAX_EXPONENT; i++) {
            double expected;

            // Create power of two
            double po2 = powerOfTwoD(i);
            expected = Math.scalb(1.0, i - (DoubleConsts.SIGNIFICAND_WIDTH-1));

            failures += testUlpCase(po2, expected);

            // Generate some random bit patterns for the significand
            for(int j = 0; j < 10; j++) {
                long randSignif = rand.nextLong();
                double randDouble;

                randDouble = Double.longBitsToDouble( // Exponent
                                                 (Double.doubleToLongBits(po2)&
                                                  (~DoubleConsts.SIGNIF_BIT_MASK)) |
                                                 // Significand
                                                 (randSignif &
                                                  DoubleConsts.SIGNIF_BIT_MASK) );

                failures += testUlpCase(randDouble, expected);
            }

            if (i > DoubleConsts.MIN_EXPONENT) {
                double po2minus = Math.nextAfter(po2,
                                                    Double.NEGATIVE_INFINITY);
                failures += testUlpCase(po2minus, expected/2.0f);
            }
        }

        // Subnormal tests

        /*
         * Start with MIN_VALUE, left shift, test high value, low
         * values, and random in between.
         *
         * Use nextAfter to calculate, high value of previous binade,
         * loop count i will indicate how many random bits, if any are
         * needed.
         */

        double top=Double.MIN_VALUE;
        for( int i = 1;
            i < DoubleConsts.SIGNIFICAND_WIDTH;
            i++, top *= 2.0f) {

            failures += testUlpCase(top, Double.MIN_VALUE);

            // Test largest value in next smaller binade
            if (i >= 3) {// (i == 1) would test 0.0;
                         // (i == 2) would just retest MIN_VALUE
                testUlpCase(Math.nextAfter(top, 0.0f),
                            Double.MIN_VALUE);

                if( i >= 10) {
                    // create a bit mask with (i-1) 1's in the low order
                    // bits
                    int mask = ~((~0)<<(i-1));
                    double randDouble = Double.longBitsToDouble( // Exponent
                                                 Double.doubleToLongBits(top) |
                                                 // Significand
                                                 (rand.nextLong() & mask ) ) ;

                    failures += testUlpCase(randDouble, Double.MIN_VALUE);
                }
            }
        }

        return failures;
    }

    public static int testFloatSignum() {
        int failures = 0;
        float testCases [][] = {
            {NaNf,                      NaNf},
            {-infinityF,                -1.0f},
            {-Float.MAX_VALUE,          -1.0f},
            {-FloatConsts.MIN_NORMAL,   -1.0f},
            {-1.0f,                     -1.0f},
            {-2.0f,                     -1.0f},
            {-Float_MAX_SUBNORMAL,      -1.0f},
            {-Float.MIN_VALUE,          -1.0f},
            {-0.0f,                     -0.0f},
            {+0.0f,                     +0.0f},
            {Float.MIN_VALUE,            1.0f},
            {Float_MAX_SUBNORMALmm,      1.0f},
            {Float_MAX_SUBNORMAL,        1.0f},
            {FloatConsts.MIN_NORMAL,     1.0f},
            {1.0f,                       1.0f},
            {2.0f,                       1.0f},
            {Float_MAX_VALUEmm,          1.0f},
            {Float.MAX_VALUE,            1.0f},
            {infinityF,                  1.0f}
        };

        for(int i = 0; i < testCases.length; i++) {
            failures+=Tests.test("Math.signum(float)",
                                 testCases[i][0], Math.signum(testCases[i][0]), testCases[i][1]);
            failures+=Tests.test("StrictMath.signum(float)",
                                 testCases[i][0], StrictMath.signum(testCases[i][0]), testCases[i][1]);
        }

        return failures;
    }

    public static int testDoubleSignum() {
        int failures = 0;
        double testCases [][] = {
            {NaNd,                      NaNd},
            {-infinityD,                -1.0},
            {-Double.MAX_VALUE,         -1.0},
            {-DoubleConsts.MIN_NORMAL,  -1.0},
            {-1.0,                      -1.0},
            {-2.0,                      -1.0},
            {-Double_MAX_SUBNORMAL,     -1.0},
            {-Double.MIN_VALUE,         -1.0d},
            {-0.0d,                     -0.0d},
            {+0.0d,                     +0.0d},
            {Double.MIN_VALUE,           1.0},
            {Double_MAX_SUBNORMALmm,     1.0},
            {Double_MAX_SUBNORMAL,       1.0},
            {DoubleConsts.MIN_NORMAL,    1.0},
            {1.0,                        1.0},
            {2.0,                        1.0},
            {Double_MAX_VALUEmm,         1.0},
            {Double.MAX_VALUE,           1.0},
            {infinityD,                  1.0}
        };

        for(int i = 0; i < testCases.length; i++) {
            failures+=Tests.test("Math.signum(double)",
                                 testCases[i][0], Math.signum(testCases[i][0]), testCases[i][1]);
            failures+=Tests.test("StrictMath.signum(double)",
                                 testCases[i][0], StrictMath.signum(testCases[i][0]), testCases[i][1]);
        }

        return failures;
    }


    public static void main(String argv[]) {
        int failures = 0;

        failures += testFloatGetExponent();
        failures += testDoubleGetExponent();

        failures += testFloatNextAfter();
        failures += testDoubleNextAfter();

        failures += testFloatNextUp();
        failures += testDoubleNextUp();

        failures += testFloatNextDown();
        failures += testDoubleNextDown();

        failures += testFloatBooleanMethods();
        failures += testDoubleBooleanMethods();

        failures += testFloatCopySign();
        failures += testDoubleCopySign();

        failures += testFloatScalb();
        failures += testDoubleScalb();

        failures += testFloatUlp();
        failures += testDoubleUlp();

        failures += testFloatSignum();
        failures += testDoubleSignum();

        if (failures > 0) {
            System.err.println("Testing the recommended functions incurred "
                               + failures + " failures.");
            throw new RuntimeException();
        }
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java IeeeRecommendedTests.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.