From 2393649538a1fc33801d50c257b4e8dbeb2f821b Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Fri, 17 Oct 2025 16:08:49 -0700 Subject: [PATCH 1/2] JDK-8370057: Correct scale handling of BigDecimal.sqrt --- src/java.base/share/classes/java/math/BigDecimal.java | 7 ++++--- test/jdk/java/math/BigDecimal/SquareRootTests.java | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/java.base/share/classes/java/math/BigDecimal.java b/src/java.base/share/classes/java/math/BigDecimal.java index 199b6648cdd94..31ee05c917f1f 100644 --- a/src/java.base/share/classes/java/math/BigDecimal.java +++ b/src/java.base/share/classes/java/math/BigDecimal.java @@ -154,7 +154,7 @@ * Subtractmax(minuend.scale(), subtrahend.scale()) * Multiplymultiplier.scale() + multiplicand.scale() * Dividedividend.scale() - divisor.scale() - * Square rootradicand.scale()/2 + * Square rootceil(radicand.scale()/2.0) * * * @@ -2113,7 +2113,7 @@ public BigDecimal[] divideAndRemainder(BigDecimal divisor, MathContext mc) { * with rounding according to the context settings. * *

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 @@ -2174,7 +2174,8 @@ public BigDecimal sqrt(MathContext mc) { // The code below favors relative simplicity over checking // for special cases that could run faster. - final int preferredScale = this.scale/2; + // final int preferredScale = this.scale/2; + final int preferredScale = Math.ceilDiv(this.scale, 2); BigDecimal result; if (mc.roundingMode == RoundingMode.UNNECESSARY || mc.precision == 0) { // Exact result requested diff --git a/test/jdk/java/math/BigDecimal/SquareRootTests.java b/test/jdk/java/math/BigDecimal/SquareRootTests.java index 7d9fce4caa0d8..90de82ff7c769 100644 --- a/test/jdk/java/math/BigDecimal/SquareRootTests.java +++ b/test/jdk/java/math/BigDecimal/SquareRootTests.java @@ -348,7 +348,7 @@ private static int lowPrecisionPerfectSquares() { for (int scale = 0; scale <= 4; scale++) { BigDecimal scaledSquare = square.setScale(scale, RoundingMode.UNNECESSARY); - int expectedScale = scale/2; + int expectedScale = Math.ceilDiv(scale, 2); for (int precision = 0; precision <= 5; precision++) { for (RoundingMode rm : RoundingMode.values()) { MathContext mc = new MathContext(precision, rm); @@ -582,7 +582,8 @@ public static BigDecimal sqrt(BigDecimal bd, MathContext mc) { // The code below favors relative simplicity over checking // for special cases that could run faster. - int preferredScale = bd.scale()/2; + int preferredScale = Math.ceilDiv(bd.scale(), 2); + BigDecimal zeroWithFinalPreferredScale = BigDecimal.valueOf(0L, preferredScale); From aa5d60fe8652a61fa773f3e67fd4f3a3a59957af Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Mon, 20 Oct 2025 08:02:54 -0700 Subject: [PATCH 2/2] Respond to review feedback. --- src/java.base/share/classes/java/math/BigDecimal.java | 1 - test/jdk/java/math/BigDecimal/SquareRootTests.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/math/BigDecimal.java b/src/java.base/share/classes/java/math/BigDecimal.java index 31ee05c917f1f..14d81d30c3d40 100644 --- a/src/java.base/share/classes/java/math/BigDecimal.java +++ b/src/java.base/share/classes/java/math/BigDecimal.java @@ -2174,7 +2174,6 @@ public BigDecimal sqrt(MathContext mc) { // The code below favors relative simplicity over checking // for special cases that could run faster. - // final int preferredScale = this.scale/2; final int preferredScale = Math.ceilDiv(this.scale, 2); BigDecimal result; diff --git a/test/jdk/java/math/BigDecimal/SquareRootTests.java b/test/jdk/java/math/BigDecimal/SquareRootTests.java index 90de82ff7c769..1a685c8483aaa 100644 --- a/test/jdk/java/math/BigDecimal/SquareRootTests.java +++ b/test/jdk/java/math/BigDecimal/SquareRootTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it