Skip to content
Permalink
Browse files
8240632: Note differences between IEEE 754-2019 math lib special case…
…s and java.lang.Math

Reviewed-by: bpb
  • Loading branch information
jddarcy committed Feb 8, 2021
1 parent ace8f94 commit 2fd8ed024b82d7ad3eecace5baa4c5eb6aeb4566
@@ -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 @@
* square root, and trigonometric functions.
*
* <p>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 @@
* occurs only with a specific minimum or maximum value and
* should be checked against the minimum or maximum as appropriate.
*
* <h2><a id=Ieee754RecommendedOps>IEEE 754 Recommended
* Operations</a></h2>
*
* 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 static double sin(double a) {
/**
* Returns the trigonometric cosine of an angle. Special cases:
* <ul><li>If the argument is NaN or an infinity, then the
* result is NaN.</ul>
* result is NaN.
* <li>If the argument is zero, then the result is {@code 1.0}.
*</ul>
*
* <p>The computed result must be within 1 ulp of the exact result.
* Results must be semi-monotonic.
@@ -209,7 +233,9 @@ public static double asin(double a) {
* Returns the arc cosine of a value; the returned angle is in the
* range 0.0 through <i>pi</i>. Special case:
* <ul><li>If the argument is NaN or its absolute value is greater
* than 1, then the result is NaN.</ul>
* than 1, then the result is NaN.
* <li>If the argument is {@code 1.0}, the result is positive zero.
* </ul>
*
* <p>The computed result must be within 1 ulp of the exact result.
* Results must be semi-monotonic.
@@ -226,7 +252,11 @@ public static double acos(double a) {
* range -<i>pi</i>/2 through <i>pi</i>/2. Special cases:
* <ul><li>If the argument is NaN, then the result is NaN.
* <li>If the argument is zero, then the result is a zero with the
* same sign as the argument.</ul>
* same sign as the argument.
* <li>If the argument is {@linkplain Double#isInfinite infinite},
* then the result is the closest value to <i>pi</i>/2 with the
* same sign as the input.
* </ul>
*
* <p>The computed result must be within 1 ulp of the exact result.
* Results must be semi-monotonic.
@@ -275,7 +305,9 @@ public static double toDegrees(double angrad) {
* <li>If the argument is positive infinity, then the result is
* positive infinity.
* <li>If the argument is negative infinity, then the result is
* positive zero.</ul>
* positive zero.
* <li>If the argument is zero, then the result is {@code 1.0}.
* </ul>
*
* <p>The computed result must be within 1 ulp of the exact result.
* Results must be semi-monotonic.
@@ -297,7 +329,10 @@ public static double exp(double a) {
* <li>If the argument is positive infinity, then the result is
* positive infinity.
* <li>If the argument is positive zero or negative zero, then the
* result is negative infinity.</ul>
* result is negative infinity.
* <li>If the argument is {@code 1.0}, then the result is positive
* zero.
* </ul>
*
* <p>The computed result must be within 1 ulp of the exact result.
* Results must be semi-monotonic.
@@ -321,8 +356,10 @@ public static double log(double a) {
* positive infinity.
* <li>If the argument is positive zero or negative zero, then the
* result is negative infinity.
* <li> If the argument is equal to 10<sup><i>n</i></sup> for
* integer <i>n</i>, then the result is <i>n</i>.
* <li>If the argument is equal to 10<sup><i>n</i></sup> for
* integer <i>n</i>, then the result is <i>n</i>. In particular,
* if the argument is {@code 1.0} (10<sup>0</sup>), then the
* result is positive zero.
* </ul>
*
* <p>The computed result must be within 1 ulp of the exact result.
@@ -529,6 +566,15 @@ public static double rint(double a) {
* <p>The computed result must be within 2 ulps of the exact result.
* Results must be semi-monotonic.
*
* @apiNote
* For <i>y</i> with a positive sign and finite nonzero
* <i>x</i>, the exact mathematical value of {@code atan2} is
* equal to:
* <ul>
* <li>If <i>x</i> {@literal >} 0, atan(abs(<i>y</i>/<i>x</i>))
* <li>If <i>x</i> {@literal <} 0, &pi; - atan(abs(<i>y</i>/<i>x</i>))
* </ul>
*
* @param y the ordinate coordinate
* @param x the abscissa coordinate
* @return the <i>theta</i> component of the point
@@ -660,6 +706,16 @@ public static double atan2(double y, double x) {
* <p>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 &plusmn;{@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}<sup>{@code b}</sup>.
@@ -2113,6 +2169,7 @@ public static double tanh(double x) {
* <li> If either argument is NaN and neither argument is infinite,
* then the result is NaN.
*
* <li> If both arguments are zero, the result is positive zero.
* </ul>
*
* <p>The computed result must be within 1 ulp of the exact
@@ -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 @@
* occurs only with a specific minimum or maximum value and
* should be checked against the minimum or maximum as appropriate.
*
* <h2><a id=Ieee754RecommendedOps>IEEE 754 Recommended
* Operations</a></h2>
*
* The {@link java.lang.Math Math} class discusses how the shared
* quality of implementation criteria for selected {@code Math} and
* {@code StrictMath} methods <a
* href="Math.html#Ieee754RecommendedOps">relate to the IEEE 754
* recommended operations</a>.
*
* @author Joseph D. Darcy
* @since 1.3
*/
@@ -126,7 +135,9 @@ private StrictMath() {}
/**
* Returns the trigonometric cosine of an angle. Special cases:
* <ul><li>If the argument is NaN or an infinity, then the
* result is NaN.</ul>
* result is NaN.
* <li>If the argument is zero, then the result is {@code 1.0}.
* </ul>
*
* @param a an angle, in radians.
* @return the cosine of the argument.
@@ -162,7 +173,9 @@ private StrictMath() {}
* Returns the arc cosine of a value; the returned angle is in the
* range 0.0 through <i>pi</i>. Special case:
* <ul><li>If the argument is NaN or its absolute value is greater
* than 1, then the result is NaN.</ul>
* than 1, then the result is NaN.
* <li>If the argument is {@code 1.0}, the result is positive zero.
* </ul>
*
* @param a the value whose arc cosine is to be returned.
* @return the arc cosine of the argument.
@@ -174,7 +187,11 @@ private StrictMath() {}
* range -<i>pi</i>/2 through <i>pi</i>/2. Special cases:
* <ul><li>If the argument is NaN, then the result is NaN.
* <li>If the argument is zero, then the result is a zero with the
* same sign as the argument.</ul>
* same sign as the argument.
* <li>If the argument is {@linkplain Double#isInfinite infinite},
* then the result is the closest value to <i>pi</i>/2 with the
* same sign as the input.
* </ul>
*
* @param a the value whose arc tangent is to be returned.
* @return the arc tangent of the argument.
@@ -220,7 +237,9 @@ public static strictfp double toDegrees(double angrad) {
* <li>If the argument is positive infinity, then the result is
* positive infinity.
* <li>If the argument is negative infinity, then the result is
* positive zero.</ul>
* positive zero.
* <li>If the argument is zero, then the result is {@code 1.0}.
* </ul>
*
* @param a the exponent to raise <i>e</i> to.
* @return the value <i>e</i><sup>{@code a}</sup>,
@@ -238,7 +257,10 @@ public static double exp(double a) {
* <li>If the argument is positive infinity, then the result is
* positive infinity.
* <li>If the argument is positive zero or negative zero, then the
* result is negative infinity.</ul>
* result is negative infinity.
* <li>If the argument is {@code 1.0}, then the result is positive
* zero.
* </ul>
*
* @param a a value
* @return the value ln&nbsp;{@code a}, the natural logarithm of
@@ -256,8 +278,10 @@ public static double exp(double a) {
* positive infinity.
* <li>If the argument is positive zero or negative zero, then the
* result is negative infinity.
* <li> If the argument is equal to 10<sup><i>n</i></sup> for
* integer <i>n</i>, then the result is <i>n</i>.
* <li>If the argument is equal to 10<sup><i>n</i></sup> for
* integer <i>n</i>, then the result is <i>n</i>. In particular,
* if the argument is {@code 1.0} (10<sup>0</sup>), then the
* result is positive zero.
* </ul>
*
* @param a a value
@@ -517,6 +541,15 @@ public static double rint(double a) {
* <li>If both arguments are negative infinity, then the result is the
* {@code double} value closest to -3*<i>pi</i>/4.</ul>
*
* @apiNote
* For <i>y</i> with a positive sign and finite nonzero
* <i>x</i>, the exact mathematical value of {@code atan2} is
* equal to:
* <ul>
* <li>If <i>x</i> {@literal >} 0, atan(abs(<i>y</i>/<i>x</i>))
* <li>If <i>x</i> {@literal <} 0, &pi; - atan(abs(<i>y</i>/<i>x</i>))
* </ul>
*
* @param y the ordinate coordinate
* @param x the abscissa coordinate
* @return the <i>theta</i> component of the point
@@ -642,6 +675,16 @@ public static double rint(double a) {
* 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 &plusmn;{@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}<sup>{@code b}</sup>.
@@ -1681,6 +1724,7 @@ public static float signum(float f) {
* <li> If either argument is NaN and neither argument is infinite,
* then the result is NaN.
*
* <li> If both arguments are zero, the result is positive zero.
* </ul>
*
* @param x a value
@@ -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 @@ private static int testExpCornerCases() {
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) {
@@ -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 @@ static int testHypot() {
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 static void main(String argv[]) {
int failures = 0;

failures += testHypot();
failures += testHypotZeros();

if (failures > 0) {
System.err.println("Testing the hypot incurred "
Loading

0 comments on commit 2fd8ed0

Please sign in to comment.