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

Java 为什么这个数字要向下舍入?,java,double,number-formatting,Java,Double,Number Formatting,我对Java的NumberFormat的行为感到困惑 考虑以下方法,将双精度值转换为其百分比表示形式,并将结果百分比四舍五入到小数点后三位: public static String doubleToPercent(final double val) { NumberFormat nf = NumberFormat.getPercentInstance(); // Default rounding mode is HALF_EVEN nf.setRoundingMode(

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

考虑以下方法,将双精度值转换为其百分比表示形式,并将结果百分比四舍五入到小数点后三位:

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);
}
取整模式为
向上取整

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);
}
这与
双精度的限制有关吗?我猜像
1.234535
这样的数字在
double
的能力范围内

我使用的是运行Windows7x86的Java1.7.051


非常感谢您的帮助。

这些数字是使用双精度浮点格式()存储的 我并不奇怪您会遇到精度方面的问题,不幸的是,Java中的
double
并不是执行精确计算的非常可靠的方法。 这也是一个原因,因为对于数学模块,首选其他工具,如Matlab 无论如何,在您的示例中,您可以解决您的问题(希望)增加
nf.setMaximumFractionDigits()中数字的数量

或者,您可以根据需要切换到
BigDecimal
DecimalFormat

1.234535=1.2345344999999993796961916814325374508514404296875作为双精度,将其四舍五入为1.23453

您可以使用我的十进制/二进制转换器来查看发生了什么

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

0.001 =
0.125, 

0.1101101 =
0.8515625, 

0.00001110101011 =
0.05731201171875, 

1.0011110000001010011111000101101011000100011100011011 =
1.2345349999999999379696191681432537734508514404296875

etc.

如果您需要更多地控制小数点和四舍五入,则必须使用。请注意,最好计算对数字执行的每个操作的舍入误差

谢谢<代码>十进制格式
也会产生不正确的结果。但是我同意
BigDecimal
是一条路要走。我对Matlab的评论感到困惑。Matlab和Java都使用IEEE 754 64位二进制浮点来表示双精度。您是否使用工具来获取该数字?@Matthias Braun是的。我使用了我的十进制/二进制转换器(),对于1.234535,它返回1.001111000000101001111100010110101100011100010110100011110…,它将53位舍入为1.001111000000101001111100010110110001110001011。然后我把它放入二进制到十进制的转换器中,得到1.234534499999999379696191681432537734508514404296875。(还有其他方法——可能更容易——来完成这项工作。)@Aaron Digulla这是一项相当繁重的编辑工作。删除评论、将评论移动到答案中并合并答案是正常的吗?不,但我的答案只是部分正确,你显然比我更了解这一点,而且评论中有太多有用的信息,我觉得我应该纠正这一点。这似乎是最好的解决办法。请随意改进我的编辑:-)我的主要反对意见是最后一段(关于BigDecimal)--我没有写。你能把这归咎于谁吗?谢谢