jdk-24/test/jdk/java/lang/Math/IeeeRemainderTests.java
2023-03-31 19:48:03 +00:00

210 lines
6.1 KiB
Java

/*
* Copyright (c) 2004, 2023, 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 8304028
* @summary Tests for {Math, StrictMath}.IEEEremainder
*/
public class IeeeRemainderTests {
private IeeeRemainderTests(){}
public static void main(String... args) {
int failures = 0;
failures += testIeeeRemainderSpecials();
failures += testIeeeRemainderZeroResult();
failures += testIeeeRemainderOneResult();
failures += testIeeeRemainderRounding();
if (failures > 0) {
System.err.println("Testing IEEEremainder incurred "
+ failures + " failures.");
throw new RuntimeException();
}
}
private static final double NaNd = Double.NaN;
private static final double MIN_VALUE = Double.MIN_VALUE;
private static final double MIN_NORM = Double.MIN_NORMAL;
private static final double MAX_VALUE = Double.MAX_VALUE;
private static final double InfinityD = Double.POSITIVE_INFINITY;
/**
* Special cases from the spec interspersed with test cases.
*/
private static int testIeeeRemainderSpecials() {
int failures = 0;
/*
* If either argument is NaN, or the first argument is
* infinite, or the second argument is positive zero or
* negative zero, then the result is NaN.
*
*/
for(double nan : Tests.NaNs) {
failures += testIEEEremainderCase(nan, 1.0, NaNd);
failures += testIEEEremainderCase(1.0, nan, NaNd);
}
double [][] nanResultCases = {
{ InfinityD, InfinityD},
{-InfinityD, InfinityD},
{ InfinityD, 1.0},
{-InfinityD, 1.0},
{ InfinityD, NaNd},
{-InfinityD, NaNd},
{ InfinityD, 0.0},
{-InfinityD, 0.0},
{ InfinityD, -0.0},
{-InfinityD, -0.0},
};
for(double[] testCase : nanResultCases) {
failures += testIEEEremainderCase(testCase[0], testCase[1], NaNd);
}
/*
* If the first argument is finite and the second argument is
* infinite, then the result is the same as the first
* argument.
*
*/
double [] specialCases = {
+0.0,
+MIN_VALUE,
+MIN_NORM,
+MAX_VALUE,
-0.0,
-MIN_VALUE,
-MIN_NORM,
-MAX_VALUE,
};
double [] infinities = {
+InfinityD,
-InfinityD
};
for (double specialCase : specialCases) {
for (double infinity: infinities) {
failures += testIEEEremainderCase(specialCase, infinity, specialCase);
}
}
return failures;
}
private static int testIeeeRemainderZeroResult() {
int failures = 0;
double [] testCases = {
+MIN_VALUE,
+MIN_NORM,
+MAX_VALUE*0.5,
-MIN_VALUE,
-MIN_NORM,
-MAX_VALUE*0.5,
};
for (double testCase : testCases) {
/*
* "If the remainder is zero, its sign is the same as the sign of the first argument."
*/
failures += testIEEEremainderCase(testCase*2.0, +testCase, Math.copySign(0.0, testCase));
failures += testIEEEremainderCase(testCase*2.0, -testCase, Math.copySign(0.0, testCase));
}
return failures;
}
/*
* Construct test cases where the remainder is one.
*/
private static int testIeeeRemainderOneResult() {
int failures = 0;
double [][] testCases = {
{4.0, 3.0},
{10_001.0, 5000.0},
{15_001.0, 5000.0},
{10_000.0, 9999.0},
{0x1.0p52 + 1.0, 0x1.0p52},
{0x1.fffffffffffffp52, 0x1.ffffffffffffep52},
};
for (var testCase : testCases) {
failures += testIEEEremainderCase(testCase[0], testCase[1], 1.0);
}
return failures;
}
/*
* Test cases that differ in rounding between % and IEEEremainder.
*/
private static int testIeeeRemainderRounding() {
int failures = 0;
double [][] testCases = {
{3.0, 2.0, -1.0},
{3.0, -2.0, -1.0},
};
for (var testCase : testCases) {
failures += testIEEEremainderCase(testCase[0], testCase[1], testCase[2]);
}
return failures;
}
/*
* For exact cases, built-in % remainder and IEEE remainder should
* be the same since the rounding mode in the implicit divide
* doesn't come into play.
*/
private static double remainder(double a, double b) {
return a % b;
}
private static int testIEEEremainderCase(double input1, double input2, double expected) {
int failures = 0;
failures += Tests.test("StrictMath.IEEEremainder", input1, input2, StrictMath::IEEEremainder, expected);
failures += Tests.test("Math.IEEEremainder", input1, input2, Math::IEEEremainder, expected);
return failures;
}
}