summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Fuller <nfuller@google.com>2014-09-26 19:48:53 +0000
committerAndroid Git Automerger <android-git-automerger@android.com>2014-09-26 19:48:53 +0000
commitb1acb15cf862c5174971b3d3654f245ec156d4d7 (patch)
treec25dfc9764c1649ada298cb801f42b2a628ade3d
parent8e642b15e05ea8492d08b725169bd55ab009d46f (diff)
parent972b728220e3d85eb549aa3451e872f5a06e25c1 (diff)
downloadlibcore-b1acb15cf862c5174971b3d3654f245ec156d4d7.zip
libcore-b1acb15cf862c5174971b3d3654f245ec156d4d7.tar.gz
libcore-b1acb15cf862c5174971b3d3654f245ec156d4d7.tar.bz2
am 972b7282: Merge "Rewrite tests and add tests that demonstrate a bug"
* commit '972b728220e3d85eb549aa3451e872f5a06e25c1': Rewrite tests and add tests that demonstrate a bug
-rw-r--r--expectations/knownfailures.txt8
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java279
2 files changed, 229 insertions, 58 deletions
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt
index f0c1056..c8a1b35 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -1436,6 +1436,14 @@
]
},
{
+ description: "Known precision issue in DecimalFormat",
+ bug: 17656132,
+ names: [
+ "org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatDouble_bug17656132",
+ "org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatDouble_roundingProblemCases"
+ ]
+},
+{
description: "Known failure in GregorianCalendarTest",
bug: 12778197,
name: "org.apache.harmony.tests.java.util.GregorianCalendarTest#test_computeTime"
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java
index ad96256..e0e04e8 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java
@@ -1465,78 +1465,241 @@ public class DecimalFormatTest extends TestCase {
formatTester.throwFailures();
}
- public void test_formatDouble_wideRange() {
+ // Demonstrates that fraction digit rounding occurs as expected with 1, 10 and 14 fraction
+ // digits, using numbers that are well within the precision of IEEE 754.
+ public void test_formatDouble_maxFractionDigits() {
final DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US);
DecimalFormat format = new DecimalFormat("#0.#", dfs);
+ format.setGroupingUsed(false);
format.setMaximumIntegerDigits(400);
- format.setMaximumFractionDigits(400);
-
- for (int i = 0; i < 309; i++) {
- String tval = "1";
- for (int j = 0; j < i; j++) {
- tval += "0";
- }
- double d = Double.parseDouble(tval);
- String result = format.format(d);
- assertEquals(i + ") e:" + tval + " r:" + result, tval, result);
- }
- for (int i = 0; i < 322; i++) {
- String tval = "0.";
- for (int j = 0; j < i; j++) {
- tval += "0";
- }
- tval += "1";
- double d = Double.parseDouble(tval);
- String result = format.format(d);
- assertEquals(i + ") e:" + tval + " r:" + result, tval, result);
+ format.setMaximumFractionDigits(1);
+
+ assertEquals("1", format.format(0.99));
+ assertEquals("1", format.format(0.95));
+ assertEquals("0.9", format.format(0.94));
+ assertEquals("0.9", format.format(0.90));
+
+ assertEquals("0.2", format.format(0.19));
+ assertEquals("0.2", format.format(0.15));
+ assertEquals("0.1", format.format(0.14));
+ assertEquals("0.1", format.format(0.10));
+
+ format.setMaximumFractionDigits(10);
+ assertEquals("1", format.format(0.99999999999));
+ assertEquals("1", format.format(0.99999999995));
+ assertEquals("0.9999999999", format.format(0.99999999994));
+ assertEquals("0.9999999999", format.format(0.99999999990));
+
+ assertEquals("0.1111111112", format.format(0.11111111119));
+ assertEquals("0.1111111112", format.format(0.11111111115));
+ assertEquals("0.1111111111", format.format(0.11111111114));
+ assertEquals("0.1111111111", format.format(0.11111111110));
+
+ format.setMaximumFractionDigits(14);
+ assertEquals("1", format.format(0.999999999999999));
+ assertEquals("1", format.format(0.999999999999995));
+ assertEquals("0.99999999999999", format.format(0.999999999999994));
+ assertEquals("0.99999999999999", format.format(0.999999999999990));
+
+ assertEquals("0.11111111111112", format.format(0.111111111111119));
+ assertEquals("0.11111111111112", format.format(0.111111111111115));
+ assertEquals("0.11111111111111", format.format(0.111111111111114));
+ assertEquals("0.11111111111111", format.format(0.111111111111110));
+ }
+
+ // This demonstrates rounding at the 15th decimal digit. By setting the maximum fraction digits
+ // we force rounding at a point just below the full IEEE 754 precision. IEEE 754 should be
+ // precise to just above 15 decimal digits.
+ // df.format() with no limits always emits up to 16 decimal digits, slightly above what IEEE 754
+ // can store precisely.
+ public void test_formatDouble_roundingTo15Digits() throws Exception {
+ final DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US);
+ DecimalFormat df = new DecimalFormat("#.#", dfs);
+ df.setMaximumIntegerDigits(400);
+ df.setGroupingUsed(false);
+
+ df.setMaximumFractionDigits(0);
+ assertEquals("1000000000000000", df.format(999999999999999.9));
+ df.setMaximumFractionDigits(1);
+ assertEquals("100000000000000", df.format(99999999999999.99));
+ df.setMaximumFractionDigits(2);
+ assertEquals("10000000000000", df.format(9999999999999.999));
+ df.setMaximumFractionDigits(3);
+ assertEquals("1000000000000", df.format(999999999999.9999));
+ df.setMaximumFractionDigits(4);
+ assertEquals("100000000000", df.format(99999999999.99999));
+ df.setMaximumFractionDigits(5);
+ assertEquals("10000000000", df.format(9999999999.999999));
+ df.setMaximumFractionDigits(6);
+ assertEquals("1000000000", df.format(999999999.9999999));
+ df.setMaximumFractionDigits(7);
+ assertEquals("100000000", df.format(99999999.99999999));
+ df.setMaximumFractionDigits(8);
+ assertEquals("10000000", df.format(9999999.999999999));
+ df.setMaximumFractionDigits(9);
+ assertEquals("1000000", df.format(999999.9999999999));
+ df.setMaximumFractionDigits(10);
+ assertEquals("100000", df.format(99999.99999999999));
+ df.setMaximumFractionDigits(11);
+ assertEquals("10000", df.format(9999.999999999999));
+ df.setMaximumFractionDigits(12);
+ assertEquals("1000", df.format(999.9999999999999));
+ df.setMaximumFractionDigits(13);
+ assertEquals("100", df.format(99.99999999999999));
+ df.setMaximumFractionDigits(14);
+ assertEquals("10", df.format(9.999999999999999));
+ df.setMaximumFractionDigits(15);
+ assertEquals("1", df.format(0.9999999999999999));
+ }
+
+ // This checks formatting over most of the representable IEEE 754 range using a formatter that
+ // should be performing no lossy rounding.
+ // It checks that the formatted double can be parsed to get the original double.
+ // IEEE 754 can represent values from (decimal) ~2.22507E−308 to ~1.79769E308 to full precision.
+ // Close to zero it can go down to 4.94066E-324 with a loss of precision.
+ // At the extremes of the double range this test will not be testing doubles that exactly
+ // represent powers of 10. The test is only interested in whether the doubles closest
+ // to powers of 10 that can be represented can each be turned into a string and read back again
+ // to arrive at the original double.
+ public void test_formatDouble_wideRange() throws Exception {
+ for (int i = -324; i < 309; i++) {
+ // Generate a decimal number we are interested in: 1 * 10^i
+ String stringForm = "1e" + i;
+ BigDecimal bigDecimal = new BigDecimal(stringForm);
+
+ // Obtain the nearest double representation of the decimal number.
+ // This is lossy because going from BigDecimal -> double is inexact, but we should
+ // arrive at a number that is as close as possible to the decimal value. We assume that
+ // BigDecimal is capable of this, but it is not critical to this test if it gets it a
+ // little wrong, though it may mean we are testing a double value different from the one
+ // we thought we were.
+ double d = bigDecimal.doubleValue();
+
+ assertDecimalFormatIsLossless(d);
}
}
- public void test_formatDouble_varyingScaleProblemCases() throws Exception {
+ // This test is a regression test for http://b/17656132.
+ // It checks hand-picked values can be formatted and parsed to get the original double.
+ // The formatter as configured should perform no rounding.
+ public void test_formatDouble_roundingProblemCases() throws Exception {
+ // Most of the double literals below are not exactly representable in IEEE 754 but
+ // it should not matter to this test.
+ assertDecimalFormatIsLossless(999999999999999.9);
+ assertDecimalFormatIsLossless(99999999999999.99);
+ assertDecimalFormatIsLossless(9999999999999.999);
+ assertDecimalFormatIsLossless(999999999999.9999);
+ assertDecimalFormatIsLossless(99999999999.99999);
+ assertDecimalFormatIsLossless(9999999999.999999);
+ assertDecimalFormatIsLossless(999999999.9999999);
+ assertDecimalFormatIsLossless(99999999.99999999);
+ assertDecimalFormatIsLossless(9999999.999999999);
+ assertDecimalFormatIsLossless(999999.9999999999);
+ assertDecimalFormatIsLossless(99999.99999999999);
+ assertDecimalFormatIsLossless(9999.999999999999);
+ assertDecimalFormatIsLossless(999.9999999999999);
+ assertDecimalFormatIsLossless(99.99999999999999);
+ assertDecimalFormatIsLossless(9.999999999999999);
+ assertDecimalFormatIsLossless(0.9999999999999999);
+ }
+
+ // This test checks hand-picked values can be formatted and parsed to get the original double.
+ // The formatter as configured should perform no rounding.
+ // These numbers are not affected by http://b/17656132.
+ public void test_formatDouble_varyingScale() throws Exception {
+ // Most of the double literals below are not exactly representable in IEEE 754 but
+ // it should not matter to this test.
+
+ assertDecimalFormatIsLossless(999999999999999.);
+
+ assertDecimalFormatIsLossless(123456789012345.);
+ assertDecimalFormatIsLossless(12345678901234.5);
+ assertDecimalFormatIsLossless(1234567890123.25);
+ assertDecimalFormatIsLossless(999999999999.375);
+ assertDecimalFormatIsLossless(99999999999.0625);
+ assertDecimalFormatIsLossless(9999999999.03125);
+ assertDecimalFormatIsLossless(999999999.015625);
+ assertDecimalFormatIsLossless(99999999.0078125);
+ assertDecimalFormatIsLossless(9999999.00390625);
+ assertDecimalFormatIsLossless(999999.001953125);
+ assertDecimalFormatIsLossless(9999.00048828125);
+ assertDecimalFormatIsLossless(999.000244140625);
+ assertDecimalFormatIsLossless(99.0001220703125);
+ assertDecimalFormatIsLossless(9.00006103515625);
+ assertDecimalFormatIsLossless(0.000030517578125);
+ }
+
+ private static void assertDecimalFormatIsLossless(double d) throws Exception {
final DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US);
DecimalFormat format = new DecimalFormat("#0.#", dfs);
+ format.setGroupingUsed(false);
format.setMaximumIntegerDigits(400);
format.setMaximumFractionDigits(400);
- assertEquals("999999999999999", format.format(999999999999999.));
- assertEquals("999999999999999.9", format.format(999999999999999.9));
- assertEquals("99999999999999.98", format.format(99999999999999.99));
- assertEquals("9999999999999.998", format.format(9999999999999.999));
- assertEquals("999999999999.9999", format.format(999999999999.9999));
- assertEquals("99999999999.99998", format.format(99999999999.99999));
- assertEquals("9999999999.999998", format.format(9999999999.999999));
- assertEquals("999999999.9999999", format.format(999999999.9999999));
- assertEquals("99999999.99999999", format.format(99999999.99999999));
- assertEquals("9999999.999999998", format.format(9999999.999999999));
- assertEquals("99999.99999999999", format.format(99999.99999999999));
- assertEquals("9999.999999999998", format.format(9999.999999999999));
- assertEquals("999.9999999999999", format.format(999.9999999999999));
- assertEquals("99.99999999999999", format.format(99.99999999999999));
- assertEquals("9.999999999999998", format.format(9.999999999999999));
- assertEquals("0.9999999999999999", format.format(.9999999999999999));
+ // Every floating point binary can be represented exactly in decimal if you have enough
+ // digits. This shows the value actually being tested.
+ String testId = "decimalValue: " + new BigDecimal(d);
+
+ // As a sanity check we try out parseDouble() with the string generated by
+ // Double.toString(). Strictly speaking Double.toString() is probably not guaranteed to be
+ // lossless, but in reality it probably is, or at least is close enough.
+ assertDoubleEqual(
+ testId + " failed parseDouble(toString()) sanity check",
+ d, Double.parseDouble(Double.toString(d)));
+
+ // Format the number: If this is lossy it is a problem. We are trying to check that it
+ // doesn't lose any unnecessary precision.
+ String result = format.format(d);
+
+ // Here we use Double.parseDouble() which should able to parse a number we know was
+ // representable as a double into the original double. If parseDouble() is not implemented
+ // correctly the test is invalid.
+ double doubleParsed = Double.parseDouble(result);
+ assertDoubleEqual(testId + " (format() produced " + result + ")",
+ d, doubleParsed);
+
+ // For completeness we try to parse using the formatter too. If this fails but the format
+ // above didn't it may be a problem with parse(), or with format() that we didn't spot.
+ assertDoubleEqual(testId + " failed parse(format()) check",
+ d, format.parse(result).doubleValue());
}
- public void test_formatDouble_varyingScale() throws Exception {
- final DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US);
- DecimalFormat format = new DecimalFormat("#0.#", dfs);
- format.setMaximumIntegerDigits(400);
- format.setMaximumFractionDigits(400);
+ private static void assertDoubleEqual(String message, double d, double doubleParsed) {
+ assertEquals(message,
+ createPrintableDouble(d),createPrintableDouble(doubleParsed));
+ }
- assertEquals("123456789012345", format.format(123456789012345.));
- assertEquals("12345678901234.5", format.format(12345678901234.5));
- assertEquals("1234567890123.25", format.format(1234567890123.25));
- assertEquals("999999999999.375", format.format(999999999999.375));
- assertEquals("99999999999.0625", format.format(99999999999.0625));
- assertEquals("9999999999.03125", format.format(9999999999.03125));
- assertEquals("999999999.015625", format.format(999999999.015625));
- assertEquals("99999999.0078125", format.format(99999999.0078125));
- assertEquals("9999999.00390625", format.format(9999999.00390625));
- assertEquals("999999.001953125", format.format(999999.001953125));
- assertEquals("9999.00048828125", format.format(9999.00048828125));
- assertEquals("999.000244140625", format.format(999.000244140625));
- assertEquals("99.0001220703125", format.format(99.0001220703125));
- assertEquals("9.00006103515625", format.format(9.00006103515625));
- assertEquals("0.000030517578125", format.format(0.000030517578125));
+ private static String createPrintableDouble(double d) {
+ return Double.toString(d) + "(" + Long.toHexString(Double.doubleToRawLongBits(d)) + ")";
+ }
+
+ // Concise demonstration of http://b/17656132 using hard-coded expected values.
+ public void test_formatDouble_bug17656132() {
+ final DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US);
+ DecimalFormat df = new DecimalFormat("#0.#", dfs);
+ df.setGroupingUsed(false);
+ df.setMaximumIntegerDigits(400);
+ df.setMaximumFractionDigits(400);
+
+ // The expected values below come from the RI and are correct 16 decimal digit
+ // representations of the formatted value. Android does something different.
+ // The decimal value given in each comment is the actual double value as represented by
+ // IEEE 754. See new BigDecimal(double).
+
+ // double: 999999999999999.9 is decimal 999999999999999.875
+ assertEquals("999999999999999.9", df.format(999999999999999.9));
+ // double: 99999999999999.98 is decimal 99999999999999.984375
+ assertEquals("99999999999999.98", df.format(99999999999999.98));
+ // double 9999999999999.998 is decimal 9999999999999.998046875
+ assertEquals("9999999999999.998", df.format(9999999999999.998));
+ // double 999999999999.9999 is decimal 999999999999.9998779296875
+ assertEquals("999999999999.9999", df.format(999999999999.9999));
+ // double 99999999999.99998 is decimal 99999999999.9999847412109375
+ assertEquals("99999999999.99998", df.format(99999999999.99998));
+ // double 9999999999.999998 is decimal 9999999999.9999980926513671875
+ assertEquals("9999999999.999998", df.format(9999999999.999998));
+ // double 1E23 is decimal 99999999999999991611392
+ assertEquals("9999999999999999", df.format(1E23));
}
public void test_getDecimalFormatSymbols() {