ICU-10542 Add more tests. Use Math.log10() instead of multiplying by 0.1 in a for loop.

X-SVN-Rev: 34656
This commit is contained in:
Travis Keep 2013-11-12 01:38:45 +00:00
parent 42dee8ca3b
commit 7db028c450
2 changed files with 65 additions and 22 deletions

View File

@ -892,13 +892,6 @@ public class DecimalFormat extends NumberFormat {
// This is to fix rounding for scientific notation. See ticket:10542.
// This code should go away when a permanent fix is done for ticket:9931.
//
// The problem:
// DigitList does ROUND_HALF_EVEN only if the number of digits in the number exceeds the precision.
// Therefore if rounding mode is set to anything besides ROUND_HALF_EVEN, the results will be incorrect.
// The {@link #resetActualRounding} method addresses this problem, but its solution only works for fixed
// decimal numbers.
//
// The solution:
// This block of code only executes for scientific notation so it will not interfere with the
// previous fix in {@link #resetActualRounding} for fixed decimal numbers.
// Moreover this code only runs when there is rounding to be done (precision > 0) and when the
@ -907,21 +900,16 @@ public class DecimalFormat extends NumberFormat {
// the number of digits indicated by precision. In this way, we avoid using the default
// ROUND_HALF_EVEN behavior of DigitList. For example, if number = 0.003016 and roundingMode =
// ROUND_DOWN and precision = 3 then after this code executes, number = 0.00301 (3 significant digits)
if (useExponentialNotation && precision > 0 && roundingMode != BigDecimal.ROUND_HALF_EVEN) {
double adjNumber = number;
for (int i = 1; i < precision; i++) {
adjNumber *= 0.1;
}
double roundingInc = 1.0;
double roundingIncReciprocal = 1.0;
while (adjNumber < 1.0) {
roundingIncReciprocal *= 10;
adjNumber *= 10;
}
while (adjNumber >= 10.0) {
roundingInc *= 10;
roundingIncReciprocal = 0.0;
adjNumber *= 0.1;
if (useExponentialNotation && precision > 0 && number != 0.0 && roundingMode != BigDecimal.ROUND_HALF_EVEN) {
int log10RoundingIncr = 1 - precision + (int) Math.floor(Math.log10(Math.abs(number)));
double roundingIncReciprocal = 0.0;
double roundingInc = 0.0;
if (log10RoundingIncr < 0) {
roundingIncReciprocal =
BigDecimal.ONE.movePointRight(-log10RoundingIncr).doubleValue();
} else {
roundingInc =
BigDecimal.ONE.movePointRight(log10RoundingIncr).doubleValue();
}
number = DecimalFormat.round(number, roundingInc, roundingIncReciprocal, roundingMode, isNegative);
}

View File

@ -86,6 +86,61 @@ public class NumberFormatTest extends com.ibm.icu.dev.test.TestFmwk {
{"-3.01E3", "-3.01E3", "-3.00E3", "3.01E3", "3.02E3", "3.02E3"},
{"-3.01E3", "-3.01E3", "-3.01E3", "3.02E3", "3.02E3", "3.02E3"}};
verifyRounding(format, values, expected, roundingModes, descriptions);
values = new double[]{0.0, -0.0};
// The order of these expected values correspond to the order of roundingModes and the order of values.
expected = new String[][]{
{"0.00E0", "-0.00E0"},
{"0.00E0", "-0.00E0"},
{"0.00E0", "-0.00E0"},
{"0.00E0", "-0.00E0"},
{"0.00E0", "-0.00E0"},
{"0.00E0", "-0.00E0"},
{"0.00E0", "-0.00E0"}};
verifyRounding(format, values, expected, roundingModes, descriptions);
values = new double[]{1e25, 1e25 + 1e15, 1e25 - 1e15};
// The order of these expected values correspond to the order of roundingModes and the order of values.
expected = new String[][]{
{"1.00E25", "1.01E25", "1.00E25"},
{"1.00E25", "1.00E25", "9.99E24"},
{"1.00E25", "1.00E25", "9.99E24"},
{"1.00E25", "1.00E25", "1.00E25"},
{"1.00E25", "1.00E25", "1.00E25"},
{"1.00E25", "1.00E25", "1.00E25"},
{"1.00E25", "1.01E25", "1.00E25"}};
verifyRounding(format, values, expected, roundingModes, descriptions);
values = new double[]{-1e25, -1e25 + 1e15, -1e25 - 1e15};
// The order of these expected values correspond to the order of roundingModes and the order of values.
expected = new String[][]{
{"-1.00E25", "-9.99E24", "-1.00E25"},
{"-1.00E25", "-9.99E24", "-1.00E25"},
{"-1.00E25", "-1.00E25", "-1.01E25"},
{"-1.00E25", "-1.00E25", "-1.00E25"},
{"-1.00E25", "-1.00E25", "-1.00E25"},
{"-1.00E25", "-1.00E25", "-1.00E25"},
{"-1.00E25", "-1.00E25", "-1.01E25"}};
verifyRounding(format, values, expected, roundingModes, descriptions);
values = new double[]{1e-25, 1e-25 + 1e-35, 1e-25 - 1e-35};
// The order of these expected values correspond to the order of roundingModes and the order of values.
expected = new String[][]{
{"1.00E-25", "1.01E-25", "1.00E-25"},
{"1.00E-25", "1.00E-25", "9.99E-26"},
{"1.00E-25", "1.00E-25", "9.99E-26"},
{"1.00E-25", "1.00E-25", "1.00E-25"},
{"1.00E-25", "1.00E-25", "1.00E-25"},
{"1.00E-25", "1.00E-25", "1.00E-25"},
{"1.00E-25", "1.01E-25", "1.00E-25"}};
verifyRounding(format, values, expected, roundingModes, descriptions);
values = new double[]{-1e-25, -1e-25 + 1e-35, -1e-25 - 1e-35};
// The order of these expected values correspond to the order of roundingModes and the order of values.
expected = new String[][]{
{"-1.00E-25", "-9.99E-26", "-1.00E-25"},
{"-1.00E-25", "-9.99E-26", "-1.00E-25"},
{"-1.00E-25", "-1.00E-25", "-1.01E-25"},
{"-1.00E-25", "-1.00E-25", "-1.00E-25"},
{"-1.00E-25", "-1.00E-25", "-1.00E-25"},
{"-1.00E-25", "-1.00E-25", "-1.00E-25"},
{"-1.00E-25", "-1.00E-25", "-1.01E-25"}};
verifyRounding(format, values, expected, roundingModes, descriptions);
}
private void verifyRounding(DecimalFormat format, double[] values, String[][] expected, int[] roundingModes,