# Add discussion of IEEE 754 to BigDecimal

XMLWordPrintable

#### Details

• Type: CSR
• Status: Closed
• Priority: P4
• Resolution: Approved
• Fix Version/s:
• Component/s:
• Labels:
None
• Subcomponent:
• Compatibility Risk:
minimal
• Compatibility Risk Description:
Mostly an informative spec clarification; explicitly mentions divide by zero throwing exceptions.
• Interface Kind:
Java API
• Scope:
SE

## 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 @@
*
+ * <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:``````

#### People

Assignee:
Joe Darcy
Reporter:
Joe Darcy
Reviewed By:
Brian Burkhalter