/*
* Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4860891 4826732 4780454 4939441 4826652
* @summary Tests for IEEE 754[R] recommended functions and similar methods
* @author Joseph D. Darcy
*/
import sun.misc.FpUtils;
import sun.misc.DoubleConsts;
import sun.misc.FloatConsts;
public class IeeeRecommendedTests {
private IeeeRecommendedTests(){}
static final float NaNf = Float.NaN;
static final double NaNd = Double.NaN;
static final float infinityF = Float.POSITIVE_INFINITY;
static final double infinityD = Double.POSITIVE_INFINITY;
static final float Float_MAX_VALUEmm = 0x1.fffffcP+127f;
static final float Float_MAX_SUBNORMAL = 0x0.fffffeP-126f;
static final float Float_MAX_SUBNORMALmm = 0x0.fffffcP-126f;
static final double Double_MAX_VALUEmm = 0x1.ffffffffffffeP+1023;
static final double Double_MAX_SUBNORMAL = 0x0.fffffffffffffP-1022;
static final double Double_MAX_SUBNORMALmm = 0x0.ffffffffffffeP-1022;
// Initialize shared random number generator
static java.util.Random rand = new java.util.Random();
/**
* Returns a floating-point power of two in the normal range.
*/
static double powerOfTwoD(int n) {
return Double.longBitsToDouble((((long)n + (long)DoubleConsts.MAX_EXPONENT) <<
(DoubleConsts.SIGNIFICAND_WIDTH-1))
& DoubleConsts.EXP_BIT_MASK);
}
/**
* Returns a floating-point power of two in the normal range.
*/
static float powerOfTwoF(int n) {
return Float.intBitsToFloat(((n + FloatConsts.MAX_EXPONENT) <<
(FloatConsts.SIGNIFICAND_WIDTH-1))
& FloatConsts.EXP_BIT_MASK);
}
/* ******************** getExponent tests ****************************** */
/*
* The tests for getExponent should test the special values (NaN, +/-
* infinity, etc.), test the endpoints of each binade (set of
* floating-point values with the same exponent), and for good
* measure, test some random values within each binade. Testing
* the endpoints of each binade includes testing both positive and
* negative numbers. Subnormal values with different normalized
* exponents should be tested too. Both Math and StrictMath
* methods should return the same results.
*/
/*
* Test Math.getExponent and StrictMath.getExponent with +d and -d.
*/
static int testGetExponentCase(float f, int expected) {
float minus_f = -f;
int failures=0;
failures+=Tests.test("Math.getExponent(float)", f,
Math.getExponent(f), expected);
failures+=Tests.test("Math.getExponent(float)", minus_f,
Math.getExponent(minus_f), expected);
failures+=Tests.test("StrictMath.getExponent(float)", f,
StrictMath.getExponent(f), expected);
failures+=Tests.test("StrictMath.getExponent(float)", minus_f,
StrictMath.getExponent(minus_f), expected);
return failures;
}
/*
* Test Math.getExponent and StrictMath.getExponent with +d and -d.
*/
static int testGetExponentCase(double d, int expected) {
double minus_d = -d;
int failures=0;
failures+=Tests.test("Math.getExponent(double)", d,
Math.getExponent(d), expected);
failures+=Tests.test("Math.getExponent(double)", minus_d,
Math.getExponent(minus_d), expected);
failures+=Tests.test("StrictMath.getExponent(double)", d,
StrictMath.getExponent(d), expected);
failures+=Tests.test("StrictMath.getExponent(double)", minus_d,
StrictMath.getExponent(minus_d), expected);
return failures;
}
public static int testFloatGetExponent() {
int failures = 0;
float [] specialValues = {NaNf,
Float.POSITIVE_INFINITY,
+0.0f,
+1.0f,
+2.0f,
+16.0f,
+Float.MIN_VALUE,
+Float_MAX_SUBNORMAL,
+FloatConsts.MIN_NORMAL,
+Float.MAX_VALUE
};
int [] specialResults = {Float.MAX_EXPONENT + 1, // NaN results
Float.MAX_EXPONENT + 1, // Infinite results
Float.MIN_EXPONENT - 1, // Zero results
0,
1,
4,
FloatConsts.MIN_EXPONENT - 1,
-FloatConsts.MAX_EXPONENT,
FloatConsts.MIN_EXPONENT,
FloatConsts.MAX_EXPONENT
};
// Special value tests
for(int i = 0; i < specialValues.length; i++) {
failures += testGetExponentCase(specialValues[i], specialResults[i]);
}
// Normal exponent tests
for(int i = FloatConsts.MIN_EXPONENT; i <= FloatConsts.MAX_EXPONENT; i++) {
int result;
// Create power of two
float po2 = powerOfTwoF(i);
failures += testGetExponentCase(po2, i);
// Generate some random bit patterns for the significand
for(int j = 0; j < 10; j++) {
int randSignif = rand.nextInt();
float randFloat;
randFloat = Float.intBitsToFloat( // Exponent
(Float.floatToIntBits(po2)&
(~FloatConsts.SIGNIF_BIT_MASK)) |
// Significand
(randSignif &
FloatConsts.SIGNIF_BIT_MASK) );
failures += testGetExponentCase(randFloat, i);
}
if (i > FloatConsts.MIN_EXPONENT) {
float po2minus = 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();
}
}
}