jdk/test/java/lang/Math/IeeeRecommendedTests.java
author jrose
Sat, 05 Oct 2013 05:30:38 -0700
changeset 20528 0b1e2130d3f7
parent 10608 7cfca36fc79b
child 22634 9c18aebe9229
permissions -rw-r--r--
8001105: findVirtual of Object[].clone produces internal error Summary: Replicate JVM logic for access control that makes Object.clone appear public when applied to an array type. Reviewed-by: twisti

/*
 * 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();
        }
    }
}