JDK-8370151 : Correct scale handling of BigDecimal.sqrt
  • Type: CSR
  • Component: core-libs
  • Sub-Component: java.math
  • Priority: P4
  • Status: Provisional
  • Resolution: Unresolved
  • Fix Versions: 26
  • Submitted: 2025-10-17
  • Updated: 2025-10-21
Related Reports
CSR :  
Description
Summary
-------
Change the preferred scale of `BigDecimal.sqrt` to align with IEEE 754.

Problem
-------

Due to an oversight when `BigDecimal.sqrt` was first added to the platform (JDK-4851777 ), the preferred scale was defined as floor(argumentScale / 2.0) rather than ceil(argumentScale / 2.0).

IEEE 754 specified preferred _exponents_ where the exponent is the negated scale. Therefore, since IEEE 754 specifies floor(argumentScale / 2.0) the correct translation for `BigDecimal` is ceil(argumentScale / 2.0). The computations are equivalent for even scales/exponents. In the case of odd scale/exponents, the result differs by one.

Solution
--------

Change the specification to require the intended scale.

This change does have some nonzero behavioral compatibility impact; however, there are a number of mitigating factors:

 * Before and after this change, numerically equal results will be returned. If the results differ, they will only differ in their representation.
 * If the scale of the argument is even, the preferred scale is the same before and after this change.
 * The scale is only _preferred_ and the scale of the result is also a function of other factors, including the precision being used for the computation. 

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

    --- a/src/java.base/share/classes/java/math/BigDecimal.java
    +++ b/src/java.base/share/classes/java/math/BigDecimal.java
    @@ -154,7 +154,7 @@
      * <tr><th scope="row">Subtract</th><td>max(minuend.scale(), subtrahend.scale())</td>
      * <tr><th scope="row">Multiply</th><td>multiplier.scale() + multiplicand.scale()</td>
      * <tr><th scope="row">Divide</th><td>dividend.scale() - divisor.scale()</td>
    - * <tr><th scope="row">Square root</th><td>radicand.scale()/2</td>
    + * <tr><th scope="row">Square root</th><td>ceil(radicand.scale()/2.0)</td>
      * </tbody>
      * </table>
      *
    @@ -2113,7 +2113,7 @@
          * with rounding according to the context settings.
          *
          * <p>The preferred scale of the returned result is equal to
    -     * {@code this.scale()/2}. The value of the returned result is
    +     * {@code Math.ceilDiv(this.scale(), 2)}. The value of the returned result is
          * always within one ulp of the exact decimal value for the
          * precision in question.  If the rounding mode is {@link
          * RoundingMode#HALF_UP HALF_UP}, {@link RoundingMode#HALF_DOWN


Comments
Moving to Provisional.
21-10-2025

(Partially, this is a notational issue. Previous the preferred scale for BigDecimal.sqrt was defined as `this.scale()/2` as a Java expression on `int` values. IEEE 754 uses a "math" expression of `floor(Q(x) / 2).` where `Q` returns the quantum/exponent of the decimal value.)
21-10-2025

(To be more precise, AFAICT the preferred scale was, in fact, defined as argumentScale / 2, not as floor(argumentScale / 2), which is different.)
20-10-2025