| /* | |
| * Copyright (c) 2003, 2022, 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 | |
| * @library /test/lib | |
| * @build jdk.test.lib.RandomFactory | |
| * @run main IeeeRecommendedTests | |
| * @bug 4860891 4826732 4780454 4939441 4826652 8078672 | |
| * @summary Tests for IEEE 754[R] recommended functions and similar methods (use -Dseed=X to set PRNG seed) | |
| * @key randomness | |
| */ | |
| import jdk.test.lib.RandomFactory; | |
| 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 = RandomFactory.getRandom(); | |
| /** | |
| * Returns a floating-point power of two in the normal range. | |
| */ | |
| static double powerOfTwoD(int n) { | |
| return Double.longBitsToDouble((((long)n + (long)Double.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 + Float.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, | |
| +Float.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, | |
| Float.MIN_EXPONENT - 1, | |
| -Float.MAX_EXPONENT, | |
| Float.MIN_EXPONENT, | |
| Float.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 = Float.MIN_EXPONENT; i <= Float.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 > Float.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, | |
| Float.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), | |
| Float.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, | |
| Float.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, | |
| +Double.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, | |
| Double.MIN_EXPONENT - 1, | |
| -Double.MAX_EXPONENT, | |
| Double.MIN_EXPONENT, | |
| Double.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 = Double.MIN_EXPONENT; i <= Double.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 > Double.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, | |
| Double.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), | |
| Double.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, | |
| Double.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, expected); | |
| failures+=Tests.test("Math.nextAfter(double,double)", minus_start, minus_direction, | |
| Math::nextAfter, minus_expected); | |
| failures+=Tests.test("StrictMath.nextAfter(double,double)", start, direction, | |
| StrictMath::nextAfter, expected); | |
| failures+=Tests.test("StrictMath.nextAfter(double,double)", minus_start, minus_direction, | |
| StrictMath::nextAfter, 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}, | |
| {Float.MIN_NORMAL, infinityF, Float.MIN_NORMAL+ | |
| Float.MIN_VALUE}, | |
| {Float.MIN_NORMAL, -infinityF, Float_MAX_SUBNORMAL}, | |
| {Float.MIN_NORMAL, 1.0f, Float.MIN_NORMAL+ | |
| Float.MIN_VALUE}, | |
| {Float.MIN_NORMAL, -1.0f, Float_MAX_SUBNORMAL}, | |
| {Float.MIN_NORMAL, Float.MIN_NORMAL, Float.MIN_NORMAL}, | |
| {Float_MAX_SUBNORMAL, Float.MIN_NORMAL, Float.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}, | |
| {Double.MIN_NORMAL, infinityD, Double.MIN_NORMAL+ | |
| Double.MIN_VALUE}, | |
| {Double.MIN_NORMAL, -infinityD, Double_MAX_SUBNORMAL}, | |
| {Double.MIN_NORMAL, 1.0f, Double.MIN_NORMAL+ | |
| Double.MIN_VALUE}, | |
| {Double.MIN_NORMAL, -1.0f, Double_MAX_SUBNORMAL}, | |
| {Double.MIN_NORMAL, Double.MIN_NORMAL, Double.MIN_NORMAL}, | |
| {Double_MAX_SUBNORMAL, Double.MIN_NORMAL, Double.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}, | |
| {-Float.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, Float.MIN_NORMAL}, | |
| {Float.MIN_NORMAL, Float.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}, | |
| {-Double.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, Double.MIN_NORMAL}, | |
| {Double.MIN_NORMAL, Double.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][1]); | |
| failures+=Tests.test("StrictMath.nextUp(double)", | |
| testCases[i][0], StrictMath::nextUp, 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, -Float.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}, | |
| {Float.MIN_NORMAL, Float_MAX_SUBNORMAL}, | |
| {Float.MIN_NORMAL+ | |
| Float.MIN_VALUE, Float.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, -Double.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}, | |
| {Double.MIN_NORMAL, Double_MAX_SUBNORMAL}, | |
| {Double.MIN_NORMAL+ | |
| Double.MIN_VALUE, Double.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][1]); | |
| failures+=Tests.test("StrictMath.nextDown(double)", | |
| testCases[i][0], StrictMath::nextDown, 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, | |
| -Float.MIN_NORMAL, | |
| -Float_MAX_SUBNORMALmm, | |
| -Float_MAX_SUBNORMAL, | |
| -Float.MIN_VALUE, | |
| -0.0f, | |
| +0.0f, | |
| Float.MIN_VALUE, | |
| Float_MAX_SUBNORMALmm, | |
| Float_MAX_SUBNORMAL, | |
| Float.MIN_NORMAL, | |
| 1.0f, | |
| 3.0f, | |
| Float_MAX_VALUEmm, | |
| Float.MAX_VALUE | |
| }; | |
| for(int i = 0; i < testCases.length; i++) { | |
| // isNaN | |
| failures+=Tests.test("Float.isNaN(float)", testCases[i], | |
| Float.isNaN(testCases[i]), (i ==0)); | |
| // isFinite | |
| failures+=Tests.test("Float.isFinite(float)", testCases[i], | |
| Float.isFinite(testCases[i]), (i >= 3)); | |
| // isInfinite | |
| failures+=Tests.test("Float.isInfinite(float)", testCases[i], | |
| Float.isInfinite(testCases[i]), (i==1 || i==2)); | |
| // isUnorderd | |
| for(int j = 0; j < testCases.length; j++) { | |
| failures+=Tests.test("Tests.isUnordered(float, float)", testCases[i],testCases[j], | |
| Tests.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, | |
| -Double.MIN_NORMAL, | |
| -Double_MAX_SUBNORMALmm, | |
| -Double_MAX_SUBNORMAL, | |
| -Double.MIN_VALUE, | |
| -0.0d, | |
| +0.0d, | |
| Double.MIN_VALUE, | |
| Double_MAX_SUBNORMALmm, | |
| Double_MAX_SUBNORMAL, | |
| Double.MIN_NORMAL, | |
| 1.0d, | |
| 3.0d, | |
| Double_MAX_VALUEmm, | |
| Double.MAX_VALUE | |
| }; | |
| for(int i = 0; i < testCases.length; i++) { | |
| // isNaN | |
| failures+=Tests.test("Double.isNaN(double)", testCases[i], | |
| Double.isNaN(testCases[i]), (i ==0)); | |
| // isFinite | |
| failures+=Tests.test("Double.isFinite(double)", testCases[i], | |
| Double.isFinite(testCases[i]), (i >= 3)); | |
| // isInfinite | |
| failures+=Tests.test("Double.isInfinite(double)", testCases[i], | |
| Double.isInfinite(testCases[i]), (i==1 || i==2)); | |
| // isUnorderd | |
| for(int j = 0; j < testCases.length; j++) { | |
| failures+=Tests.test("Tests.isUnordered(double, double)", testCases[i],testCases[j], | |
| Tests.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, | |
| Float.MIN_NORMAL, | |
| 1.0f, | |
| 3.0f, | |
| Float_MAX_VALUEmm, | |
| Float.MAX_VALUE, | |
| infinityF, | |
| }, | |
| {-infinityF, | |
| -Float.MAX_VALUE, | |
| -3.0f, | |
| -1.0f, | |
| -Float.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, | |
| Double.MIN_NORMAL, | |
| 1.0d, | |
| 3.0d, | |
| Double_MAX_VALUEmm, | |
| Double.MAX_VALUE, | |
| infinityD, | |
| }, | |
| {-infinityD, | |
| -Double.MAX_VALUE, | |
| -3.0d, | |
| -1.0d, | |
| -Double.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, | |
| (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, | |
| (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, | |
| 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 = Float.MAX_EXPONENT + -Float.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, | |
| Float.MIN_NORMAL, | |
| 1.0f, | |
| 2.0f, | |
| 3.0f, | |
| (float)Math.PI, | |
| Float_MAX_VALUEmm, | |
| Float.MAX_VALUE | |
| }; | |
| int [] oneMultiplyScalingFactors = { | |
| Float.MIN_EXPONENT, | |
| Float.MIN_EXPONENT+1, | |
| -3, | |
| -2, | |
| -1, | |
| 0, | |
| 1, | |
| 2, | |
| 3, | |
| Float.MAX_EXPONENT-1, | |
| Float.MAX_EXPONENT | |
| }; | |
| int [] manyScalingFactors = { | |
| Integer.MIN_VALUE, | |
| Integer.MIN_VALUE+1, | |
| -MAX_SCALE -1, | |
| -MAX_SCALE, | |
| -MAX_SCALE+1, | |
| 2*Float.MIN_EXPONENT-1, // -253 | |
| 2*Float.MIN_EXPONENT, // -252 | |
| 2*Float.MIN_EXPONENT+1, // -251 | |
| Float.MIN_EXPONENT - FloatConsts.SIGNIFICAND_WIDTH, | |
| FloatConsts.MIN_SUB_EXPONENT, | |
| -Float.MAX_EXPONENT, // -127 | |
| Float.MIN_EXPONENT, // -126 | |
| -2, | |
| -1, | |
| 0, | |
| 1, | |
| 2, | |
| Float.MAX_EXPONENT-1, // 126 | |
| Float.MAX_EXPONENT, // 127 | |
| Float.MAX_EXPONENT+1, // 128 | |
| 2*Float.MAX_EXPONENT-1, // 253 | |
| 2*Float.MAX_EXPONENT, // 254 | |
| 2*Float.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 < Float.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=Float.MAX_EXPONENT*2; j < MAX_SCALE; j++) { // MAX_SCALE -1 should cause overflow | |
| int scaleFactor = j; | |
| failures+=testScalbCase(value, | |
| scaleFactor, | |
| (Tests.ilogb(value) +j > Float.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 = Double.MAX_EXPONENT + -Double.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, | |
| Double.MIN_NORMAL, | |
| 1.0d, | |
| 2.0d, | |
| 3.0d, | |
| Math.PI, | |
| Double_MAX_VALUEmm, | |
| Double.MAX_VALUE | |
| }; | |
| int [] oneMultiplyScalingFactors = { | |
| Double.MIN_EXPONENT, | |
| Double.MIN_EXPONENT+1, | |
| -3, | |
| -2, | |
| -1, | |
| 0, | |
| 1, | |
| 2, | |
| 3, | |
| Double.MAX_EXPONENT-1, | |
| Double.MAX_EXPONENT | |
| }; | |
| int [] manyScalingFactors = { | |
| Integer.MIN_VALUE, | |
| Integer.MIN_VALUE+1, | |
| -MAX_SCALE -1, | |
| -MAX_SCALE, | |
| -MAX_SCALE+1, | |
| 2*Double.MIN_EXPONENT-1, // -2045 | |
| 2*Double.MIN_EXPONENT, // -2044 | |
| 2*Double.MIN_EXPONENT+1, // -2043 | |
| Double.MIN_EXPONENT, // -1022 | |
| Double.MIN_EXPONENT - DoubleConsts.SIGNIFICAND_WIDTH, | |
| DoubleConsts.MIN_SUB_EXPONENT, | |
| -Double.MAX_EXPONENT, // -1023 | |
| Double.MIN_EXPONENT, // -1022 | |
| -2, | |
| -1, | |
| 0, | |
| 1, | |
| 2, | |
| Double.MAX_EXPONENT-1, // 1022 | |
| Double.MAX_EXPONENT, // 1023 | |
| Double.MAX_EXPONENT+1, // 1024 | |
| 2*Double.MAX_EXPONENT-1, // 2045 | |
| 2*Double.MAX_EXPONENT, // 2046 | |
| 2*Double.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 < Double.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=Double.MAX_EXPONENT*2; j < MAX_SCALE; j++) { // MAX_SCALE -1 should cause overflow | |
| int scaleFactor = j; | |
| failures+=testScalbCase(value, | |
| scaleFactor, | |
| (Tests.ilogb(value) +j > Double.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 < Double.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, expected); | |
| failures+=Tests.test("Math.ulp(double)", minus_d, | |
| Math::ulp, expected); | |
| failures+=Tests.test("StrictMath.ulp(double)", d, | |
| StrictMath::ulp, expected); | |
| failures+=Tests.test("StrictMath.ulp(double)", minus_d, | |
| StrictMath::ulp, 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, | |
| +Float.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 = Float.MIN_EXPONENT; i <= Float.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 > Float.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, | |
| +Double.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 = Double.MIN_EXPONENT; i <= Double.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 > Double.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}, | |
| {-Float.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}, | |
| {Float.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}, | |
| {-Double.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}, | |
| {Double.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][1]); | |
| failures+=Tests.test("StrictMath.signum(double)", | |
| testCases[i][0], StrictMath::signum, 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(); | |
| } | |
| } | |
| } |