为什么这个数字向下舍入?

时间:2014-04-11 09:36:24

标签: java double number-formatting

我对Java NumberFormat的行为感到困惑。

考虑以下方法,将double值转换为其百分比表示形式,并将结果百分比舍入为三位小数:

public static String doubleToPercent(final double val) {
    NumberFormat nf = NumberFormat.getPercentInstance();
    // Default rounding mode is HALF_EVEN
    nf.setRoundingMode(RoundingMode.HALF_UP);
    nf.setMaximumFractionDigits(3);
    return nf.format(val);
}

舍入模式为HALF_UP

worksAsExpected的结果并不让我感到惊讶;测试通过:

@Test
public void worksAsExpected() {
    double input = 1.234585;
    String expected = "123.459%";
    String output = doubleToPercent(input);
    assertEquals(expected, output);
}

但是这个怎么样:

@Test
public void surprise() {
    double input = 1.234535;
    String expected = "123.454%";
    String output = doubleToPercent(input);
    assertEquals(expected, output);
}

为什么这个测试失败了?为什么1.234535向上舍入而1.234585被舍入?

另一方面,如果最后一个数字是6,则该数字将向上舍入。

@Test
public void noSurprise() {
    double input = 1.234536;
    String expected = "123.454%";
    String output = doubleToPercent(input);
    assertEquals(expected, output);
}

这与double精度的限制有关吗?我想像1.234535这样的数字在double的能力范围内。

我正在使用运行Windows 7 x86的Java 1.7.0_51。

感谢任何见解。

2 个答案:

答案 0 :(得分:2)

1.234535 = 1.2345349999999999379696191681432537734508514404296875为double,因此对于6位数,它向下舍入为1.23453。

您可以使用我的十进制/二进制转换器exploringbinary.com/binary-converter来查看会发生什么。

注意:与普通二进制数不同,二进制小数的精确十进制表示始终具有相同的位数:

0.001 =
0.125, 

0.1101101 =
0.8515625, 

0.00001110101011 =
0.05731201171875, 

1.0011110000001010011111000101101011000100011100011011 =
1.2345349999999999379696191681432537734508514404296875

etc.

如果您需要更多控制小数位和舍入,则必须使用BigDecimal。请注意,计算对数字执行的每个操作的舍入误差最好。 See this question for details

答案 1 :(得分:0)

使用双精度浮点格式(http://en.wikipedia.org/wiki/Double-precision_floating-point_format)存储数字。

我很惊讶您遇到了精度方面的问题,遗憾的是,double在Java中并不是一种执行精确计算的非常可靠的方法。 这也是其中一个原因,因为对于数学模块,其他工具如Matlab是首选。

无论如何,在你的例子中,你可以解决你的问题(希望)增加nf.setMaximumFractionDigits(<something bigger than 3>);

中数字的数字 或者,您可以根据需要切换到BigDecimalDecimalFormat