diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/TDecimalFormat.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/TDecimalFormat.java index ed43dc983..5db006aac 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/TDecimalFormat.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/TDecimalFormat.java @@ -15,6 +15,8 @@ */ package org.teavm.classlib.java.text; +import java.math.BigDecimal; +import java.math.BigInteger; import java.text.DecimalFormatSymbols; import org.teavm.classlib.impl.unicode.CLDRHelper; import org.teavm.classlib.java.lang.TArithmeticException; @@ -36,11 +38,11 @@ public class TDecimalFormat extends TNumberFormat { private static final double[] POWM10_FRAC_ARRAY = { 1E-1, 1E-2, 1E-4, 1E-8, 1E-16, 1E-32, 1E-64, 1E-128, 1E-256 }; private static final int DOUBLE_MAX_EXPONENT = 308; TDecimalFormatSymbols symbols; - private String positivePrefix; - private String negativePrefix; - private String positiveSuffix; - private String negativeSuffix; - private int multiplier; + private String positivePrefix = ""; + private String negativePrefix = "-"; + private String positiveSuffix = ""; + private String negativeSuffix = ""; + private int multiplier = 1; private int groupingSize; private boolean decimalSeparatorAlwaysShown; private boolean parseBigDecimal; @@ -181,6 +183,31 @@ public class TDecimalFormat extends TNumberFormat { return null; } + @Override + public StringBuffer format(Object object, StringBuffer buffer, TFieldPosition field) { + if (object instanceof BigDecimal) { + return format((BigDecimal)object, buffer, field); + } else if (object instanceof BigInteger) { + return format((BigInteger)object, buffer, field); + } else { + return super.format(object, buffer, field); + } + } + + private StringBuffer format(BigInteger value, StringBuffer buffer, TFieldPosition field) { + return format(new BigDecimal(value), buffer, field); + } + + private StringBuffer format(BigDecimal value, StringBuffer buffer, + @SuppressWarnings("unused") TFieldPosition field) { + if (exponentDigits > 0) { + formatExponent(value, buffer); + } else { + formatRegular(value, buffer); + } + return buffer; + } + @Override public StringBuffer format(long value, StringBuffer buffer, TFieldPosition field) { if (exponentDigits > 0) { @@ -193,11 +220,18 @@ public class TDecimalFormat extends TNumberFormat { @Override public StringBuffer format(double value, StringBuffer buffer, TFieldPosition field) { - MantissaAndExponent me = getMantissaAndExponent(value); - if (exponentDigits > 0) { - formatExponent(me.mantissa, me.exponent, buffer); + if (Double.isNaN(value)) { + buffer.append(positivePrefix).append(symbols.getNaN()).append(positiveSuffix); + } else if (Double.isInfinite(value)) { + buffer.append(value > 0 ? positivePrefix : negativePrefix).append(symbols.getInfinity()) + .append(value > 0 ? positiveSuffix : negativeSuffix); } else { - formatRegular(me.mantissa, me.exponent, buffer); + MantissaAndExponent me = getMantissaAndExponent(value); + if (exponentDigits > 0) { + formatExponent(me.mantissa, me.exponent, buffer); + } else { + formatRegular(me.mantissa, me.exponent, buffer); + } } return buffer; } @@ -217,6 +251,22 @@ public class TDecimalFormat extends TNumberFormat { int visibleExponent = fastLn10(mantissa); int mantissaLength = visibleExponent + 1; + if (multiplier != 1) { + int multiplierDigits = fastLn10(multiplier); + int tenMultiplier = POW10_INT_ARRAY[multiplierDigits]; + if (tenMultiplier == multiplier) { + exponent += multiplierDigits; + } else if (mantissa >= Long.MAX_VALUE / multiplier || mantissa <= Long.MIN_VALUE / multiplier) { + formatExponent(new BigDecimal(BigInteger.valueOf(mantissa), mantissaLength - exponent), buffer); + return; + } else { + mantissa *= multiplier; + positive = mantissa >= 0; + visibleExponent = fastLn10(mantissa); + mantissaLength = visibleExponent + 1; + } + } + int significantSize = getMinimumIntegerDigits() + getMaximumFractionDigits(); int exponentMultiplier = getMaximumIntegerDigits() - getMinimumIntegerDigits() + 1; if (exponentMultiplier > 1) { @@ -240,7 +290,7 @@ public class TDecimalFormat extends TNumberFormat { int exponentPos = Math.max(visibleExponent, 0); for (int i = mantissaLength - 1; i >= exponentPos; --i) { long mantissaDigitMask = POW10_ARRAY[i]; - buffer.append(Character.forDigit(Math.abs((int)(mantissa / mantissaDigitMask)), 10)); + buffer.append(forDigit(Math.abs((int)(mantissa / mantissaDigitMask)))); mantissa %= mantissaDigitMask; } for (int i = exponentPos - 1; i >= visibleExponent; --i) { @@ -256,7 +306,7 @@ public class TDecimalFormat extends TNumberFormat { int count = 0; for (int i = visibleExponent - 1; i >= limit; --i) { long mantissaDigitMask = POW10_ARRAY[i]; - buffer.append(Character.forDigit(Math.abs((int)(mantissa / mantissaDigitMask)), 10)); + buffer.append(forDigit(Math.abs((int)(mantissa / mantissaDigitMask)))); mantissa %= mantissaDigitMask; ++count; if (mantissa == 0) { @@ -276,7 +326,7 @@ public class TDecimalFormat extends TNumberFormat { int exponentLength = Math.max(exponentDigits, fastLn10(exponent) + 1); for (int i = exponentLength - 1; i >= 0; --i) { int exponentDigit = POW10_INT_ARRAY[i]; - buffer.append(Character.forDigit(exponent / exponentDigit, 10)); + buffer.append(forDigit(exponent / exponentDigit)); exponent %= exponentDigit; } @@ -293,6 +343,18 @@ public class TDecimalFormat extends TNumberFormat { int mantissaLength = fastLn10(mantissa) + 1; ++exponent; + int multiplierDigits = fastLn10(multiplier); + int tenMultiplier = POW10_INT_ARRAY[multiplierDigits]; + if (tenMultiplier == multiplier) { + exponent += multiplierDigits; + } else if (mantissa >= Long.MAX_VALUE / multiplier || mantissa <= Long.MIN_VALUE / multiplier) { + formatRegular(new BigDecimal(BigInteger.valueOf(mantissa), mantissaLength - exponent), buffer); + return; + } else { + mantissa *= multiplier; + mantissaLength = fastLn10(mantissa) + 1; + } + // Apply rounding if necessary int roundingPos = exponent + getMaximumFractionDigits(); if (roundingPos < 0) { @@ -320,7 +382,7 @@ public class TDecimalFormat extends TNumberFormat { int mantissaDigit = mantissaLength - 1; for (int i = 0; i < significantIntDigits; ++i) { long mantissaDigitMask = POW10_ARRAY[mantissaDigit--]; - buffer.append(Character.forDigit(Math.abs((int)(mantissa / mantissaDigitMask)), 10)); + buffer.append(forDigit(Math.abs((int)(mantissa / mantissaDigitMask)))); mantissa %= mantissaDigitMask; if (groupingSize > 0 && digitPos % groupingSize == 0 && digitPos > 0) { buffer.append(symbols.getGroupingSeparator()); @@ -368,7 +430,7 @@ public class TDecimalFormat extends TNumberFormat { } ++digitPos; long mantissaDigitMask = POW10_ARRAY[mantissaDigit]; - buffer.append(Character.forDigit(Math.abs((int)(mantissa / mantissaDigitMask)), 10)); + buffer.append(forDigit(Math.abs((int)(mantissa / mantissaDigitMask)))); mantissa %= mantissaDigitMask; mantissaDigit--; } @@ -388,6 +450,197 @@ public class TDecimalFormat extends TNumberFormat { } } + private void formatExponent(BigDecimal value, StringBuffer buffer) { + if (multiplier != 1) { + value = value.multiply(BigDecimal.valueOf(multiplier)); + } + boolean positive = value.compareTo(BigDecimal.ZERO) >= 0; + int mantissaLength = value.precision(); + int visibleExponent = mantissaLength - 1; + int exponent = visibleExponent - value.scale(); + BigInteger mantissa = value.unscaledValue(); + + int significantSize = getMinimumIntegerDigits() + getMaximumFractionDigits(); + int exponentMultiplier = getMaximumIntegerDigits() - getMinimumIntegerDigits() + 1; + if (exponentMultiplier > 1) { + int delta = exponent - (exponent / exponentMultiplier) * exponentMultiplier; + exponent -= delta; + visibleExponent -= delta; + } else { + exponent -= getMinimumIntegerDigits() - 1; + visibleExponent -= getMinimumIntegerDigits() - 1; + } + + if (significantSize < 0) { + mantissa = BigInteger.ZERO; + } else if (significantSize < mantissaLength) { + mantissa = applyRounding(mantissa, mantissaLength, significantSize); + } + + // Append pattern prefix + buffer.append(positive ? positivePrefix : negativePrefix); + + int exponentPos = Math.max(visibleExponent, 0); + BigInteger mantissaDigitMask = pow10(BigInteger.ONE, mantissaLength - 1); + for (int i = mantissaLength - 1; i >= exponentPos; --i) { + BigInteger[] parts = mantissa.divideAndRemainder(mantissaDigitMask); + buffer.append(forDigit(Math.abs(parts[0].intValue()))); + mantissa = parts[1]; + mantissaDigitMask = mantissaDigitMask.divide(BigInteger.TEN); + } + for (int i = exponentPos - 1; i >= visibleExponent; --i) { + buffer.append('0'); + } + + significantSize -= mantissaLength - visibleExponent; + int requiredSize = significantSize - (getMaximumFractionDigits() - getMinimumFractionDigits()); + if (requiredSize > 0 || (!mantissa.equals(BigInteger.ZERO) && significantSize > 0)) { + buffer.append(symbols.getDecimalSeparator()); + + int limit = Math.max(0, visibleExponent - significantSize); + int count = 0; + for (int i = visibleExponent - 1; i >= limit; --i) { + BigInteger[] parts = mantissa.divideAndRemainder(mantissaDigitMask); + buffer.append(forDigit(Math.abs(parts[0].intValue()))); + mantissa = parts[1]; + ++count; + if (mantissa.equals(BigInteger.ZERO)) { + break; + } + mantissaDigitMask = mantissaDigitMask.divide(BigInteger.TEN); + } + while (count++ < requiredSize) { + buffer.append('0'); + } + } + + buffer.append(symbols.getExponentSeparator()); + if (exponent < 0) { + exponent = -exponent; + buffer.append(symbols.getMinusSign()); + } + int exponentLength = Math.max(exponentDigits, fastLn10(exponent) + 1); + for (int i = exponentLength - 1; i >= 0; --i) { + int exponentDigit = POW10_INT_ARRAY[i]; + buffer.append(forDigit(exponent / exponentDigit)); + exponent %= exponentDigit; + } + + // Add suffix + if (positive) { + buffer.append(positiveSuffix != null ? positiveSuffix : ""); + } else { + buffer.append(negativeSuffix != null ? negativeSuffix : positiveSuffix != null ? positiveSuffix : ""); + } + } + + private void formatRegular(BigDecimal value, StringBuffer buffer) { + if (multiplier != 1) { + value = value.multiply(BigDecimal.valueOf(multiplier)); + } + BigInteger mantissa = value.unscaledValue(); + boolean positive = mantissa.compareTo(BigInteger.ZERO) >= 0; + int mantissaLength = value.precision(); + int exponent = value.precision() - value.scale(); + + // Apply rounding if necessary + int roundingPos = exponent + getMaximumFractionDigits(); + if (roundingPos < 0) { + mantissa = BigInteger.ZERO; + } else if (roundingPos < mantissaLength) { + mantissa = applyRounding(mantissa, mantissaLength, roundingPos); + } + + // Append pattern prefix + buffer.append(positive ? positivePrefix : negativePrefix); + + // Add insignificant integer zeros + int intLength = Math.max(0, exponent); + int digitPos = Math.max(intLength, getMinimumIntegerDigits()) - 1; + for (int i = getMinimumIntegerDigits() - 1; i >= intLength; --i) { + buffer.append('0'); + if (groupingSize > 0 && digitPos % groupingSize == 0 && digitPos > 0) { + buffer.append(symbols.getGroupingSeparator()); + } + --digitPos; + } + + // Add significant integer digits + int significantIntDigits = Math.min(mantissaLength, intLength); + BigInteger mantissaDigitMask = pow10(BigInteger.ONE, mantissaLength - 1); + for (int i = 0; i < significantIntDigits; ++i) { + BigInteger[] parts = mantissa.divideAndRemainder(mantissaDigitMask); + buffer.append(forDigit(Math.abs(parts[0].intValue()))); + mantissa = parts[1]; + if (groupingSize > 0 && digitPos % groupingSize == 0 && digitPos > 0) { + buffer.append(symbols.getGroupingSeparator()); + } + --digitPos; + --mantissaLength; + mantissaDigitMask = mantissaDigitMask.divide(BigInteger.TEN); + } + + // Add significant integer zeros + intLength -= significantIntDigits; + for (int i = 0; i < intLength; ++i) { + buffer.append('0'); + if (groupingSize > 0 && digitPos % groupingSize == 0 && digitPos > 0) { + buffer.append(symbols.getGroupingSeparator()); + } + --digitPos; + } + + if (mantissa.equals(BigInteger.ZERO)) { + if (getMinimumFractionDigits() == 0) { + if (isDecimalSeparatorAlwaysShown()) { + buffer.append(symbols.getDecimalSeparator()); + } + } else { + buffer.append(symbols.getDecimalSeparator()); + for (int i = 0; i < getMinimumFractionDigits(); ++i) { + buffer.append('0'); + } + } + } else { + buffer.append(symbols.getDecimalSeparator()); + + // Add significant fractional zeros + int fracZeros = Math.min(getMaximumFractionDigits(), Math.max(0, -exponent)); + digitPos = 0; + for (int i = 0; i < fracZeros; ++i) { + ++digitPos; + buffer.append('0'); + } + + // Add significant fractional digits + int significantFracDigits = Math.min(getMaximumFractionDigits() - digitPos, mantissaLength); + for (int i = 0; i < significantFracDigits; ++i) { + if (mantissa.equals(BigInteger.ZERO)) { + break; + } + ++digitPos; + BigInteger[] parts = mantissa.divideAndRemainder(mantissaDigitMask); + buffer.append(forDigit(Math.abs(parts[0].intValue()))); + mantissa = parts[1]; + --mantissaLength; + mantissaDigitMask = mantissaDigitMask.divide(BigInteger.TEN); + } + + // Add insignificant fractional zeros + for (int i = digitPos; i < getMinimumFractionDigits(); ++i) { + ++digitPos; + buffer.append('0'); + } + } + + // Add suffix + if (positive) { + buffer.append(positiveSuffix != null ? positiveSuffix : ""); + } else { + buffer.append(negativeSuffix != null ? negativeSuffix : positiveSuffix != null ? positiveSuffix : ""); + } + } + private long applyRounding(long mantissa, int mantissaLength, int exponent) { long rounding = POW10_ARRAY[mantissaLength - exponent]; long signedRounding = mantissa > 0 ? rounding : -rounding; @@ -444,6 +697,65 @@ public class TDecimalFormat extends TNumberFormat { return mantissa; } + private BigInteger applyRounding(BigInteger mantissa, int mantissaLength, int exponent) { + BigInteger rounding = pow10(BigInteger.ONE, mantissaLength - exponent); + BigInteger signedRounding = mantissa.compareTo(BigInteger.ZERO) >= 0 ? rounding : rounding.negate(); + switch (getRoundingMode()) { + case CEILING: + mantissa = mantissa.divide(rounding).multiply(rounding); + if (mantissa.compareTo(BigInteger.ZERO) >= 0) { + mantissa = mantissa.add(rounding); + } + break; + case FLOOR: + mantissa = mantissa.divide(rounding).multiply(rounding); + if (mantissa.compareTo(BigInteger.ZERO) <= 0) { + mantissa = mantissa.subtract(rounding); + } + break; + case UP: + mantissa = mantissa.divide(rounding).multiply(rounding).add(signedRounding); + break; + case DOWN: + mantissa = mantissa.divide(rounding).multiply(rounding); + break; + case UNNECESSARY: + if (mantissa.remainder(rounding).equals(BigInteger.ZERO)) { + throw new TArithmeticException(TString.wrap("Can't avoid rounding")); + } + break; + case HALF_DOWN: + if (mantissa.remainder(rounding).equals(signedRounding.divide(BigInteger.valueOf(2)))) { + mantissa = mantissa.divide(rounding).multiply(rounding); + } else { + mantissa = mantissa.add(signedRounding.divide(BigInteger.valueOf(2))) + .divide(rounding).multiply(rounding); + } + break; + case HALF_UP: + if (mantissa.remainder(rounding).equals(signedRounding.divide(BigInteger.valueOf(2)))) { + mantissa = mantissa.divide(rounding).multiply(rounding).add(signedRounding); + } else { + mantissa = mantissa.add(signedRounding.divide(BigInteger.valueOf(2))) + .divide(rounding).multiply(rounding); + } + break; + case HALF_EVEN: { + if (mantissa.remainder(rounding).equals(signedRounding.divide(BigInteger.valueOf(2)))) { + mantissa = mantissa.divide(rounding).multiply(rounding); + if (!mantissa.divide(rounding).remainder(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) { + mantissa = mantissa.add(signedRounding); + } + } else { + mantissa = mantissa.add(signedRounding.divide(BigInteger.valueOf(2))) + .divide(rounding).multiply(rounding); + } + break; + } + } + return mantissa; + } + private int fastLn10(long value) { int result = 0; if (value >= 0) { @@ -513,6 +825,18 @@ public class TDecimalFormat extends TNumberFormat { return result; } + private BigInteger pow10(BigInteger value, int power) { + BigInteger digit = BigInteger.TEN; + while (power != 0) { + if ((power & 1) != 0) { + value = value.multiply(digit); + } + digit = digit.multiply(digit); + power >>>= 1; + } + return value; + } + private MantissaAndExponent getMantissaAndExponent(double value) { long mantissaPattern = POW10_ARRAY[17]; int exp = 0; @@ -554,6 +878,10 @@ public class TDecimalFormat extends TNumberFormat { return new MantissaAndExponent(positive ? mantissa : -mantissa, exp); } + private char forDigit(int n) { + return (char)(symbols.getZeroDigit() + n); + } + static class MantissaAndExponent { long mantissa; int exponent; diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/TDecimalFormatParser.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/TDecimalFormatParser.java index 1c4c8e1a1..d666b2e4c 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/TDecimalFormatParser.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/TDecimalFormatParser.java @@ -20,8 +20,8 @@ package org.teavm.classlib.java.text; * @author Alexey Andreev */ class TDecimalFormatParser { - private String positivePrefix; - private String positiveSuffix; + private String positivePrefix = ""; + private String positiveSuffix = ""; private String negativePrefix; private String negativeSuffix; private int groupSize; diff --git a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js index 6d8e90300..b4e1b0d5e 100644 --- a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js +++ b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js @@ -744,6 +744,9 @@ function Long_rem(a, b) { return Long_divRem(a, b)[1]; } function Long_divRem(a, b) { + if (b.lo == 0 && b.hi == 0) { + throw new Error("Division by zero"); + } var positive = Long_isNegative(a) === Long_isNegative(b); if (Long_isNegative(a)) { a = Long_neg(a); diff --git a/teavm-tests/src/test/java/org/teavm/classlib/java/text/DecimalFormatTest.java b/teavm-tests/src/test/java/org/teavm/classlib/java/text/DecimalFormatTest.java index e0632782c..a44e7b2cc 100644 --- a/teavm-tests/src/test/java/org/teavm/classlib/java/text/DecimalFormatTest.java +++ b/teavm-tests/src/test/java/org/teavm/classlib/java/text/DecimalFormatTest.java @@ -1,6 +1,8 @@ package org.teavm.classlib.java.text; import static org.junit.Assert.*; +import java.math.BigDecimal; +import java.math.BigInteger; import java.math.RoundingMode; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; @@ -122,6 +124,15 @@ public class DecimalFormatTest { assertEquals("24", format.format(23.7)); } + @Test + public void formatsBigIntegerPart() { + DecimalFormat format = createFormat("00"); + assertEquals("02", format.format(new BigInteger("2"))); + assertEquals("23", format.format(new BigInteger("23"))); + assertEquals("23", format.format(new BigDecimal("23.2"))); + assertEquals("24", format.format(new BigDecimal("23.7"))); + } + @Test public void formatsNumber() { DecimalFormat format = createFormat("0.0"); @@ -144,6 +155,28 @@ public class DecimalFormatTest { assertEquals("0.00000000000000000000000023", format.format(23E-26)); } + @Test + public void formatsBigNumber() { + DecimalFormat format = createFormat("0.0"); + assertEquals("23.0", format.format(BigInteger.valueOf(23))); + assertEquals("23.2", format.format(new BigDecimal("23.2"))); + assertEquals("23.2", format.format(new BigDecimal("23.23"))); + assertEquals("23.3", format.format(new BigDecimal("23.27"))); + assertEquals("0.0", format.format(new BigDecimal("0.0001"))); + + format = createFormat("00000000000000000000000000.0"); + assertEquals("00000000000000000000000023.0", format.format(new BigInteger("23"))); + assertEquals("00002300000000000000000000.0", format.format(new BigInteger("2300000000000000000000"))); + assertEquals("23000000000000000000000000.0", format.format(new BigInteger("23000000000000000000000000"))); + + format = createFormat("0.00000000000000000000000000"); + assertEquals("23.00000000000000000000000000", format.format(new BigInteger("23"))); + assertEquals("0.23000000000000000000000000", format.format(new BigDecimal("0.23"))); + assertEquals("0.00230000000000000000000000", format.format(new BigDecimal("0.0023"))); + assertEquals("0.00000000000000000000230000", format.format(new BigDecimal("0.0000000000000000000023"))); + assertEquals("0.00000000000000000000000023", format.format(new BigDecimal("0.00000000000000000000000023"))); + } + @Test public void formatsFractionalPart() { DecimalFormat format = createFormat("0.0000####"); @@ -216,6 +249,59 @@ public class DecimalFormatTest { assertEquals("-4", format.format(-3.5)); } + @Test + public void bigRoundingWorks() { + DecimalFormat format = createFormat("0"); + + format.setRoundingMode(RoundingMode.UP); + assertEquals("3", format.format(new BigDecimal("2.3"))); + assertEquals("3", format.format(new BigDecimal("2.7"))); + assertEquals("-3", format.format(new BigDecimal("-2.3"))); + assertEquals("-3", format.format(new BigDecimal("-2.7"))); + + format.setRoundingMode(RoundingMode.DOWN); + assertEquals("2", format.format(new BigDecimal("2.3"))); + assertEquals("2", format.format(new BigDecimal("2.7"))); + assertEquals("-2", format.format(new BigDecimal("-2.3"))); + assertEquals("-2", format.format(new BigDecimal("-2.7"))); + + format.setRoundingMode(RoundingMode.FLOOR); + assertEquals("2", format.format(new BigDecimal("2.3"))); + assertEquals("2", format.format(new BigDecimal("2.7"))); + assertEquals("-3", format.format(new BigDecimal("-2.3"))); + assertEquals("-3", format.format(new BigDecimal("-2.7"))); + + format.setRoundingMode(RoundingMode.CEILING); + assertEquals("3", format.format(new BigDecimal("2.3"))); + assertEquals("3", format.format(new BigDecimal("2.7"))); + assertEquals("-2", format.format(new BigDecimal("-2.3"))); + assertEquals("-2", format.format(new BigDecimal("-2.7"))); + + format.setRoundingMode(RoundingMode.HALF_DOWN); + assertEquals("2", format.format(new BigDecimal("2.3"))); + assertEquals("3", format.format(new BigDecimal("2.7"))); + assertEquals("2", format.format(new BigDecimal("2.5"))); + assertEquals("3", format.format(new BigDecimal("3.5"))); + assertEquals("-2", format.format(new BigDecimal("-2.5"))); + assertEquals("-3", format.format(new BigDecimal("-3.5"))); + + format.setRoundingMode(RoundingMode.HALF_UP); + assertEquals("2", format.format(new BigDecimal("2.3"))); + assertEquals("3", format.format(new BigDecimal("2.7"))); + assertEquals("3", format.format(new BigDecimal("2.5"))); + assertEquals("4", format.format(new BigDecimal("3.5"))); + assertEquals("-3", format.format(new BigDecimal("-2.5"))); + assertEquals("-4", format.format(new BigDecimal("-3.5"))); + + format.setRoundingMode(RoundingMode.HALF_EVEN); + assertEquals("2", format.format(new BigDecimal("2.3"))); + assertEquals("3", format.format(new BigDecimal("2.7"))); + assertEquals("2", format.format(new BigDecimal("2.5"))); + assertEquals("4", format.format(new BigDecimal("3.5"))); + assertEquals("-2", format.format(new BigDecimal("-2.5"))); + assertEquals("-4", format.format(new BigDecimal("-3.5"))); + } + @Test public void formatsWithGroups() { DecimalFormat format = createFormat("#,###.0"); @@ -228,6 +314,19 @@ public class DecimalFormatTest { assertEquals("000,000,000,000,000,000,023", format.format(23)); } + @Test + public void formatsBigWithGroups() { + DecimalFormat format = createFormat("#,###.0"); + assertEquals("23.0", format.format(BigInteger.valueOf(23))); + assertEquals("2,300.0", format.format(BigInteger.valueOf(2300))); + assertEquals("2,300,000,000,000,000,000,000.0", format.format(new BigInteger("2300000000000000000000"))); + assertEquals("23,000,000,000,000,000,000,000,000.0", format.format( + new BigInteger("23000000000000000000000000"))); + + format = createFormat("000,000,000,000,000,000,000"); + assertEquals("000,000,000,000,000,000,023", format.format(BigInteger.valueOf(23))); + } + @Test public void formatsLargeValues() { DecimalFormat format = createFormat("0"); @@ -264,6 +363,35 @@ public class DecimalFormatTest { assertEquals("1.234E4", format.format(12345)); } + @Test + public void formatsBigExponent() { + DecimalFormat format = createFormat("000E0"); + assertEquals("230E-1", format.format(BigInteger.valueOf(23))); + assertEquals("230E0", format.format(BigInteger.valueOf(230))); + assertEquals("230E1", format.format(BigInteger.valueOf(2300))); + assertEquals("123E1", format.format(BigInteger.valueOf(1234))); + assertEquals("-123E1", format.format(BigInteger.valueOf(-1234))); + + format = createFormat("0.00E0"); + assertEquals("2.00E1", format.format(BigInteger.valueOf(20))); + assertEquals("2.30E1", format.format(BigInteger.valueOf(23))); + assertEquals("2.30E2", format.format(BigInteger.valueOf(230))); + assertEquals("1.23E3", format.format(BigInteger.valueOf(1234))); + + format = createFormat("000000000000000000000.00E0"); + assertEquals("230000000000000000000.00E-19", format.format(BigInteger.valueOf(23))); + + format = createFormat("0.0000000000000000000000E0"); + assertEquals("2.3000000000000000000000E1", format.format(BigInteger.valueOf(23))); + + format = createFormat("0.0##E0"); + assertEquals("1.0E0", format.format(BigInteger.valueOf(1))); + assertEquals("1.2E1", format.format(BigInteger.valueOf(12))); + assertEquals("1.23E2", format.format(BigInteger.valueOf(123))); + assertEquals("1.234E3", format.format(BigInteger.valueOf(1234))); + assertEquals("1.234E4", format.format(BigInteger.valueOf(12345))); + } + @Test public void formatsExponentWithMultiplier() { DecimalFormat format = createFormat("##0.00E0"); @@ -274,6 +402,44 @@ public class DecimalFormatTest { assertEquals("23.0E3", format.format(23000)); } + @Test + public void formatsBigExponentWithMultiplier() { + DecimalFormat format = createFormat("##0.00E0"); + assertEquals("2.30E0", format.format(new BigDecimal("2.3"))); + assertEquals("23.0E0", format.format(new BigDecimal("23"))); + assertEquals("230E0", format.format(new BigDecimal("230"))); + assertEquals("2.30E3", format.format(new BigDecimal("2300"))); + assertEquals("23.0E3", format.format(new BigDecimal("23000"))); + } + + @Test + public void formatsSpecialValues() { + DecimalFormat format = createFormat("0"); + assertEquals("∞", format.format(Double.POSITIVE_INFINITY)); + assertEquals("-∞", format.format(Double.NEGATIVE_INFINITY)); + } + + @Test + public void formatsWithMultiplier() { + DecimalFormat format = createFormat("0"); + format.setMultiplier(2); + assertEquals("18446744073709551614", format.format(9223372036854775807L)); + assertEquals("46", format.format(BigInteger.valueOf(23))); + + format.setMultiplier(100); + assertEquals("2300", format.format(23)); + assertEquals("2300", format.format(BigInteger.valueOf(23))); + + format = createFormat("00E0"); + format.setMultiplier(2); + assertEquals("18E18", format.format(9223372036854775807L)); + assertEquals("46E0", format.format(BigInteger.valueOf(23))); + + format.setMultiplier(100); + assertEquals("23E2", format.format(23)); + assertEquals("23E2", format.format(BigInteger.valueOf(23))); + } + private DecimalFormat createFormat(String format) { return new DecimalFormat(format, symbols); }