diff --git a/src/java.base/share/classes/java/util/Formatter.java b/src/java.base/share/classes/java/util/Formatter.java index b6ca8fb3b6572..6bd93315e3232 100644 --- a/src/java.base/share/classes/java/util/Formatter.java +++ b/src/java.base/share/classes/java/util/Formatter.java @@ -61,7 +61,7 @@ import java.time.temporal.UnsupportedTemporalTypeException; import jdk.internal.math.DoubleConsts; -import jdk.internal.math.FormattedFloatingDecimal; +import jdk.internal.math.FormattedFPDecimal; import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.locale.provider.ResourceBundleBasedAdapter; @@ -1260,6 +1260,9 @@ * id="scientific">computerized scientific notation. The localization algorithm is applied. * + *

A {@code float} or {@link Float} argument is first converted to + * {@code double} or {@link Double}, without loss of precision. + * *

The formatting of the magnitude m depends upon its value. * *

If m is NaN or infinite, the literal strings "NaN" or @@ -1291,8 +1294,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 @@ -1342,6 +1345,9 @@ * format. The localization algorithm is * applied. * + *

A {@code float} or {@link Float} argument is first converted to + * {@code double} or {@link Double}, without loss of precision. + * *

The result is a string that represents the sign and magnitude * (absolute value) of the argument. The formatting of the sign is * described in the 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-1f < 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 */