aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Ian Graves <igraves@openjdk.org> 2021-04-16 20:05:48 +0000
committerGravatar Roger Riggs <rriggs@openjdk.org> 2021-04-16 20:05:48 +0000
commit0bdc3e7a41b5fbc58a984f1edb64a1b0b4860086 (patch)
treefea7d53409e244558c085d2344cb9e4fad2cb1b2
parent4413dbfbdb66a572406200dfec67e60e9d679642 (diff)
downloadjdk-0bdc3e7a41b5fbc58a984f1edb64a1b0b4860086.tar.gz
jdk-0bdc3e7a41b5fbc58a984f1edb64a1b0b4860086.zip
8262744: Formatter '%g' conversion uses wrong format for BigDecimal rounding up to limits
Reviewed-by: rriggs, bpb
-rw-r--r--src/java.base/share/classes/java/util/Formatter.java7
-rw-r--r--test/jdk/java/util/Formatter/BigDecimalRounding.java62
2 files changed, 65 insertions, 4 deletions
diff --git a/src/java.base/share/classes/java/util/Formatter.java b/src/java.base/share/classes/java/util/Formatter.java
index c83e20b7554..e125548b506 100644
--- a/src/java.base/share/classes/java/util/Formatter.java
+++ b/src/java.base/share/classes/java/util/Formatter.java
@@ -3821,11 +3821,10 @@ public final class Formatter implements Closeable, Flushable {
else if (precision == 0)
prec = 1;
- BigDecimal tenToTheNegFour = BigDecimal.valueOf(1, 4);
- BigDecimal tenToThePrec = BigDecimal.valueOf(1, -prec);
+ value = value.round(new MathContext(prec));
if ((value.equals(BigDecimal.ZERO))
- || ((value.compareTo(tenToTheNegFour) != -1)
- && (value.compareTo(tenToThePrec) == -1))) {
+ || ((value.compareTo(BigDecimal.valueOf(1, 4)) != -1)
+ && (value.compareTo(BigDecimal.valueOf(1, -prec)) == -1))) {
int e = - value.scale()
+ (value.unscaledValue().toString().length() - 1);
diff --git a/test/jdk/java/util/Formatter/BigDecimalRounding.java b/test/jdk/java/util/Formatter/BigDecimalRounding.java
new file mode 100644
index 00000000000..6600eba6cef
--- /dev/null
+++ b/test/jdk/java/util/Formatter/BigDecimalRounding.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2021, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8262744
+ * @summary BigDecimal does not always display formatting correctly because
+ * rounding is done after formatting check. Fix moves rounding to before the
+ * range-based formatting check for %g formatting flag.
+ * @run testng BigDecimalRounding
+ */
+
+import org.testng.annotations.Test;
+
+import java.math.BigDecimal;
+
+import static org.testng.Assert.*;
+
+@Test
+public class BigDecimalRounding {
+
+ public static void testBigDecimalRounding() {
+ var res1 = String.format("%g", 0.00009999999999999995);
+ var res2 = String.format("%g", 0.00009999999f);
+ var res3 = String.format("%g", new BigDecimal(0.0001));
+ var res4 = String.format("%g", new BigDecimal("0.00009999999999999999995"));
+
+ assertEquals(res1, res2);
+ assertEquals(res2, res3);
+ assertEquals(res3, res4);
+
+ var res5 = String.format("%.9g", 999999.999999432168754e+3);
+ var res6 = String.format("%.9g", 999999999.999432168754f);
+ var res7 = String.format("%.9g", new BigDecimal("999999.999999432168754e+3")); // !!
+ var res8 = String.format("%.9g", new BigDecimal("1000000000")); // !!
+
+ assertEquals(res5, res6);
+ assertEquals(res6, res7);
+ assertEquals(res7, res8);
+
+ }
+}