diff --git a/src/java.base/share/classes/java/lang/Math.java b/src/java.base/share/classes/java/lang/Math.java index ff7ceff6cf2..bc7d92c98e2 100644 --- a/src/java.base/share/classes/java/lang/Math.java +++ b/src/java.base/share/classes/java/lang/Math.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2021, 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 @@ -37,7 +37,7 @@ import jdk.internal.vm.annotation.IntrinsicCandidate; * square root, and trigonometric functions. * *

Unlike some of the numeric methods of class - * {@code StrictMath}, all implementations of the equivalent + * {@link java.lang.StrictMath StrictMath}, all implementations of the equivalent * functions of class {@code Math} are not defined to return the * bit-for-bit same results. This relaxation permits * better-performing implementations where strict reproducibility is @@ -99,6 +99,28 @@ import jdk.internal.vm.annotation.IntrinsicCandidate; * occurs only with a specific minimum or maximum value and * should be checked against the minimum or maximum as appropriate. * + *

IEEE 754 Recommended + * Operations

+ * + * The 2019 revision of the IEEE 754 floating-point standard includes + * a section of recommended operations and the semantics of those + * operations if they are included in a programming environment. The + * recommended operations present in this class include {@link sin + * sin}, {@link cos cos}, {@link tan tan}, {@link asin asin}, {@link + * acos acos}, {@link atan atan}, {@link exp exp}, {@link expm1 + * expm1}, {@link log log}, {@link log10 log10}, {@link log1p log1p}, + * {@link sinh sinh}, {@link cosh cosh}, {@link tanh tanh}, {@link + * hypot hypot}, and {@link pow pow}. (The {@link sqrt sqrt} + * operation is a required part of IEEE 754 from a different section + * of the standard.) The special case behavior of the recommended + * operations generally follows the guidance of the IEEE 754 + * standard. However, the {@code pow} method defines different + * behavior for some arguments, as noted in its {@linkplain pow + * specification}. The IEEE 754 standard defines its operations to be + * correctly rounded, which is a more stringent quality of + * implementation condition than required for most of the methods in + * question that are also included in this class. + * * @author Joseph D. Darcy * @since 1.0 */ @@ -156,7 +178,9 @@ public final class Math { /** * Returns the trigonometric cosine of an angle. Special cases: * + * result is NaN. + *
  • If the argument is zero, then the result is {@code 1.0}. + * * *

    The computed result must be within 1 ulp of the exact result. * Results must be semi-monotonic. @@ -209,7 +233,9 @@ public final class Math { * Returns the arc cosine of a value; the returned angle is in the * range 0.0 through pi. Special case: *

    + * than 1, then the result is NaN. + *
  • If the argument is {@code 1.0}, the result is positive zero. + * * *

    The computed result must be within 1 ulp of the exact result. * Results must be semi-monotonic. @@ -226,7 +252,11 @@ public final class Math { * range -pi/2 through pi/2. Special cases: *

    + * same sign as the argument. + *
  • If the argument is {@linkplain Double#isInfinite infinite}, + * then the result is the closest value to pi/2 with the + * same sign as the input. + * * *

    The computed result must be within 1 ulp of the exact result. * Results must be semi-monotonic. @@ -275,7 +305,9 @@ public final class Math { *

  • If the argument is positive infinity, then the result is * positive infinity. *
  • If the argument is negative infinity, then the result is - * positive zero. + * positive zero. + *
  • If the argument is zero, then the result is {@code 1.0}. + * * *

    The computed result must be within 1 ulp of the exact result. * Results must be semi-monotonic. @@ -297,7 +329,10 @@ public final class Math { *

  • If the argument is positive infinity, then the result is * positive infinity. *
  • If the argument is positive zero or negative zero, then the - * result is negative infinity. + * result is negative infinity. + *
  • If the argument is {@code 1.0}, then the result is positive + * zero. + * * *

    The computed result must be within 1 ulp of the exact result. * Results must be semi-monotonic. @@ -321,8 +356,10 @@ public final class Math { * positive infinity. *

  • If the argument is positive zero or negative zero, then the * result is negative infinity. - *
  • If the argument is equal to 10n for - * integer n, then the result is n. + *
  • If the argument is equal to 10n for + * integer n, then the result is n. In particular, + * if the argument is {@code 1.0} (100), then the + * result is positive zero. * * *

    The computed result must be within 1 ulp of the exact result. @@ -529,6 +566,15 @@ public final class Math { *

    The computed result must be within 2 ulps of the exact result. * Results must be semi-monotonic. * + * @apiNote + * For y with a positive sign and finite nonzero + * x, the exact mathematical value of {@code atan2} is + * equal to: + *

    + * * @param y the ordinate coordinate * @param x the abscissa coordinate * @return the theta component of the point @@ -660,6 +706,16 @@ public final class Math { *

    The computed result must be within 1 ulp of the exact result. * Results must be semi-monotonic. * + * @apiNote + * The special cases definitions of this method differ from the + * special case definitions of the IEEE 754 recommended {@code + * pow} operation for ±{@code 1.0} raised to an infinite + * power. This method treats such cases as indeterminate and + * specifies a NaN is returned. The IEEE 754 specification treats + * the infinite power as a large integer (large-magnitude + * floating-point numbers are numerically integers, specifically + * even integers) and therefore specifies {@code 1.0} be returned. + * * @param a the base. * @param b the exponent. * @return the value {@code a}{@code b}. @@ -2113,6 +2169,7 @@ public final class Math { *

  • If either argument is NaN and neither argument is infinite, * then the result is NaN. * + *
  • If both arguments are zero, the result is positive zero. * * *

    The computed result must be within 1 ulp of the exact diff --git a/src/java.base/share/classes/java/lang/StrictMath.java b/src/java.base/share/classes/java/lang/StrictMath.java index 941834381be..506324f3346 100644 --- a/src/java.base/share/classes/java/lang/StrictMath.java +++ b/src/java.base/share/classes/java/lang/StrictMath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2021, 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 @@ -74,6 +74,15 @@ import jdk.internal.vm.annotation.IntrinsicCandidate; * occurs only with a specific minimum or maximum value and * should be checked against the minimum or maximum as appropriate. * + *

    IEEE 754 Recommended + * Operations

    + * + * The {@link java.lang.Math Math} class discusses how the shared + * quality of implementation criteria for selected {@code Math} and + * {@code StrictMath} methods relate to the IEEE 754 + * recommended operations. + * * @author Joseph D. Darcy * @since 1.3 */ @@ -126,7 +135,9 @@ public final class StrictMath { /** * Returns the trigonometric cosine of an angle. Special cases: * + * result is NaN. + *
  • If the argument is zero, then the result is {@code 1.0}. + * * * @param a an angle, in radians. * @return the cosine of the argument. @@ -162,7 +173,9 @@ public final class StrictMath { * Returns the arc cosine of a value; the returned angle is in the * range 0.0 through pi. Special case: * + * than 1, then the result is NaN. + *
  • If the argument is {@code 1.0}, the result is positive zero. + * * * @param a the value whose arc cosine is to be returned. * @return the arc cosine of the argument. @@ -174,7 +187,11 @@ public final class StrictMath { * range -pi/2 through pi/2. Special cases: * + * same sign as the argument. + *
  • If the argument is {@linkplain Double#isInfinite infinite}, + * then the result is the closest value to pi/2 with the + * same sign as the input. + * * * @param a the value whose arc tangent is to be returned. * @return the arc tangent of the argument. @@ -220,7 +237,9 @@ public final class StrictMath { *
  • If the argument is positive infinity, then the result is * positive infinity. *
  • If the argument is negative infinity, then the result is - * positive zero. + * positive zero. + *
  • If the argument is zero, then the result is {@code 1.0}. + * * * @param a the exponent to raise e to. * @return the value e{@code a}, @@ -238,7 +257,10 @@ public final class StrictMath { *
  • If the argument is positive infinity, then the result is * positive infinity. *
  • If the argument is positive zero or negative zero, then the - * result is negative infinity. + * result is negative infinity. + *
  • If the argument is {@code 1.0}, then the result is positive + * zero. + * * * @param a a value * @return the value ln {@code a}, the natural logarithm of @@ -256,8 +278,10 @@ public final class StrictMath { * positive infinity. *
  • If the argument is positive zero or negative zero, then the * result is negative infinity. - *
  • If the argument is equal to 10n for - * integer n, then the result is n. + *
  • If the argument is equal to 10n for + * integer n, then the result is n. In particular, + * if the argument is {@code 1.0} (100), then the + * result is positive zero. * * * @param a a value @@ -517,6 +541,15 @@ public final class StrictMath { *
  • If both arguments are negative infinity, then the result is the * {@code double} value closest to -3*pi/4. * + * @apiNote + * For y with a positive sign and finite nonzero + * x, the exact mathematical value of {@code atan2} is + * equal to: + * + * * @param y the ordinate coordinate * @param x the abscissa coordinate * @return the theta component of the point @@ -642,6 +675,16 @@ public final class StrictMath { * method if and only if the result of applying the method to the * value is equal to the value.) * + * @apiNote + * The special cases definitions of this method differ from the + * special case definitions of the IEEE 754 recommended {@code + * pow} operation for ±{@code 1.0} raised to an infinite + * power. This method treats such cases as indeterminate and + * specifies a NaN is returned. The IEEE 754 specification treats + * the infinite power as a large integer (large-magnitude + * floating-point numbers are numerically integers, specifically + * even integers) and therefore specifies {@code 1.0} be returned. + * * @param a base. * @param b the exponent. * @return the value {@code a}{@code b}. @@ -1681,6 +1724,7 @@ public final class StrictMath { *
  • If either argument is NaN and neither argument is infinite, * then the result is NaN. * + *
  • If both arguments are zero, the result is positive zero. * * * @param x a value diff --git a/test/jdk/java/lang/Math/ExpCornerCaseTests.java b/test/jdk/java/lang/Math/ExpCornerCaseTests.java index c7948b19af8..16168254378 100644 --- a/test/jdk/java/lang/Math/ExpCornerCaseTests.java +++ b/test/jdk/java/lang/Math/ExpCornerCaseTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011,2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2020, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8255368 + * @bug 8255368 8240632 * @summary Tests corner cases of Math.exp */ @@ -46,6 +46,10 @@ public class ExpCornerCaseTests { double [][] testCases = { {+0x4.0p8, Double.POSITIVE_INFINITY}, {+0x2.71p12, Double.POSITIVE_INFINITY}, + + // Identified special cases in IEEE 754 exp operation + {+0.0, 1.0}, + {-0.0, 1.0}, }; for (double[] testCase : testCases) { diff --git a/test/jdk/java/lang/Math/HypotTests.java b/test/jdk/java/lang/Math/HypotTests.java index 0f31a8881f8..d7e562ca5fd 100644 --- a/test/jdk/java/lang/Math/HypotTests.java +++ b/test/jdk/java/lang/Math/HypotTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, 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 @@ -26,7 +26,7 @@ * @library /test/lib * @build jdk.test.lib.RandomFactory * @run main HypotTests - * @bug 4851638 4939441 8078672 + * @bug 4851638 4939441 8078672 8240632 * @summary Tests for {Math, StrictMath}.hypot (use -Dseed=X to set PRNG seed) * @author Joseph D. Darcy * @key randomness @@ -198,6 +198,13 @@ public class HypotTests { return failures; } + /** + * Verify +0.0 is returned if both arguments are zero. + */ + private static int testHypotZeros() { + return testHypotCase(0.0, 0.0, +0.0, 0.0); + } + static int testHypotCase(double input1, double input2, double expected) { return testHypotCase(input1,input2, expected, 1); } @@ -237,6 +244,7 @@ public class HypotTests { int failures = 0; failures += testHypot(); + failures += testHypotZeros(); if (failures > 0) { System.err.println("Testing the hypot incurred " diff --git a/test/jdk/java/lang/Math/Ieee754SpecialCaseTests.java b/test/jdk/java/lang/Math/Ieee754SpecialCaseTests.java new file mode 100644 index 00000000000..d8192f2fee3 --- /dev/null +++ b/test/jdk/java/lang/Math/Ieee754SpecialCaseTests.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2011, 2021, 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 8240632 + * @summary Test special cases of IEEE 754 recommended ops not otherwise tested + * @build Tests + * @build Ieee754SpecialCaseTests + * @run main Ieee754SpecialCaseTests + */ + +public class Ieee754SpecialCaseTests { + private Ieee754SpecialCaseTests() {throw new AssertionError("No instances for you.");} + + public static void main(String... args) { + int failures = 0; + + failures += testSpecialCos(); + failures += testSpecialAcos(); + failures += testSpecialAtan(); + failures += testSpecialLog(); + + if (failures > 0) { + System.err.printf("Testing special cases incurred %d failures.%n", failures); + throw new RuntimeException(); + } + } + private static int testSpecialCos() { + int failures = 0; + double [][] testCases = { + {+0.0, 1.0}, + {-0.0, 1.0}, + }; + + for(double[] testCase: testCases) { + failures += testCosCase(testCase[0], testCase[1]); + } + + return failures; + } + + private static int testCosCase(double input, double expected) { + int failures = 0; + failures += Tests.test("Math.cos", input, Math.cos(input), expected); + failures += Tests.test("StrictMath.cos", input, StrictMath.cos(input), expected); + return failures; + } + + private static int testSpecialAcos() { + int failures = 0; + double [][] testCases = { + {1.0, 0.0}, + }; + + for(double[] testCase: testCases) { + failures += testAcosCase(testCase[0], testCase[1]); + } + + return failures; + } + + private static int testAcosCase(double input, double expected) { + int failures = 0; + failures += Tests.test("Math.acos", input, Math.acos(input), expected); + failures += Tests.test("StrictMath.acos", input, StrictMath.acos(input), expected); + return failures; + } + + private static int testSpecialAtan() { + int failures = 0; + double [][] testCases = { + {Double.POSITIVE_INFINITY, +Math.PI/2.0}, + {Double.NEGATIVE_INFINITY, -Math.PI/2.0}, + }; + + for(double[] testCase: testCases) { + failures += testAtanCase(testCase[0], testCase[1]); + } + + return failures; + } + + private static int testAtanCase(double input, double expected) { + int failures = 0; + failures += Tests.test("Math.atan", input, Math.atan(input), expected); + failures += Tests.test("StrictMath.atan", input, StrictMath.atan(input), expected); + return failures; + } + + private static int testSpecialLog() { + int failures = 0; + double [][] testCases = { + {1.0, +0.0}, + }; + + for(double[] testCase: testCases) { + failures += testLogCase(testCase[0], testCase[1]); + } + + return failures; + } + + private static int testLogCase(double input, double expected) { + int failures = 0; + failures += Tests.test("Math.log", input, Math.log(input), expected); + failures += Tests.test("StrictMath.log", input, StrictMath.log(input), expected); + return failures; + } +}