JDK-8263205 : Add discussion of IEEE 754 to BigDecimal
  • Type: CSR
  • Component: core-libs
  • Sub-Component: java.math
  • Priority: P4
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 17
  • Submitted: 2021-03-08
  • Updated: 2021-03-09
  • Resolved: 2021-03-08
Related Reports
CSR :  
Description
Summary
-------
Add a discussion of how IEEE 754 decimal arithmetic relates to `BigDecimal` arithmetic. Make some exceptional cases more explicit.

Problem
-------
The `BigDecimal` class does not discuss how it differs from the decimal arithmetic standardized in IEEE 754.

Solution
--------

Update `BigDecimal` and other classes in `java.math` accordingly.

Specification
-------------

    diff --git a/src/java.base/share/classes/java/math/BigDecimal.java b/src/java.base/share/classes/java/math/BigDecimal.java
    index 7257a6f349e..5bb8a58184e 100644
    --- a/src/java.base/share/classes/java/math/BigDecimal.java
    +++ b/src/java.base/share/classes/java/math/BigDecimal.java
    @@ -37,7 +37,7 @@
     /**
      * Immutable, arbitrary-precision signed decimal numbers.  A
      * {@code BigDecimal} consists of an arbitrary precision integer
    - * <i>unscaled value</i> and a 32-bit integer <i>scale</i>.  If zero
    + * <i>{@linkplain unscaledValue() unscaled value}</i> and a 32-bit integer <i>{@linkplain scale() scale}</i>.  If zero
      * or positive, the scale is the number of digits to the right of the
      * decimal point.  If negative, the unscaled value of the number is
      * multiplied by ten to the power of the negation of the scale.  The
    @@ -220,6 +220,63 @@
      * Comparable}, {@link java.util.SortedMap} or {@link
      * java.util.SortedSet} for more information.
      *
    + * <h2>Relation to IEEE 754 Decimal Arithmetic</h2>
    + *
    + * Starting with its 2008 revision, the <cite>IEEE 754 Standard for
    + * Floating-point Arithmetic</cite> has covered decimal formats and
    + * operations. While there are broad similarities in the decimal
    + * arithmetic defined by IEEE 754 and by this class, there are notable
    + * differences as well. The fundamental similarity shared by {@code
    + * BigDecimal} and IEEE 754 decimal arithmetic is the conceptual
    + * operation of computing the mathematical infinitely precise real
    + * number value of an operation and then mapping that real number to a
    + * representable decimal floating-point value under a <em>rounding
    + * policy</em>. The rounding policy is called a {@linkplain
    + * RoundingMode rounding mode} for {@code BigDecimal} and called a
    + * rounding-direction attribute in IEEE 754-2019. When the exact value
    + * is not representable, the rounding policy determines which of the
    + * two representable decimal values bracketing the exact value is
    + * selected as the computed result. The notion of a <em>preferred
    + * scale/preferred exponent</em> is also shared by both systems.
    + *
    + * <p>For differences, IEEE 754 includes several kinds of values not
    + * modeled by {@code BigDecimal} including negative zero, signed
    + * infinities, and NaN (not-a-number). IEEE 754 defines formats, which
    + * are parameterized by base (binary or decimal), number of digits of
    + * precision, and exponent range. A format determines the set of
    + * representable values. Most operations accept as input one or more
    + * values of a given format and produce a result in the same format.
    + * A {@code BigDecimal}'s {@linkplain scale() scale} is equivalent to
    + * negating an IEEE 754 value's exponent. {@code BigDecimal} values do
    + * not have a format in the same sense; all values have the same
    + * possible range of scale/exponent and the {@linkplain
    + * unscaledValue() unscaled value} has arbitrary precision. Instead,
    + * for the {@code BigDecimal} operations taking a {@code MathContext}
    + * parameter, if the {@code MathContext} has a nonzero precision, the
    + * set of possible representable values for the result is determined
    + * by the precision of the {@code MathContext} argument. For example
    + * in {@code BigDecimal}, if a nonzero three-digit number and a
    + * nonzero four-digit number are multiplied together in the context of
    + * a {@code MathContext} object having a precision of three, the result
    + * will have three digits (assuming no overflow or underflow, etc.).
    + *
    + * <p>The rounding policies implemented by {@code BigDecimal}
    + * operations indicated by {@linkplain RoundingMode rounding modes}
    + * are a proper superset of the IEEE 754 rounding-direction
    + * attributes.
    +
    + * <p>{@code BigDecimal} arithmetic will most resemble IEEE 754
    + * decimal arithmetic if a {@code MathContext} corresponding to an
    + * IEEE 754 decimal format, such as {@linkplain MathContext#DECIMAL64
    + * decimal64} or {@linkplain MathContext#DECIMAL128 decimal128} is
    + * used to round all starting values and intermediate operations. The
    + * numerical values computed can differ if the exponent range of the
    + * IEEE 754 format being approximated is exceeded since a {@code
    + * MathContext} does not constrain the scale of {@code BigDecimal}
    + * results. Operations that would generate a NaN or exact infinity,
    + * such as dividing by zero, throw an {@code ArithmeticException} in
    + * {@code BigDecimal} arithmetic.
    + *
      * @see     BigInteger
      * @see     MathContext
      * @see     RoundingMode
    @@ -1681,7 +1738,7 @@ public BigDecimal divide(BigDecimal divisor, RoundingMode roundingMode) {
          *
          * @param  divisor value by which this {@code BigDecimal} is to be divided.
          * @throws ArithmeticException if the exact quotient does not have a
    -     *         terminating decimal expansion
    +     *         terminating decimal expansion, including dividing by zero
          * @return {@code this / divisor}
          * @since 1.5
          * @author Joseph D. Darcy
    @@ -1745,7 +1802,7 @@ public BigDecimal divide(BigDecimal divisor) {
          * @throws ArithmeticException if the result is inexact but the
          *         rounding mode is {@code UNNECESSARY} or
          *         {@code mc.precision == 0} and the quotient has a
    -     *         non-terminating decimal expansion.
    +     *         non-terminating decimal expansion,including dividing by zero
          * @since  1.5
          */
         public BigDecimal divide(BigDecimal divisor, MathContext mc) {
    diff --git a/src/java.base/share/classes/java/math/MathContext.java b/src/java.base/share/classes/java/math/MathContext.java
    index 028ede34de6..5c759666eee 100644
    --- a/src/java.base/share/classes/java/math/MathContext.java
    +++ b/src/java.base/share/classes/java/math/MathContext.java
    @@ -69,39 +69,39 @@
     
         /* ----- Public Properties ----- */
         /**
    -     *  A {@code MathContext} object whose settings have the values
    -     *  required for unlimited precision arithmetic.
    -     *  The values of the settings are:
    -     *  <code>
    -     *  precision=0 roundingMode=HALF_UP
    -     *  </code>
    +     * A {@code MathContext} object whose settings have the values
    +     * required for unlimited precision arithmetic.
    +     * The values of the settings are: {@code precision=0 roundingMode=HALF_UP}
          */
         public static final MathContext UNLIMITED =
             new MathContext(0, RoundingMode.HALF_UP);
     
         /**
    -     *  A {@code MathContext} object with a precision setting
    -     *  matching the IEEE 754R Decimal32 format, 7 digits, and a
    -     *  rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}, the
    -     *  IEEE 754R default.
    +     * A {@code MathContext} object with a precision setting
    +     * matching the precision of the IEEE 754-2019 decimal32 format, 7 digits, and a
    +     * rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}.
    +     * Note the exponent range of decimal32 is <em>not</em> used for
    +     * rounding.
          */
         public static final MathContext DECIMAL32 =
             new MathContext(7, RoundingMode.HALF_EVEN);
     
         /**
    -     *  A {@code MathContext} object with a precision setting
    -     *  matching the IEEE 754R Decimal64 format, 16 digits, and a
    -     *  rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}, the
    -     *  IEEE 754R default.
    +     * A {@code MathContext} object with a precision setting
    +     * matching the precision of the IEEE 754-2019 decimal64 format, 16 digits, and a
    +     * rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}.
    +     * Note the exponent range of decimal64 is <em>not</em> used for
    +     * rounding.
          */
         public static final MathContext DECIMAL64 =
             new MathContext(16, RoundingMode.HALF_EVEN);
     
         /**
    -     *  A {@code MathContext} object with a precision setting
    -     *  matching the IEEE 754R Decimal128 format, 34 digits, and a
    -     *  rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}, the
    -     *  IEEE 754R default.
    +     * A {@code MathContext} object with a precision setting
    +     * matching the precision of the IEEE 754-2019 decimal128 format, 34 digits, and a
    +     * rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}.
    +     * Note the exponent range of decimal64 is <em>not</em> used for
    +     * rounding.
          */
         public static final MathContext DECIMAL128 =
             new MathContext(34, RoundingMode.HALF_EVEN);
    diff --git a/src/java.base/share/classes/java/math/RoundingMode.java b/src/java.base/share/classes/java/math/RoundingMode.java
    index de7c33e5392..92e9463c932 100644
    --- a/src/java.base/share/classes/java/math/RoundingMode.java
    +++ b/src/java.base/share/classes/java/math/RoundingMode.java
    @@ -29,7 +29,7 @@
     package java.math;
     
     /**
    - * Specifies a <i>rounding behavior</i> for numerical operations
    + * Specifies a <i>rounding policy</i> for numerical operations
      * capable of discarding precision. Each rounding mode indicates how
      * the least significant returned digit of a rounded result is to be
      * calculated.  If fewer digits are returned than the digits needed to
    @@ -89,7 +89,7 @@
      *
      * @apiNote
      * Five of the rounding modes declared in this class correspond to
    - * rounding direction attributes defined in the <cite>IEEE Standard
    + * rounding-direction attributes defined in the <cite>IEEE Standard
      * for Floating-Point Arithmetic</cite>, IEEE 754-2019. Where present,
      * this correspondence will be noted in the documentation of the
      * particular constant.
    @@ -137,7 +137,7 @@
              * Rounding mode to round towards zero.  Never increments the digit
              * prior to a discarded fraction (i.e., truncates).  Note that this
              * rounding mode never increases the magnitude of the calculated value.
    -         * This mode corresponds to the IEEE 754-2019 rounding
    +         * This mode corresponds to the IEEE 754-2019 rounding-direction
              * attribute roundTowardZero.
              *
              *<p>Example:
    @@ -168,7 +168,7 @@
              * result is positive, behaves as for {@code RoundingMode.UP};
              * if negative, behaves as for {@code RoundingMode.DOWN}.  Note
              * that this rounding mode never decreases the calculated value.
    -         * This mode corresponds to the IEEE 754-2019 rounding
    +         * This mode corresponds to the IEEE 754-2019 rounding-direction
              * attribute roundTowardPositive.
              *
              *<p>Example:
    @@ -199,7 +199,7 @@
              * result is positive, behave as for {@code RoundingMode.DOWN};
              * if negative, behave as for {@code RoundingMode.UP}.  Note that
              * this rounding mode never increases the calculated value.
    -         * This mode corresponds to the IEEE 754-2019 rounding
    +         * This mode corresponds to the IEEE 754-2019 rounding-direction
              * attribute roundTowardNegative.
              *
              *<p>Example:
    @@ -232,7 +232,7 @@
              * fraction is &ge; 0.5; otherwise, behaves as for
              * {@code RoundingMode.DOWN}.  Note that this is the rounding
              * mode commonly taught at school.
    -         * This mode corresponds to the IEEE 754-2019 rounding
    +         * This mode corresponds to the IEEE 754-2019 rounding-direction
              * attribute roundTiesToAway.
              *
              *<p>Example:
    @@ -301,7 +301,7 @@
              * chiefly used in the USA.  This rounding mode is analogous to
              * the rounding policy used for {@code float} and {@code double}
              * arithmetic in Java.
    -         * This mode corresponds to the IEEE 754-2019 rounding
    +         * This mode corresponds to the IEEE 754-2019 rounding-direction
              * attribute roundTiesToEven.
              *
              *<p>Example:


Comments
Moving to Approved.
08-03-2021