RFR: 8341402: BigDecimal's square root optimization [v17]

Raffaello Giulietti rgiulietti at openjdk.org
Mon Nov 18 14:16:59 UTC 2024


On Fri, 15 Nov 2024 14:21:21 GMT, fabioromano1 <duke at openjdk.org> wrote:

>> After changing `BigInteger.sqrt()` algorithm, this can be also used to speed up `BigDecimal.sqrt()` implementation. Here is how I made it.
>> 
>> The main steps of the algorithm are as follows:
>> first argument reduce the value to an integer using the following relations:
>> 
>> x = y * 10 ^ exp
>> sqrt(x) = sqrt(y) * 10^(exp / 2) if exp is even
>> sqrt(x) = sqrt(y*10) * 10^((exp-1)/2) is exp is odd
>> 
>> Then use BigInteger.sqrt() on the reduced value to compute the numerical digits of the desired result.
>> 
>> Finally, scale back to the desired exponent range and perform any adjustment to get the preferred scale in the representation.
>
> fabioromano1 has updated the pull request incrementally with one additional commit since the last revision:
> 
>   Optimize sqrt branch for exact results

src/java.base/share/classes/java/math/BigDecimal.java line 2248:

> 2246:                             }
> 2247:                         }
> 2248:                     } else { // mc.roundingMode == RoundingMode.UP || mc.roundingMode == RoundingMode.CEILING

It would be more robust to make all enum constant explicit, and reserve the `else` to throw a `RuntimeException` of some sort, e.g., `MatchException`. Should an additional enum constant be added to `RoundingMode` in the future, this code will then throw instead of silently producing a wrong result.

If possible at all, it would be preferable to use a `switch` rather than `if`s.

src/java.base/share/classes/java/math/RoundingMode.java line 425:

> 423:             default -> false;
> 424:         };
> 425:     }

For this PR, it would be preferable to move this method as a private static in BigDecimal itself, even if its usefulness is more broad.

Also, I suggest making all the cases explicit, like so

Suggestion:

    private static boolean isHalfWay(RoundingMode m) {
        return switch (m) {
            case HALF_DOWN, HALF_UP, HALF_EVEN -> true;
            case FLOOR, CEILING, DOWN, UP, UNNECESSARY -> false;
        };
    }


In this way, should another enum constant be added in the future, the method will throw instead of silently returning a wrong value, indicating that a new case must be added to the switch for it to be exhaustive. (There's a hidden `default` that throws.)

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/21301#discussion_r1846658170
PR Review Comment: https://git.openjdk.org/jdk/pull/21301#discussion_r1846627164


More information about the core-libs-dev mailing list