/* * Copyright 2003-2005 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.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 = FpUtils.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(FpUtils.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 = FpUtils.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(FpUtils.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("FpUtils.nextDown(float)", testCases[i][0], FpUtils.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("FpUtils.nextDown(double)", testCases[i][0], FpUtils.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("FpUtils.isFinite(float)", testCases[i], FpUtils.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("FpUtils.isFinite(double)", testCases[i], FpUtils.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, FpUtils.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 ) ? FpUtils.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, FpUtils.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 ) ? FpUtils.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 = FpUtils.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 = FpUtils.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(FpUtils.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 = FpUtils.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 = FpUtils.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(FpUtils.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(); } } }