8294539: Augment discussion of equivalence relations on floating-point values

Reviewed-by: psandoz, smarks
This commit is contained in:
Joe Darcy 2022-10-05 00:18:55 +00:00
parent b2e86a6209
commit 1dafbe3f94
2 changed files with 71 additions and 7 deletions

View file

@ -58,7 +58,7 @@ import jdk.internal.vm.annotation.IntrinsicCandidate;
* *
* IEEE 754 floating-point values include finite nonzero values, * IEEE 754 floating-point values include finite nonzero values,
* signed zeros ({@code +0.0} and {@code -0.0}), signed infinities * signed zeros ({@code +0.0} and {@code -0.0}), signed infinities
* {@linkplain Double#POSITIVE_INFINITY positive infinity} and * ({@linkplain Double#POSITIVE_INFINITY positive infinity} and
* {@linkplain Double#NEGATIVE_INFINITY negative infinity}), and * {@linkplain Double#NEGATIVE_INFINITY negative infinity}), and
* {@linkplain Double#NaN NaN} (not-a-number). * {@linkplain Double#NaN NaN} (not-a-number).
* *
@ -116,12 +116,13 @@ import jdk.internal.vm.annotation.IntrinsicCandidate;
* <p>To provide the appropriate semantics for {@code equals} and * <p>To provide the appropriate semantics for {@code equals} and
* {@code compareTo} methods, those methods cannot simply be wrappers * {@code compareTo} methods, those methods cannot simply be wrappers
* around {@code ==} or ordered comparison operations. Instead, {@link * around {@code ==} or ordered comparison operations. Instead, {@link
* Double#equals equals} defines NaN arguments to be equal to each * Double#equals equals} uses <a href=#repEquivalence> representation
* other and defines {@code +0.0} to <em>not</em> be equal to {@code * equivalence</a>, defining NaN arguments to be equal to each other,
* -0.0}, restoring reflexivity. For comparisons, {@link * restoring reflexivity, and defining {@code +0.0} to <em>not</em> be
* Double#compareTo compareTo} defines a total order where {@code * equal to {@code -0.0}. For comparisons, {@link Double#compareTo
* -0.0} is less than {@code +0.0} and where a NaN is equal to itself * compareTo} defines a total order where {@code -0.0} is less than
* and considered greater than positive infinity. * {@code +0.0} and where a NaN is equal to itself and considered
* greater than positive infinity.
* *
* <p>The operational semantics of {@code equals} and {@code * <p>The operational semantics of {@code equals} and {@code
* compareTo} are expressed in terms of {@linkplain #doubleToLongBits * compareTo} are expressed in terms of {@linkplain #doubleToLongBits
@ -143,6 +144,62 @@ import jdk.internal.vm.annotation.IntrinsicCandidate;
* elements of a {@link java.util.SortedSet SortedSet} or as keys of a * elements of a {@link java.util.SortedSet SortedSet} or as keys of a
* {@link java.util.SortedMap SortedMap}. * {@link java.util.SortedMap SortedMap}.
* *
* <p>Comparing numerical equality to various useful equivalence
* relations that can be defined over floating-point values:
*
* <dl>
* <dt><a id=fpNumericalEq><i>numerical equality</i></a> ({@code ==}
* operator): (<em>Not</em> an equivalence relation)</dt>
* <dd>Two floating-point values represent the same extended real
* number. The extended real numbers are the real numbers augmented
* with positive infinity and negative infinity. Under numerical
* equality, {@code +0.0} and {@code -0.0} are equal since they both
* map to the same real value, 0. A NaN does not map to any real
* number and is not equal to any value, including itself.
* </dd>
*
* <dt><i>bit-wise equivalence</i>:</dt>
* <dd>The bits of the two floating-point values are the same. This
* equivalence relation for {@code double} values {@code a} and {@code
* b} is implemented by the expression
* <br>{@code Double.doubleTo}<code><b>Raw</b></code>{@code LongBits(a) == Double.doubleTo}<code><b>Raw</b></code>{@code LongBits(b)}<br>
* Under this relation, {@code +0.0} and {@code -0.0} are
* distinguished from each other and every bit pattern encoding a NaN
* is distinguished from every other bit pattern encoding a NaN.
* </dd>
*
* <dt><i><a id=repEquivalence>representation equivalence</a></i>:</dt>
* <dd>The two floating-point values represent the the same IEEE 754
* <i>datum</i>. In particular, for {@linkplain #isFinite(double)
* finite} values, the sign, {@linkplain Math#getExponent(double)
* exponent}, and significand components of the
* floating-point values are the same. Under this relation:
* <ul>
* <li> {@code +0.0} and {@code -0.0} are distinguished from each other.
* <li> every bit pattern encoding a NaN is considered equivalent to each other
* <li> positive infinity is equivalent to positive infinity; negative
* infinity is equivalent to negative infinity.
* </ul>
* Expressions implementing this equivalence relation include:
* <ul>
* <li>{@code Double.doubleToLongBits(a) == Double.doubleToLongBits(b)}
* <li>{@code Double.valueOf(a).equals(Double.valueOf(b))}
* <li>{@code Double.compare(a, b) == 0}
* </ul>
* Note that representation equivalence is often an appropriate notion
* of equivalence to test the behavior of {@linkplain StrictMath math
* libraries}.
* </dd>
* </dl>
*
* For two binary floating-point values {@code a} and {@code b}, if
* neither of {@code a} and {@code b} is zero or NaN, then the three
* relations numerical equality, bit-wise equivalence, and
* representation equivalence of {@code a} and {@code b} have the same
* {@code true}/{@code false} value. In other words, for binary
* floating-point values, the three relations only differ if at least
* one argument is zero or NaN.
*
* @jls 4.2.3 Floating-Point Types, Formats, and Values * @jls 4.2.3 Floating-Point Types, Formats, and Values
* @jls 4.2.4. Floating-Point Operations * @jls 4.2.4. Floating-Point Operations
* @jls 15.21.1 Numerical Equality Operators == and != * @jls 15.21.1 Numerical Equality Operators == and !=

View file

@ -3087,6 +3087,10 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* @apiNote * @apiNote
* Note: this class has a natural ordering that is inconsistent with equals. * Note: this class has a natural ordering that is inconsistent with equals.
* The behavior of comparing the result of this method for
* equality to 0 is analogous to checking the <a
* href="{@docRoot}/java.base/java/lang/Double.html#fpNumericalEq">numerical
* equality</a> of {@code double} values.
* *
* @param val {@code BigDecimal} to which this {@code BigDecimal} is * @param val {@code BigDecimal} to which this {@code BigDecimal} is
* to be compared. * to be compared.
@ -3179,6 +3183,9 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
* HALF_UP)} which evaluates to 0.7 and <br> * HALF_UP)} which evaluates to 0.7 and <br>
* {@code new BigDecimal("2.00").divide(BigDecimal.valueOf(3), * {@code new BigDecimal("2.00").divide(BigDecimal.valueOf(3),
* HALF_UP)} which evaluates to 0.67. * HALF_UP)} which evaluates to 0.67.
* The behavior of this method is analogous to checking the <a
* href="{@docRoot}/java.base/java/lang/Double.html#repEquivalence">representation
* equivalence</a> of {@code double} values.
* *
* @param x {@code Object} to which this {@code BigDecimal} is * @param x {@code Object} to which this {@code BigDecimal} is
* to be compared. * to be compared.