diff --git a/src/java.base/share/classes/java/text/CompactNumberFormat.java b/src/java.base/share/classes/java/text/CompactNumberFormat.java index 0cb5eb88079..35464d6ec91 100644 --- a/src/java.base/share/classes/java/text/CompactNumberFormat.java +++ b/src/java.base/share/classes/java/text/CompactNumberFormat.java @@ -652,16 +652,16 @@ public final class CompactNumberFormat extends NumberFormat { double val = getNumberValue(number, divisor); if (checkIncrement(val, compactDataIndex, divisor)) { divisor = (Long) divisors.get(++compactDataIndex); - val = getNumberValue(number, divisor); } + roundedNumber = roundedNumber / divisor; + decimalFormat.setDigitList(roundedNumber, isNegative, getMaximumFractionDigits()); + val = decimalFormat.getDigitList().getDouble(); String prefix = getAffix(false, true, isNegative, compactDataIndex, val); String suffix = getAffix(false, false, isNegative, compactDataIndex, val); if (!prefix.isEmpty() || !suffix.isEmpty()) { appendPrefix(result, prefix, delegate); if (!placeHolderPatterns.get(compactDataIndex).get(val).isEmpty()) { - roundedNumber = roundedNumber / divisor; - decimalFormat.setDigitList(roundedNumber, isNegative, getMaximumFractionDigits()); decimalFormat.subformatNumber(result, delegate, isNegative, false, getMaximumIntegerDigits(), getMinimumIntegerDigits(), getMaximumFractionDigits(), getMinimumFractionDigits()); @@ -734,31 +734,28 @@ public final class CompactNumberFormat extends NumberFormat { double val = getNumberValue(number, divisor); if (checkIncrement(val, compactDataIndex, divisor)) { divisor = (Long) divisors.get(++compactDataIndex); - val = getNumberValue(number, divisor); } + var noFraction = number % divisor == 0; + if (noFraction) { + number = number / divisor; + decimalFormat.setDigitList(number, isNegative, 0); + } else { + // To avoid truncation of fractional part store + // the value in double and follow double path instead of + // long path + double dNumber = (double) number / divisor; + decimalFormat.setDigitList(dNumber, isNegative, getMaximumFractionDigits()); + } + val = decimalFormat.getDigitList().getDouble(); String prefix = getAffix(false, true, isNegative, compactDataIndex, val); String suffix = getAffix(false, false, isNegative, compactDataIndex, val); if (!prefix.isEmpty() || !suffix.isEmpty()) { appendPrefix(result, prefix, delegate); if (!placeHolderPatterns.get(compactDataIndex).get(val).isEmpty()) { - if ((number % divisor == 0)) { - number = number / divisor; - decimalFormat.setDigitList(number, isNegative, 0); - decimalFormat.subformatNumber(result, delegate, - isNegative, true, getMaximumIntegerDigits(), - getMinimumIntegerDigits(), getMaximumFractionDigits(), - getMinimumFractionDigits()); - } else { - // To avoid truncation of fractional part store - // the value in double and follow double path instead of - // long path - double dNumber = (double) number / divisor; - decimalFormat.setDigitList(dNumber, isNegative, getMaximumFractionDigits()); - decimalFormat.subformatNumber(result, delegate, - isNegative, false, getMaximumIntegerDigits(), - getMinimumIntegerDigits(), getMaximumFractionDigits(), - getMinimumFractionDigits()); - } + decimalFormat.subformatNumber(result, delegate, + isNegative, noFraction, getMaximumIntegerDigits(), + getMinimumIntegerDigits(), getMaximumFractionDigits(), + getMinimumFractionDigits()); appendSuffix(result, suffix, delegate); } } else { @@ -833,15 +830,15 @@ public final class CompactNumberFormat extends NumberFormat { double val = getNumberValue(number.doubleValue(), divisor.doubleValue()); if (checkIncrement(val, compactDataIndex, divisor.doubleValue())) { divisor = divisors.get(++compactDataIndex); - val = getNumberValue(number.doubleValue(), divisor.doubleValue()); } + number = number.divide(new BigDecimal(divisor.toString()), getRoundingMode()); + decimalFormat.setDigitList(number, isNegative, getMaximumFractionDigits()); + val = decimalFormat.getDigitList().getDouble(); String prefix = getAffix(false, true, isNegative, compactDataIndex, val); String suffix = getAffix(false, false, isNegative, compactDataIndex, val); if (!prefix.isEmpty() || !suffix.isEmpty()) { appendPrefix(result, prefix, delegate); if (!placeHolderPatterns.get(compactDataIndex).get(val).isEmpty()) { - number = number.divide(new BigDecimal(divisor.toString()), getRoundingMode()); - decimalFormat.setDigitList(number, isNegative, getMaximumFractionDigits()); decimalFormat.subformatNumber(result, delegate, isNegative, false, getMaximumIntegerDigits(), getMinimumIntegerDigits(), getMaximumFractionDigits(), getMinimumFractionDigits()); @@ -904,34 +901,30 @@ public final class CompactNumberFormat extends NumberFormat { double val = getNumberValue(number.doubleValue(), divisor.doubleValue()); if (checkIncrement(val, compactDataIndex, divisor.doubleValue())) { divisor = divisors.get(++compactDataIndex); - val = getNumberValue(number.doubleValue(), divisor.doubleValue()); } + var noFraction = number.mod(new BigInteger(divisor.toString())) + .compareTo(BigInteger.ZERO) == 0; + if (noFraction) { + number = number.divide(new BigInteger(divisor.toString())); + decimalFormat.setDigitList(number, isNegative, 0); + } else { + // To avoid truncation of fractional part store the value in + // BigDecimal and follow BigDecimal path instead of + // BigInteger path + BigDecimal nDecimal = new BigDecimal(number) + .divide(new BigDecimal(divisor.toString()), getRoundingMode()); + decimalFormat.setDigitList(nDecimal, isNegative, getMaximumFractionDigits()); + } + val = decimalFormat.getDigitList().getDouble(); String prefix = getAffix(false, true, isNegative, compactDataIndex, val); String suffix = getAffix(false, false, isNegative, compactDataIndex, val); if (!prefix.isEmpty() || !suffix.isEmpty()) { appendPrefix(result, prefix, delegate); if (!placeHolderPatterns.get(compactDataIndex).get(val).isEmpty()) { - if (number.mod(new BigInteger(divisor.toString())) - .compareTo(BigInteger.ZERO) == 0) { - number = number.divide(new BigInteger(divisor.toString())); - - decimalFormat.setDigitList(number, isNegative, 0); - decimalFormat.subformatNumber(result, delegate, - isNegative, true, getMaximumIntegerDigits(), - getMinimumIntegerDigits(), getMaximumFractionDigits(), - getMinimumFractionDigits()); - } else { - // To avoid truncation of fractional part store the value in - // BigDecimal and follow BigDecimal path instead of - // BigInteger path - BigDecimal nDecimal = new BigDecimal(number) - .divide(new BigDecimal(divisor.toString()), getRoundingMode()); - decimalFormat.setDigitList(nDecimal, isNegative, getMaximumFractionDigits()); - decimalFormat.subformatNumber(result, delegate, - isNegative, false, getMaximumIntegerDigits(), - getMinimumIntegerDigits(), getMaximumFractionDigits(), - getMinimumFractionDigits()); - } + decimalFormat.subformatNumber(result, delegate, + isNegative, noFraction, getMaximumIntegerDigits(), + getMinimumIntegerDigits(), getMaximumFractionDigits(), + getMinimumFractionDigits()); appendSuffix(result, suffix, delegate); } } else { diff --git a/src/java.base/share/classes/java/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java index c04abbd042f..b23c5f360bf 100644 --- a/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/src/java.base/share/classes/java/text/DecimalFormat.java @@ -1799,6 +1799,14 @@ public class DecimalFormat extends NumberFormat { } } + /** + * {@return the {@code DigitList} used by this {@code DecimalFormat} instance} + * Declared as package-private, intended for {@code CompactNumberFormat}. + */ + DigitList getDigitList() { + return digitList; + } + // ======== End fast-path formatting logic for double ========================= /** diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java b/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java index 40da19adfe7..16de2247779 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java @@ -22,7 +22,7 @@ */ /* * @test - * @bug 8177552 8217721 8222756 8295372 8306116 8319990 + * @bug 8177552 8217721 8222756 8295372 8306116 8319990 8338690 * @summary Checks the functioning of compact number format * @modules jdk.localedata * @run testng/othervm TestCompactNumber @@ -60,6 +60,9 @@ public class TestCompactNumber { private static final NumberFormat FORMAT_IT_SHORT = NumberFormat .getCompactNumberInstance(Locale.ITALIAN, NumberFormat.Style.SHORT); + private static final NumberFormat FORMAT_IT_LONG = NumberFormat + .getCompactNumberInstance(Locale.ITALIAN, NumberFormat.Style.LONG); + private static final NumberFormat FORMAT_CA_LONG = NumberFormat .getCompactNumberInstance(Locale.of("ca"), NumberFormat.Style.LONG); @@ -89,6 +92,13 @@ public class TestCompactNumber { .getCompactNumberInstance(Locale.ITALIAN, NumberFormat.Style.LONG); private static final NumberFormat FORMAT_PT_LONG_FD4 = NumberFormat .getCompactNumberInstance(Locale.of("pt"), NumberFormat.Style.LONG); + + private static final NumberFormat FORMAT_PL_LONG = NumberFormat + .getCompactNumberInstance(Locale.of("pl"), NumberFormat.Style.LONG); + + private static final NumberFormat FORMAT_FR_LONG = NumberFormat + .getCompactNumberInstance(Locale.FRENCH, NumberFormat.Style.LONG); + static { FORMAT_ES_LONG_FD1.setMaximumFractionDigits(1); FORMAT_DE_LONG_FD2.setMaximumFractionDigits(2); @@ -359,6 +369,12 @@ public class TestCompactNumber { {FORMAT_DE_LONG_FD2, 1_234_500, "1,23 Millionen"}, {FORMAT_IT_LONG_FD3, 1_234_500, "1,234 milioni"}, {FORMAT_PT_LONG_FD4, 1_234_500, "1,2345 milh\u00f5es"}, + + // 8338690 + {FORMAT_PL_LONG, 5_000, "5 tysi\u0119cy"}, + {FORMAT_PL_LONG, 4_949, "5 tysi\u0119cy"}, + {FORMAT_FR_LONG, 1_949, "2 mille"}, + {FORMAT_IT_LONG, 1_949, "2 mila"}, }; } @@ -466,6 +482,10 @@ public class TestCompactNumber { {FORMAT_DE_LONG_FD2, "1,23 Millionen", 1_230_000L, Long.class}, {FORMAT_IT_LONG_FD3, "1,234 milioni", 1_234_000L, Long.class}, {FORMAT_PT_LONG_FD4, "1,2345 milh\u00f5es", 1_234_500L, Long.class}, + // 8338690 + {FORMAT_PL_LONG, "5 tysi\u0119cy", 5_000L, Long.class}, + {FORMAT_FR_LONG, "2 mille", 2_000L, Long.class}, + {FORMAT_IT_LONG, "2 mila", 2_000L, Long.class}, }; } @@ -514,6 +534,10 @@ public class TestCompactNumber { {FORMAT_SL_LONG, "5 milijon", 5L}, {FORMAT_SL_LONG, "5 milijona", 5L}, {FORMAT_SL_LONG, "5 milijone", 5L}, + // 8338690 + {FORMAT_PL_LONG, "5 tysiÄ…ce", 5L}, + {FORMAT_FR_LONG, "2 millier", 2L}, + {FORMAT_IT_LONG, "2 mille", 2L}, }; }