localization
@@ -1360,8 +1366,8 @@
* m or a is equal to the precision. If the precision is not
* specified then the default value is {@code 6}. If the precision is less
* than the number of digits which would appear after the decimal point in
- * the string returned by {@link Float#toString(float)} or {@link
- * Double#toString(double)} respectively, then the value will be rounded
+ * the string returned by {@link
+ * Double#toString(double)}, then the value will be rounded
* using the {@linkplain java.math.RoundingMode#HALF_UP round half up
* algorithm}. Otherwise, zeros may be appended to reach the precision.
* For a canonical representation of the value, use {@link
@@ -3512,19 +3518,16 @@ private void print(Formatter fmt, double value, Locale l) throws IOException {
appendJustified(fmt.a, sb);
}
- // !Double.isInfinite(value) && !Double.isNaN(value)
+ // !Double.isInfinite(value) && !Double.isNaN(value) && value sign bit is 0
private void print(Formatter fmt, StringBuilder sb, double value, Locale l,
- int flags, char c, int precision, boolean neg)
- throws IOException
- {
+ int flags, char c, int precision, boolean neg) {
if (c == Conversion.SCIENTIFIC) {
- // Create a new FormattedFloatingDecimal with the desired
+ // Create a new FormattedFPDecimal with the desired
// precision.
int prec = (precision == -1 ? 6 : precision);
- FormattedFloatingDecimal fd
- = FormattedFloatingDecimal.valueOf(value, prec,
- FormattedFloatingDecimal.Form.SCIENTIFIC);
+ FormattedFPDecimal fd = FormattedFPDecimal.valueOf(
+ value, prec, FormattedFPDecimal.SCIENTIFIC);
StringBuilder mant = new StringBuilder().append(fd.getMantissa());
addZeros(mant, prec);
@@ -3552,13 +3555,12 @@ private void print(Formatter fmt, StringBuilder sb, double value, Locale l,
localizedMagnitudeExp(fmt, sb, exp, 1, l);
} else if (c == Conversion.DECIMAL_FLOAT) {
- // Create a new FormattedFloatingDecimal with the desired
+ // Create a new FormattedFPDecimal with the desired
// precision.
int prec = (precision == -1 ? 6 : precision);
- FormattedFloatingDecimal fd
- = FormattedFloatingDecimal.valueOf(value, prec,
- FormattedFloatingDecimal.Form.DECIMAL_FLOAT);
+ FormattedFPDecimal fd = FormattedFPDecimal.valueOf(
+ value, prec, FormattedFPDecimal.PLAIN);
StringBuilder mant = new StringBuilder().append(fd.getMantissa());
addZeros(mant, prec);
@@ -3587,9 +3589,8 @@ else if (precision == 0)
mant.append('0');
expRounded = 0;
} else {
- FormattedFloatingDecimal fd
- = FormattedFloatingDecimal.valueOf(value, prec,
- FormattedFloatingDecimal.Form.GENERAL);
+ FormattedFPDecimal fd = FormattedFPDecimal.valueOf(
+ value, prec, FormattedFPDecimal.GENERAL);
exp = fd.getExponent();
mant.append(fd.getMantissa());
expRounded = fd.getExponentRounded();
diff --git a/src/java.base/share/classes/jdk/internal/math/DoubleToDecimal.java b/src/java.base/share/classes/jdk/internal/math/DoubleToDecimal.java
index d6a45a3e9da32..e3472d559b2c1 100644
--- a/src/java.base/share/classes/jdk/internal/math/DoubleToDecimal.java
+++ b/src/java.base/share/classes/jdk/internal/math/DoubleToDecimal.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2023, 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
@@ -35,7 +35,7 @@
/**
* This class exposes a method to render a {@code double} as a string.
*/
-final public class DoubleToDecimal {
+public final class DoubleToDecimal {
/*
* For full details about this code see the following references:
*
@@ -110,12 +110,13 @@ final public class DoubleToDecimal {
*/
public static final int MAX_CHARS = H + 7;
- private final byte[] bytes = new byte[MAX_CHARS];
+ private final byte[] bytes;
/* Index into bytes of rightmost valid character */
private int index;
- private DoubleToDecimal() {
+ private DoubleToDecimal(boolean noChars) {
+ bytes = noChars ? null : new byte[MAX_CHARS];
}
/**
@@ -127,7 +128,28 @@ private DoubleToDecimal() {
* @see Double#toString(double)
*/
public static String toString(double v) {
- return new DoubleToDecimal().toDecimalString(v);
+ return new DoubleToDecimal(false).toDecimalString(v);
+ }
+
+ /**
+ * Splits the decimal d described in
+ * {@link Double#toString(double)} in integers f and e
+ * such that d = f 10e .
+ *
+ * Further, determines integer n such that n = 0 when
+ * f = 0, and
+ * 10n -1 ≤ f < 10n
+ * otherwise.
+ *
+ *
The argument {@code v} is assumed to be a positive finite value or
+ * positive zero.
+ * Further, {@code fd} must not be {@code null}.
+ *
+ * @param v the finite {@code double} to be split.
+ * @param fd the object that will carry f , e , and n .
+ */
+ public static void split(double v, FormattedFPDecimal fd) {
+ new DoubleToDecimal(true).toDecimal(v, fd);
}
/**
@@ -143,11 +165,11 @@ public static String toString(double v) {
*/
public static Appendable appendTo(double v, Appendable app)
throws IOException {
- return new DoubleToDecimal().appendDecimalTo(v, app);
+ return new DoubleToDecimal(false).appendDecimalTo(v, app);
}
private String toDecimalString(double v) {
- return switch (toDecimal(v)) {
+ return switch (toDecimal(v, null)) {
case NON_SPECIAL -> charsToString();
case PLUS_ZERO -> "0.0";
case MINUS_ZERO -> "-0.0";
@@ -159,7 +181,7 @@ private String toDecimalString(double v) {
private Appendable appendDecimalTo(double v, Appendable app)
throws IOException {
- switch (toDecimal(v)) {
+ switch (toDecimal(v, null)) {
case NON_SPECIAL:
char[] chars = new char[index + 1];
for (int i = 0; i < chars.length; ++i) {
@@ -191,7 +213,7 @@ private Appendable appendDecimalTo(double v, Appendable app)
* MINUS_INF iff v is NEGATIVE_INFINITY
* NAN iff v is NaN
*/
- private int toDecimal(double v) {
+ private int toDecimal(double v, FormattedFPDecimal fd) {
/*
* For full details see references [2] and [1].
*
@@ -207,6 +229,10 @@ private int toDecimal(double v) {
if (bq < BQ_MASK) {
index = -1;
if (bits < 0) {
+ /*
+ * fd != null implies bytes == null and bits >= 0
+ * Thus, when fd != null, control never reaches here.
+ */
append('-');
}
if (bq != 0) {
@@ -217,16 +243,16 @@ private int toDecimal(double v) {
if (0 < mq & mq < P) {
long f = c >> mq;
if (f << mq == c) {
- return toChars(f, 0);
+ return toChars(f, 0, fd);
}
}
- return toDecimal(-mq, c, 0);
+ return toDecimal(-mq, c, 0, fd);
}
if (t != 0) {
/* subnormal value */
return t < C_TINY
- ? toDecimal(Q_MIN, 10 * t, -1)
- : toDecimal(Q_MIN, t, 0);
+ ? toDecimal(Q_MIN, 10 * t, -1, fd)
+ : toDecimal(Q_MIN, t, 0, fd);
}
return bits == 0 ? PLUS_ZERO : MINUS_ZERO;
}
@@ -236,7 +262,7 @@ private int toDecimal(double v) {
return bits > 0 ? PLUS_INF : MINUS_INF;
}
- private int toDecimal(int q, long c, int dk) {
+ private int toDecimal(int q, long c, int dk, FormattedFPDecimal fd) {
/*
* The skeleton corresponds to figure 7 of [1].
* The efficient computations are those summarized in figure 9.
@@ -301,7 +327,7 @@ private int toDecimal(int q, long c, int dk) {
boolean upin = vbl + out <= sp10 << 2;
boolean wpin = (tp10 << 2) + out <= vbr;
if (upin != wpin) {
- return toChars(upin ? sp10 : tp10, k);
+ return toChars(upin ? sp10 : tp10, k, fd);
}
}
@@ -316,14 +342,14 @@ private int toDecimal(int q, long c, int dk) {
boolean win = (t << 2) + out <= vbr;
if (uin != win) {
/* Exactly one of u or w lies in Rv */
- return toChars(uin ? s : t, k + dk);
+ return toChars(uin ? s : t, k + dk, fd);
}
/*
* Both u and w lie in Rv: determine the one closest to v.
* See section 9.3 of [1].
*/
long cmp = vb - (s + t << 1);
- return toChars(cmp < 0 || cmp == 0 && (s & 0x1) == 0 ? s : t, k + dk);
+ return toChars(cmp < 0 || cmp == 0 && (s & 0x1) == 0 ? s : t, k + dk, fd);
}
/*
@@ -342,7 +368,7 @@ private static long rop(long g1, long g0, long cp) {
/*
* Formats the decimal f 10^e.
*/
- private int toChars(long f, int e) {
+ private int toChars(long f, int e, FormattedFPDecimal fd) {
/*
* For details not discussed here see section 10 of [1].
*
@@ -353,6 +379,10 @@ private int toChars(long f, int e) {
if (f >= pow10(len)) {
len += 1;
}
+ if (fd != null) {
+ fd.set(f, e, len);
+ return NON_SPECIAL;
+ }
/*
* Let fp and ep be the original f and e, respectively.
diff --git a/src/java.base/share/classes/jdk/internal/math/FormattedFPDecimal.java b/src/java.base/share/classes/jdk/internal/math/FormattedFPDecimal.java
new file mode 100644
index 0000000000000..ce9b2fc4eeae6
--- /dev/null
+++ b/src/java.base/share/classes/jdk/internal/math/FormattedFPDecimal.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2023, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package jdk.internal.math;
+
+/*
+ * This class provides support for the 'e', 'f' and 'g' conversions on double
+ * values with sign bit 0.
+ * It is worth noting that float values are converted to double values _before_
+ * control reaches code in this class.
+ *
+ * It delegates the conversion to decimal to class DoubleToDecimal to get
+ * the decimal d selected by Double.toString(double) as a pair of integers
+ * f and e meeting d = f 10^e.
+ * It then rounds d to the appropriate number of digits, as per specification,
+ * and extracts the digits of both the significand and, where required, the
+ * exponent of the rounded value.
+ *
+ * Further processing like padding, sign, grouping, localization, etc., is the
+ * responsibility of the caller.
+ */
+public final class FormattedFPDecimal {
+
+ public static final char SCIENTIFIC = 'e';
+ public static final char PLAIN = 'f';
+ public static final char GENERAL = 'g';
+
+ private long f;
+ private int e; // normalized to 0 when f = 0
+ private int n;
+ private char[] digits; // ... and often the decimal separator as well
+ private char[] exp; // [+-][e]ee, that is, sign and minimum 2 digits
+
+ private FormattedFPDecimal() {
+ }
+
+ public static FormattedFPDecimal valueOf(double v, int prec, char form) {
+ FormattedFPDecimal fd = new FormattedFPDecimal();
+ DoubleToDecimal.split(v, fd);
+ return switch (form) {
+ case SCIENTIFIC -> fd.scientific(prec);
+ case PLAIN -> fd.plain(prec);
+ case GENERAL -> fd.general(prec);
+ default -> throw new IllegalArgumentException(
+ String.format("unsupported form '%c'", form)
+ );
+ };
+ }
+
+ public void set(long f, int e, int n) {
+ /* Initially, n = 0 if f = 0, and 10^{n-1} <= f < 10^n if f != 0 */
+ this.f = f;
+ this.e = e;
+ this.n = n;
+ }
+
+ public char[] getExponent() {
+ return exp;
+ }
+
+ public char[] getMantissa() {
+ return digits;
+ }
+
+ public int getExponentRounded() {
+ return n + e - 1;
+ }
+
+ private FormattedFPDecimal plain(int prec) {
+ /*
+ * Rounding d = f 10^e to prec digits in plain mode means the same
+ * as rounding it to the p = n + e + prec most significand digits of d,
+ * with the understanding that p < 0 cuts off all its digits.
+ */
+ round(n + e + (long) prec); // n + e is well inside the int range
+ return plainChars();
+ }
+
+ private FormattedFPDecimal plainChars() {
+ if (e >= 0) {
+ plainCharsPureInteger();
+ } else if (n + e > 0) {
+ plainCharsMixed();
+ } else {
+ plainCharsPureFraction();
+ }
+ return this;
+ }
+
+ private void plainCharsPureInteger() {
+ digits = new char[n + e];
+ fillWithZeros(n, n + e);
+ fillWithDigits(f, 0, n);
+ }
+
+ private void plainCharsMixed() {
+ digits = new char[n + 1];
+ long x = fillWithDigits(f, n + 1 + e, n + 1);
+ digits[n + e] = '.';
+ fillWithDigits(x, 0, n + e);
+ }
+
+ private void plainCharsPureFraction() {
+ digits = new char[2 - e];
+ long x = f;
+ fillWithDigits(x, 2 - e - n, 2 - e);
+ fillWithZeros(0, 2 - e - n);
+ digits[1] = '.';
+ }
+
+ private FormattedFPDecimal scientific(int prec) {
+ /*
+ * Rounding d = f 10^e to prec digits in scientific mode means the same
+ * as rounding it to the p = prec + 1 most significand digits of d.
+ */
+ round(prec + 1L);
+ return scientificChars(prec);
+ }
+
+ private FormattedFPDecimal scientificChars(int prec) {
+ if (prec != 0) {
+ scientificCharsWithFraction();
+ } else {
+ scientificCharsNoFraction();
+ }
+ expChars();
+ return this;
+ }
+
+ private void scientificCharsWithFraction() {
+ digits = new char[1 + n]; // room for leading digit and for '.'
+ long x = fillWithDigits(f, 2, 1 + n);
+ digits[1] = '.';
+ digits[0] = toDigit(x);
+ }
+
+ private void scientificCharsNoFraction() {
+ digits = new char[1];
+ digits[0] = toDigit(f);
+ }
+
+ private FormattedFPDecimal general(int prec) {
+ /*
+ * Rounding d = f 10^e to prec digits in general mode means the same
+ * as rounding it to the p = prec most significand digits of d, and then
+ * deciding whether to format it in plain or scientific mode, depending
+ * on the rounded value.
+ */
+ round(prec);
+ int er = getExponentRounded();
+ if (-4 <= er && er < prec) {
+ plainChars();
+ } else {
+ scientificChars(prec - 1);
+ }
+ return this;
+ }
+
+ private void expChars() {
+ int er = getExponentRounded();
+ int aer = Math.abs(er);
+ exp = new char[aer >= 100 ? 4 : 3];
+ int q;
+ if (aer >= 100) {
+ q = aer / 10;
+ exp[3] = toDigit(aer - 10 * q);
+ aer = q;
+ }
+ q = aer / 10;
+ exp[2] = toDigit(aer - 10 * q);
+ exp[1] = toDigit(q);
+ exp[0] = er >= 0 ? '+' : '-';
+ }
+
+ private void round(long pp) {
+ /*
+ * Let d = f 10^e, and let p shorten pp.
+ * This method rounds d to the p most significant digits.
+ * It does so by possibly modifying f, e and n.
+ * When f becomes 0, e and n are normalized to 0 and 1, resp.
+ *
+ * For any real x let
+ * r(x) = floor(x + 1/2)
+ * which is rounding to the closest integer, with ties rounded toward
+ * positive infinity.
+ *
+ * When f = 0 there's not much to say, except that this holds iff n = 0.
+ *
+ * Otherwise, since
+ * 10^{n-1} <= f < 10^n
+ * it follows that
+ * 10^{e+n-1} <= d < 10^{e+n}
+ * To round d to the most significant p digits, first scale d to the
+ * range [10^{p-1}, 10^p), cutoff the fractional digits by applying r,
+ * and finally scale back.
+ * To this end, first define
+ * ds = d 10^{p-e-n}
+ * which ensures
+ * 10^{p-1} <= ds < 10^p
+ *
+ * Now, if p < 0 (that is, if p <= -1) then
+ * ds < 10^p <= 10^{-1} < 1/2
+ * so that
+ * r(ds) = 0
+ * Thus, rounding d to p < 0 digits leads to 0.
+ */
+ if (n == 0 || pp < 0) {
+ f = 0;
+ e = 0;
+ n = 1;
+ return;
+ }
+
+ /*
+ * Further, if p >= n then
+ * ds = f 10^e 10^{p-e-n} = f 10^{p-n}
+ * which shows that ds is an integer, so r(ds) = ds. That is,
+ * rounding to p >= n digits leads to a result equal to d.
+ */
+ if (pp >= n) { // no rounding needed
+ return;
+ }
+
+ /*
+ * Finally, 0 <= p < n. When p = 0 it follows that
+ * 10^{-1} <= ds < 1
+ * 0 <= f' = r(ds) <= 1
+ * that is, f' is either 0 or 1.
+ *
+ * Otherwise
+ * 10^{p-1} <= ds < 10^p
+ * 1 <= 10^{p-1} <= f' = r(ds) <= 10^p
+ * Note that f' = 10^p is a possible outcome.
+ *
+ * Scale back, where e' = e + n - p
+ * d' = f' 10^{e+n-p} = f' 10^e', with 10^{e+n-1} <= d' <= 10^{e+n}
+ *
+ * Since n > p, f' can be computed in integer arithmetic as follows,
+ * where / denotes division in the real numbers:
+ * f' = r(ds) = r(f 10^{p-n}) = r(f / 10^{n-p})
+ * = floor(f / 10^{n-p} + 1/2)
+ * = floor((f + 10^{n-p}/2) / 10^{n-p})
+ */
+ int p = (int) pp; // 0 <= pp < n, safe cast
+ e += n - p; // new e is well inside the int range
+ long pow10 = MathUtils.pow10(n - p);
+ f = (f + (pow10 >> 1)) / pow10;
+ if (p == 0) {
+ n = 1;
+ if (f == 0) {
+ e = 0;
+ }
+ return;
+ }
+
+ n = p;
+ if (f == MathUtils.pow10(p)) {
+ /*
+ * f is n + 1 digits long.
+ * Absorb one trailing zero into e and reduce f accordingly.
+ */
+ f /= 10;
+ e += 1;
+ }
+ }
+
+ /*
+ * Fills the digits section with indices in [from, to) with the lower
+ * to - from digits of x (as chars), while stripping them away from x.
+ * Returns the stripped x.
+ */
+ private long fillWithDigits(long x, int from, int to) {
+ while (to > from) {
+ long q = x / 10;
+ digits[--to] = toDigit(x - q * 10);
+ x = q;
+ }
+ return x;
+ }
+
+ /*
+ * Fills the digits section with indices in [from, to) with '0'.
+ */
+ private void fillWithZeros(int from, int to) {
+ while (to > from) {
+ digits[--to] = '0';
+ }
+ }
+
+ private static char toDigit(long d) {
+ return toDigit((int) d);
+ }
+
+ private static char toDigit(int d) {
+ return (char) (d + '0');
+ }
+
+}
diff --git a/src/java.base/share/classes/jdk/internal/math/FormattedFloatingDecimal.java b/src/java.base/share/classes/jdk/internal/math/FormattedFloatingDecimal.java
deleted file mode 100644
index 88cd1feaf8f0b..0000000000000
--- a/src/java.base/share/classes/jdk/internal/math/FormattedFloatingDecimal.java
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.
- */
-
-package jdk.internal.math;
-
-import java.util.Arrays;
-
-public class FormattedFloatingDecimal{
-
- public enum Form { SCIENTIFIC, COMPATIBLE, DECIMAL_FLOAT, GENERAL };
-
-
- public static FormattedFloatingDecimal valueOf(double d, int precision, Form form){
- FloatingDecimal.BinaryToASCIIConverter fdConverter =
- FloatingDecimal.getBinaryToASCIIConverter(d, form == Form.COMPATIBLE);
- return new FormattedFloatingDecimal(precision,form, fdConverter);
- }
-
- private int decExponentRounded;
- private char[] mantissa;
- private char[] exponent;
-
- private static final ThreadLocal threadLocalCharBuffer =
- new ThreadLocal() {
- @Override
- protected Object initialValue() {
- return new char[20];
- }
- };
-
- private static char[] getBuffer(){
- return (char[]) threadLocalCharBuffer.get();
- }
-
- private FormattedFloatingDecimal(int precision, Form form, FloatingDecimal.BinaryToASCIIConverter fdConverter) {
- if (fdConverter.isExceptional()) {
- this.mantissa = fdConverter.toJavaFormatString().toCharArray();
- this.exponent = null;
- return;
- }
- char[] digits = getBuffer();
- int nDigits = fdConverter.getDigits(digits);
- int decExp = fdConverter.getDecimalExponent();
- int exp;
- boolean isNegative = fdConverter.isNegative();
- switch (form) {
- case COMPATIBLE:
- exp = decExp;
- this.decExponentRounded = exp;
- fillCompatible(precision, digits, nDigits, exp, isNegative);
- break;
- case DECIMAL_FLOAT:
- exp = applyPrecision(decExp, digits, nDigits, decExp + precision);
- fillDecimal(precision, digits, nDigits, exp, isNegative);
- this.decExponentRounded = exp;
- break;
- case SCIENTIFIC:
- exp = applyPrecision(decExp, digits, nDigits, precision + 1);
- fillScientific(precision, digits, nDigits, exp, isNegative);
- this.decExponentRounded = exp;
- break;
- case GENERAL:
- exp = applyPrecision(decExp, digits, nDigits, precision);
- // adjust precision to be the number of digits to right of decimal
- // the real exponent to be output is actually exp - 1, not exp
- if (exp - 1 < -4 || exp - 1 >= precision) {
- // form = Form.SCIENTIFIC;
- precision--;
- fillScientific(precision, digits, nDigits, exp, isNegative);
- } else {
- // form = Form.DECIMAL_FLOAT;
- precision = precision - exp;
- fillDecimal(precision, digits, nDigits, exp, isNegative);
- }
- this.decExponentRounded = exp;
- break;
- default:
- assert false;
- }
- }
-
- // returns the exponent after rounding has been done by applyPrecision
- public int getExponentRounded() {
- return decExponentRounded - 1;
- }
-
- /**
- * Returns the mantissa as a {@code char[]}. Note that the returned value
- * is a reference to the internal {@code char[]} containing the mantissa,
- * therefore code invoking this method should not pass the return value to
- * external code but should in that case make a copy.
- *
- * @return a reference to the internal {@code char[]} representing the
- * mantissa.
- */
- public char[] getMantissa(){
- return mantissa;
- }
-
- /**
- * Returns the exponent as a {@code char[]}. Note that the returned value
- * is a reference to the internal {@code char[]} containing the exponent,
- * therefore code invoking this method should not pass the return value to
- * external code but should in that case make a copy.
- *
- * @return a reference to the internal {@code char[]} representing the
- * exponent.
- */
- public char[] getExponent(){
- return exponent;
- }
-
- /**
- * Returns new decExp in case of overflow.
- */
- private static int applyPrecision(int decExp, char[] digits, int nDigits, int prec) {
- if (prec >= nDigits || prec < 0) {
- // no rounding necessary
- return decExp;
- }
- if (prec == 0) {
- // only one digit (0 or 1) is returned because the precision
- // excludes all significant digits
- if (digits[0] >= '5') {
- digits[0] = '1';
- Arrays.fill(digits, 1, nDigits, '0');
- return decExp + 1;
- } else {
- Arrays.fill(digits, 0, nDigits, '0');
- return decExp;
- }
- }
- int q = digits[prec];
- if (q >= '5') {
- int i = prec;
- q = digits[--i];
- if ( q == '9' ) {
- while ( q == '9' && i > 0 ){
- q = digits[--i];
- }
- if ( q == '9' ){
- // carryout! High-order 1, rest 0s, larger exp.
- digits[0] = '1';
- Arrays.fill(digits, 1, nDigits, '0');
- return decExp+1;
- }
- }
- digits[i] = (char)(q + 1);
- Arrays.fill(digits, i+1, nDigits, '0');
- } else {
- Arrays.fill(digits, prec, nDigits, '0');
- }
- return decExp;
- }
-
- /**
- * Fills mantissa and exponent char arrays for compatible format.
- */
- private void fillCompatible(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {
- int startIndex = isNegative ? 1 : 0;
- if (exp > 0 && exp < 8) {
- // print digits.digits.
- if (nDigits < exp) {
- int extraZeros = exp - nDigits;
- mantissa = create(isNegative, nDigits + extraZeros + 2);
- System.arraycopy(digits, 0, mantissa, startIndex, nDigits);
- Arrays.fill(mantissa, startIndex + nDigits, startIndex + nDigits + extraZeros, '0');
- mantissa[startIndex + nDigits + extraZeros] = '.';
- mantissa[startIndex + nDigits + extraZeros+1] = '0';
- } else if (exp < nDigits) {
- int t = Math.min(nDigits - exp, precision);
- mantissa = create(isNegative, exp + 1 + t);
- System.arraycopy(digits, 0, mantissa, startIndex, exp);
- mantissa[startIndex + exp ] = '.';
- System.arraycopy(digits, exp, mantissa, startIndex+exp+1, t);
- } else { // exp == digits.length
- mantissa = create(isNegative, nDigits + 2);
- System.arraycopy(digits, 0, mantissa, startIndex, nDigits);
- mantissa[startIndex + nDigits ] = '.';
- mantissa[startIndex + nDigits +1] = '0';
- }
- } else if (exp <= 0 && exp > -3) {
- int zeros = Math.max(0, Math.min(-exp, precision));
- int t = Math.max(0, Math.min(nDigits, precision + exp));
- // write '0' s before the significant digits
- if (zeros > 0) {
- mantissa = create(isNegative, zeros + 2 + t);
- mantissa[startIndex] = '0';
- mantissa[startIndex+1] = '.';
- Arrays.fill(mantissa, startIndex + 2, startIndex + 2 + zeros, '0');
- if (t > 0) {
- // copy only when significant digits are within the precision
- System.arraycopy(digits, 0, mantissa, startIndex + 2 + zeros, t);
- }
- } else if (t > 0) {
- mantissa = create(isNegative, zeros + 2 + t);
- mantissa[startIndex] = '0';
- mantissa[startIndex + 1] = '.';
- // copy only when significant digits are within the precision
- System.arraycopy(digits, 0, mantissa, startIndex + 2, t);
- } else {
- this.mantissa = create(isNegative, 1);
- this.mantissa[startIndex] = '0';
- }
- } else {
- if (nDigits > 1) {
- mantissa = create(isNegative, nDigits + 1);
- mantissa[startIndex] = digits[0];
- mantissa[startIndex + 1] = '.';
- System.arraycopy(digits, 1, mantissa, startIndex + 2, nDigits - 1);
- } else {
- mantissa = create(isNegative, 3);
- mantissa[startIndex] = digits[0];
- mantissa[startIndex + 1] = '.';
- mantissa[startIndex + 2] = '0';
- }
- int e, expStartIntex;
- boolean isNegExp = (exp <= 0);
- if (isNegExp) {
- e = -exp + 1;
- expStartIntex = 1;
- } else {
- e = exp - 1;
- expStartIntex = 0;
- }
- // decExponent has 1, 2, or 3, digits
- if (e <= 9) {
- exponent = create(isNegExp,1);
- exponent[expStartIntex] = (char) (e + '0');
- } else if (e <= 99) {
- exponent = create(isNegExp,2);
- exponent[expStartIntex] = (char) (e / 10 + '0');
- exponent[expStartIntex+1] = (char) (e % 10 + '0');
- } else {
- exponent = create(isNegExp,3);
- exponent[expStartIntex] = (char) (e / 100 + '0');
- e %= 100;
- exponent[expStartIntex+1] = (char) (e / 10 + '0');
- exponent[expStartIntex+2] = (char) (e % 10 + '0');
- }
- }
- }
-
- private static char[] create(boolean isNegative, int size) {
- if(isNegative) {
- char[] r = new char[size +1];
- r[0] = '-';
- return r;
- } else {
- return new char[size];
- }
- }
-
- /*
- * Fills mantissa char arrays for DECIMAL_FLOAT format.
- * Exponent should be equal to null.
- */
- private void fillDecimal(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {
- int startIndex = isNegative ? 1 : 0;
- if (exp > 0) {
- // print digits.digits.
- if (nDigits < exp) {
- mantissa = create(isNegative,exp);
- System.arraycopy(digits, 0, mantissa, startIndex, nDigits);
- Arrays.fill(mantissa, startIndex + nDigits, startIndex + exp, '0');
- // Do not append ".0" for formatted floats since the user
- // may request that it be omitted. It is added as necessary
- // by the Formatter.
- } else {
- int t = Math.min(nDigits - exp, precision);
- mantissa = create(isNegative, exp + (t > 0 ? (t + 1) : 0));
- System.arraycopy(digits, 0, mantissa, startIndex, exp);
- // Do not append ".0" for formatted floats since the user
- // may request that it be omitted. It is added as necessary
- // by the Formatter.
- if (t > 0) {
- mantissa[startIndex + exp] = '.';
- System.arraycopy(digits, exp, mantissa, startIndex + exp + 1, t);
- }
- }
- } else if (exp <= 0) {
- int zeros = Math.max(0, Math.min(-exp, precision));
- int t = Math.max(0, Math.min(nDigits, precision + exp));
- // write '0' s before the significant digits
- if (zeros > 0) {
- mantissa = create(isNegative, zeros + 2 + t);
- mantissa[startIndex] = '0';
- mantissa[startIndex+1] = '.';
- Arrays.fill(mantissa, startIndex + 2, startIndex + 2 + zeros, '0');
- if (t > 0) {
- // copy only when significant digits are within the precision
- System.arraycopy(digits, 0, mantissa, startIndex + 2 + zeros, t);
- }
- } else if (t > 0) {
- mantissa = create(isNegative, zeros + 2 + t);
- mantissa[startIndex] = '0';
- mantissa[startIndex + 1] = '.';
- // copy only when significant digits are within the precision
- System.arraycopy(digits, 0, mantissa, startIndex + 2, t);
- } else {
- this.mantissa = create(isNegative, 1);
- this.mantissa[startIndex] = '0';
- }
- }
- }
-
- /**
- * Fills mantissa and exponent char arrays for SCIENTIFIC format.
- */
- private void fillScientific(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {
- int startIndex = isNegative ? 1 : 0;
- int t = Math.max(0, Math.min(nDigits - 1, precision));
- if (t > 0) {
- mantissa = create(isNegative, t + 2);
- mantissa[startIndex] = digits[0];
- mantissa[startIndex + 1] = '.';
- System.arraycopy(digits, 1, mantissa, startIndex + 2, t);
- } else {
- mantissa = create(isNegative, 1);
- mantissa[startIndex] = digits[0];
- }
- char expSign;
- int e;
- if (exp <= 0) {
- expSign = '-';
- e = -exp + 1;
- } else {
- expSign = '+' ;
- e = exp - 1;
- }
- // decExponent has 1, 2, or 3, digits
- if (e <= 9) {
- exponent = new char[] { expSign,
- '0', (char) (e + '0') };
- } else if (e <= 99) {
- exponent = new char[] { expSign,
- (char) (e / 10 + '0'), (char) (e % 10 + '0') };
- } else {
- char hiExpChar = (char) (e / 100 + '0');
- e %= 100;
- exponent = new char[] { expSign,
- hiExpChar, (char) (e / 10 + '0'), (char) (e % 10 + '0') };
- }
- }
-}
diff --git a/test/jdk/java/util/Formatter/Basic-X.java.template b/test/jdk/java/util/Formatter/Basic-X.java.template
index 9976badac22a1..e259bdad5cc09 100644
--- a/test/jdk/java/util/Formatter/Basic-X.java.template
+++ b/test/jdk/java/util/Formatter/Basic-X.java.template
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, 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
@@ -931,6 +931,16 @@ public class Basic$Type$ extends Basic {
test("%3.0e", "1e+07", 10000000.00);
test("%3.0e", "1e+08", 100000000.00);
+ //---------------------------------------------------------------------
+ // %e - adoption of Double.toString(double) algorithm
+ //---------------------------------------------------------------------
+ test("%.1e", "9.9e-324", 1e-323);
+ test("%.1e", "9.9e-323", 1e-322);
+ test("%.15e", "7.387900000000000e+20", 7.3879e20);
+ test("%.15e", "1.000000000000000e+23", 1e23);
+ test("%.16e", "2.0000000000000000e+23", 2e23);
+ test("%.16e", "1.9400994884341945e+25", 1.9400994884341945E25);
+
//---------------------------------------------------------------------
// %f
//
@@ -991,6 +1001,14 @@ public class Basic$Type$ extends Basic {
test("%,3.0f", "100,000,000", 100000000.00);
test("%,3.0f", "10,000,000", 10000000.00);
test("%,3.0f", "100,000,000", 100000000.00);
+
+ //---------------------------------------------------------------------
+ // %f - adoption of Double.toString(double) algorithm
+ //---------------------------------------------------------------------
+ test("%.0f", "738790000000000000000", 7.3879e20);
+ test("%.0f", "100000000000000000000000", 1e23);
+ test("%.0f", "200000000000000000000000", 2e23);
+ test("%.0f", "19400994884341945000000000", 1.9400994884341945E25);
#if[BigDecimal]
//---------------------------------------------------------------------
// %f - BigDecimal
@@ -1187,6 +1205,16 @@ public class Basic$Type$ extends Basic {
tryCatch("%#3.0g", FormatFlagsConversionMismatchException.class, 1000.00);
+ //---------------------------------------------------------------------
+ // %g - adoption of Double.toString(double) algorithm
+ //---------------------------------------------------------------------
+ test("%.2g", "9.9e-324", 1e-323);
+ test("%.2g", "9.9e-323", 1e-322);
+ test("%.16g", "7.387900000000000e+20", 7.3879e20);
+ test("%.16g", "1.000000000000000e+23", 1e23);
+ test("%.17g", "2.0000000000000000e+23", 2e23);
+ test("%.17g", "1.9400994884341945e+25", 1.9400994884341945E25);
+
// double PI^300
// = 13962455701329742638131355433930076081862072808 ... e+149
#if[BigDecimal]
diff --git a/test/jdk/java/util/Formatter/BasicBigDecimal.java b/test/jdk/java/util/Formatter/BasicBigDecimal.java
index 51cd19141287b..738c30eff5976 100644
--- a/test/jdk/java/util/Formatter/BasicBigDecimal.java
+++ b/test/jdk/java/util/Formatter/BasicBigDecimal.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, 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
@@ -357,6 +357,16 @@ public static void test() {
test("%3.0e", "1e+07", 10000000.00);
test("%3.0e", "1e+08", 100000000.00);
+ //---------------------------------------------------------------------
+ // %e - adoption of Double.toString(double) algorithm
+ //---------------------------------------------------------------------
+ test("%.1e", "9.9e-324", 1e-323);
+ test("%.1e", "9.9e-323", 1e-322);
+ test("%.15e", "7.387900000000000e+20", 7.3879e20);
+ test("%.15e", "1.000000000000000e+23", 1e23);
+ test("%.16e", "2.0000000000000000e+23", 2e23);
+ test("%.16e", "1.9400994884341945e+25", 1.9400994884341945E25);
+
//---------------------------------------------------------------------
// %f
//
@@ -417,6 +427,14 @@ public static void test() {
test("%,3.0f", "100,000,000", 100000000.00);
test("%,3.0f", "10,000,000", 10000000.00);
test("%,3.0f", "100,000,000", 100000000.00);
+
+ //---------------------------------------------------------------------
+ // %f - adoption of Double.toString(double) algorithm
+ //---------------------------------------------------------------------
+ test("%.0f", "738790000000000000000", 7.3879e20);
+ test("%.0f", "100000000000000000000000", 1e23);
+ test("%.0f", "200000000000000000000000", 2e23);
+ test("%.0f", "19400994884341945000000000", 1.9400994884341945E25);
//---------------------------------------------------------------------
// %f - BigDecimal
//---------------------------------------------------------------------
@@ -591,6 +609,16 @@ public static void test() {
tryCatch("%#3.0g", FormatFlagsConversionMismatchException.class, 1000.00);
+ //---------------------------------------------------------------------
+ // %g - adoption of Double.toString(double) algorithm
+ //---------------------------------------------------------------------
+ test("%.2g", "9.9e-324", 1e-323);
+ test("%.2g", "9.9e-323", 1e-322);
+ test("%.16g", "7.387900000000000e+20", 7.3879e20);
+ test("%.16g", "1.000000000000000e+23", 1e23);
+ test("%.17g", "2.0000000000000000e+23", 2e23);
+ test("%.17g", "1.9400994884341945e+25", 1.9400994884341945E25);
+
// double PI^300
// = 13962455701329742638131355433930076081862072808 ... e+149
//---------------------------------------------------------------------
diff --git a/test/jdk/java/util/Formatter/BasicDouble.java b/test/jdk/java/util/Formatter/BasicDouble.java
index 493840839c43d..1bc395713a407 100644
--- a/test/jdk/java/util/Formatter/BasicDouble.java
+++ b/test/jdk/java/util/Formatter/BasicDouble.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, 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
@@ -329,6 +329,16 @@ public static void test() {
test("%3.0e", "1e+07", 10000000.00);
test("%3.0e", "1e+08", 100000000.00);
+ //---------------------------------------------------------------------
+ // %e - adoption of Double.toString(double) algorithm
+ //---------------------------------------------------------------------
+ test("%.1e", "9.9e-324", 1e-323);
+ test("%.1e", "9.9e-323", 1e-322);
+ test("%.15e", "7.387900000000000e+20", 7.3879e20);
+ test("%.15e", "1.000000000000000e+23", 1e23);
+ test("%.16e", "2.0000000000000000e+23", 2e23);
+ test("%.16e", "1.9400994884341945e+25", 1.9400994884341945E25);
+
//---------------------------------------------------------------------
// %f
//
@@ -390,6 +400,14 @@ public static void test() {
test("%,3.0f", "10,000,000", 10000000.00);
test("%,3.0f", "100,000,000", 100000000.00);
+ //---------------------------------------------------------------------
+ // %f - adoption of Double.toString(double) algorithm
+ //---------------------------------------------------------------------
+ test("%.0f", "738790000000000000000", 7.3879e20);
+ test("%.0f", "100000000000000000000000", 1e23);
+ test("%.0f", "200000000000000000000000", 2e23);
+ test("%.0f", "19400994884341945000000000", 1.9400994884341945E25);
+
//---------------------------------------------------------------------
// %f - float, double, Double, BigDecimal
//---------------------------------------------------------------------
@@ -487,6 +505,16 @@ public static void test() {
tryCatch("%#3.0g", FormatFlagsConversionMismatchException.class, 1000.00);
+ //---------------------------------------------------------------------
+ // %g - adoption of Double.toString(double) algorithm
+ //---------------------------------------------------------------------
+ test("%.2g", "9.9e-324", 1e-323);
+ test("%.2g", "9.9e-323", 1e-322);
+ test("%.16g", "7.387900000000000e+20", 7.3879e20);
+ test("%.16g", "1.000000000000000e+23", 1e23);
+ test("%.17g", "2.0000000000000000e+23", 2e23);
+ test("%.17g", "1.9400994884341945e+25", 1.9400994884341945E25);
+
// double PI^300
// = 13962455701329742638131355433930076081862072808 ... e+149
diff --git a/test/jdk/java/util/Formatter/BasicDoubleObject.java b/test/jdk/java/util/Formatter/BasicDoubleObject.java
index a62a10400db9a..e499f0cdce813 100644
--- a/test/jdk/java/util/Formatter/BasicDoubleObject.java
+++ b/test/jdk/java/util/Formatter/BasicDoubleObject.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, 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
@@ -328,6 +328,16 @@ public static void test() {
test("%3.0e", "1e+07", 10000000.00);
test("%3.0e", "1e+08", 100000000.00);
+ //---------------------------------------------------------------------
+ // %e - adoption of Double.toString(double) algorithm
+ //---------------------------------------------------------------------
+ test("%.1e", "9.9e-324", 1e-323);
+ test("%.1e", "9.9e-323", 1e-322);
+ test("%.15e", "7.387900000000000e+20", 7.3879e20);
+ test("%.15e", "1.000000000000000e+23", 1e23);
+ test("%.16e", "2.0000000000000000e+23", 2e23);
+ test("%.16e", "1.9400994884341945e+25", 1.9400994884341945E25);
+
//---------------------------------------------------------------------
// %f
//
@@ -389,6 +399,14 @@ public static void test() {
test("%,3.0f", "10,000,000", 10000000.00);
test("%,3.0f", "100,000,000", 100000000.00);
+ //---------------------------------------------------------------------
+ // %f - adoption of Double.toString(double) algorithm
+ //---------------------------------------------------------------------
+ test("%.0f", "738790000000000000000", 7.3879e20);
+ test("%.0f", "100000000000000000000000", 1e23);
+ test("%.0f", "200000000000000000000000", 2e23);
+ test("%.0f", "19400994884341945000000000", 1.9400994884341945E25);
+
//---------------------------------------------------------------------
// %f - float, double, Double, BigDecimal
//---------------------------------------------------------------------
@@ -486,6 +504,16 @@ public static void test() {
tryCatch("%#3.0g", FormatFlagsConversionMismatchException.class, 1000.00);
+ //---------------------------------------------------------------------
+ // %g - adoption of Double.toString(double) algorithm
+ //---------------------------------------------------------------------
+ test("%.2g", "9.9e-324", 1e-323);
+ test("%.2g", "9.9e-323", 1e-322);
+ test("%.16g", "7.387900000000000e+20", 7.3879e20);
+ test("%.16g", "1.000000000000000e+23", 1e23);
+ test("%.17g", "2.0000000000000000e+23", 2e23);
+ test("%.17g", "1.9400994884341945e+25", 1.9400994884341945E25);
+
// double PI^300
// = 13962455701329742638131355433930076081862072808 ... e+149
diff --git a/test/jdk/java/util/Formatter/BasicFloat.java b/test/jdk/java/util/Formatter/BasicFloat.java
index ba61b3f52d04b..e490af6f6f3a8 100644
--- a/test/jdk/java/util/Formatter/BasicFloat.java
+++ b/test/jdk/java/util/Formatter/BasicFloat.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, 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
@@ -328,6 +328,16 @@ public static void test() {
test("%3.0e", "1e+07", 10000000.00);
test("%3.0e", "1e+08", 100000000.00);
+ //---------------------------------------------------------------------
+ // %e - adoption of Double.toString(double) algorithm
+ //---------------------------------------------------------------------
+ test("%.1e", "9.9e-324", 1e-323);
+ test("%.1e", "9.9e-323", 1e-322);
+ test("%.15e", "7.387900000000000e+20", 7.3879e20);
+ test("%.15e", "1.000000000000000e+23", 1e23);
+ test("%.16e", "2.0000000000000000e+23", 2e23);
+ test("%.16e", "1.9400994884341945e+25", 1.9400994884341945E25);
+
//---------------------------------------------------------------------
// %f
//
@@ -389,6 +399,14 @@ public static void test() {
test("%,3.0f", "10,000,000", 10000000.00);
test("%,3.0f", "100,000,000", 100000000.00);
+ //---------------------------------------------------------------------
+ // %f - adoption of Double.toString(double) algorithm
+ //---------------------------------------------------------------------
+ test("%.0f", "738790000000000000000", 7.3879e20);
+ test("%.0f", "100000000000000000000000", 1e23);
+ test("%.0f", "200000000000000000000000", 2e23);
+ test("%.0f", "19400994884341945000000000", 1.9400994884341945E25);
+
//---------------------------------------------------------------------
// %f - float
//---------------------------------------------------------------------
@@ -489,6 +507,16 @@ public static void test() {
tryCatch("%#3.0g", FormatFlagsConversionMismatchException.class, 1000.00);
+ //---------------------------------------------------------------------
+ // %g - adoption of Double.toString(double) algorithm
+ //---------------------------------------------------------------------
+ test("%.2g", "9.9e-324", 1e-323);
+ test("%.2g", "9.9e-323", 1e-322);
+ test("%.16g", "7.387900000000000e+20", 7.3879e20);
+ test("%.16g", "1.000000000000000e+23", 1e23);
+ test("%.17g", "2.0000000000000000e+23", 2e23);
+ test("%.17g", "1.9400994884341945e+25", 1.9400994884341945E25);
+
// double PI^300
// = 13962455701329742638131355433930076081862072808 ... e+149
diff --git a/test/jdk/java/util/Formatter/BasicFloatObject.java b/test/jdk/java/util/Formatter/BasicFloatObject.java
index 9bfe1dcc036c8..ab3de8099f0eb 100644
--- a/test/jdk/java/util/Formatter/BasicFloatObject.java
+++ b/test/jdk/java/util/Formatter/BasicFloatObject.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, 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
@@ -328,6 +328,16 @@ public static void test() {
test("%3.0e", "1e+07", 10000000.00);
test("%3.0e", "1e+08", 100000000.00);
+ //---------------------------------------------------------------------
+ // %e - adoption of Double.toString(double) algorithm
+ //---------------------------------------------------------------------
+ test("%.1e", "9.9e-324", 1e-323);
+ test("%.1e", "9.9e-323", 1e-322);
+ test("%.15e", "7.387900000000000e+20", 7.3879e20);
+ test("%.15e", "1.000000000000000e+23", 1e23);
+ test("%.16e", "2.0000000000000000e+23", 2e23);
+ test("%.16e", "1.9400994884341945e+25", 1.9400994884341945E25);
+
//---------------------------------------------------------------------
// %f
//
@@ -389,6 +399,14 @@ public static void test() {
test("%,3.0f", "10,000,000", 10000000.00);
test("%,3.0f", "100,000,000", 100000000.00);
+ //---------------------------------------------------------------------
+ // %f - adoption of Double.toString(double) algorithm
+ //---------------------------------------------------------------------
+ test("%.0f", "738790000000000000000", 7.3879e20);
+ test("%.0f", "100000000000000000000000", 1e23);
+ test("%.0f", "200000000000000000000000", 2e23);
+ test("%.0f", "19400994884341945000000000", 1.9400994884341945E25);
+
//---------------------------------------------------------------------
@@ -474,6 +492,16 @@ public static void test() {
tryCatch("%#3.0g", FormatFlagsConversionMismatchException.class, 1000.00);
+ //---------------------------------------------------------------------
+ // %g - adoption of Double.toString(double) algorithm
+ //---------------------------------------------------------------------
+ test("%.2g", "9.9e-324", 1e-323);
+ test("%.2g", "9.9e-323", 1e-322);
+ test("%.16g", "7.387900000000000e+20", 7.3879e20);
+ test("%.16g", "1.000000000000000e+23", 1e23);
+ test("%.17g", "2.0000000000000000e+23", 2e23);
+ test("%.17g", "1.9400994884341945e+25", 1.9400994884341945E25);
+
// double PI^300
// = 13962455701329742638131355433930076081862072808 ... e+149
diff --git a/test/jdk/java/util/Formatter/BasicTestLauncher.java b/test/jdk/java/util/Formatter/BasicTestLauncher.java
index f3451ab366ce2..0b37acfd944ae 100644
--- a/test/jdk/java/util/Formatter/BasicTestLauncher.java
+++ b/test/jdk/java/util/Formatter/BasicTestLauncher.java
@@ -53,7 +53,7 @@
* @bug 4906370 4962433 4973103 4989961 5005818 5031150 4970931 4989491 5002937
* 5005104 5007745 5061412 5055180 5066788 5088703 6317248 6318369 6320122
* 6344623 6369500 6534606 6282094 6286592 6476425 5063507 6469160 6476168
- * 8059175 8204229
+ * 8059175 8204229 8300869
*
* @run junit BasicTestLauncher
*/