Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8263205

Add discussion of IEEE 754 to BigDecimal

    XMLWordPrintable

Details

    • CSR
    • Resolution: Approved
    • P4
    • 17
    • core-libs
    • None
    • minimal
    • Mostly an informative spec clarification; explicitly mentions divide by zero throwing exceptions.
    • Java API
    • SE

    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:

      Attachments

        Issue Links

          Activity

            People

              darcy Joe Darcy
              darcy Joe Darcy
              Brian Burkhalter
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: