在Java中将double类型数据打印到System.out

7

这段代码并不像我预想的那样起作用。

a=-1;   
b=0.1;   
for(i=0;i<=20;i++){  
    System.out.println(i + ". x= " + a);   
    a=a+b;   
}       

在控制台上,我应该看到:
0. x= -1.0  
1. x= -0.9  
2. x= -0.8  
3. x= -0.7  
4. x= -0.6  
5. x= -0.5  
6. x= -0.4  
7. x= -0.3  

但实际情况是这样的:

0. x= -1.0  
1. x= -0.9  
2. x= -0.8  
3. x= -0.7000000000000001  
4. x= -0.6000000000000001  
5. x= -0.5000000000000001  
6. x= -0.40000000000000013  
7. x= -0.30000000000000016  
8. x= -0.20000000000000015  
9. x= -0.10000000000000014  
10. x= -1.3877787807814457E-16  
11. x= 0.09999999999999987  
12. x= 0.19999999999999987  
13. x= 0.2999999999999999  
14. x= 0.3999999999999999  
15. x= 0.4999999999999999  
16. x= 0.5999999999999999  
17. x= 0.6999999999999998  
18. x= 0.7999999999999998  
19. x= 0.8999999999999998  
20. x= 0.9999999999999998  

我在这里做错了什么?

你的代码示例中没有指定a和b的类型。能否添加一下? - David Brossard
你没有做错任何事情。只是十进制小数无法被二进制完美表示,因此预期值和实际存储值之间存在一些差异。 - jonhopkins
3
这是许多问题的重复。让我们找到一个合适的候选重复问题并将其关闭。 - Hovercraft Full Of Eels
1
你可能会发现http://floating-point-gui.de/很有帮助。 - legoscia
4
你提出了一个问题并提供了所有细节。即使这是重复的问题,很少有人在第一次提问时这样做。+1 - Sotirios Delimanolis
我也给了@SotiriosDelimanolis的+1赞,然后立即关闭了你的问题 :P - Sage
6个回答

4
你所遇到的问题是浮点数不精确。因为double具有有限的精度,它们无法精确表示所有十进制数字。特别地,0.1是一个循环二进制数,因此所有有限长度的二进制表示都会有误差。这意味着计算机无法完全存储你使用的数字。
你可以通过格式化输出来修复输出结果(例如:System.out.format("%d. x=%.1f", i, a);),或者你可以使用BigDecimal代替double来修正你的数字。另外,你也可以通过每次计算a而不是累加(并每次添加增量误差)来减少问题的规模,例如:a = i/10.0。这取决于你想要实现什么目标。
重要的“主要信息”是不能依靠双精度浮点数提供完全准确的答案,并且你应该预期浮点算术中的小误差。

一篇非常好的解释,既提供了两种不同情景的原因,也给出了解决方案! - blalasaadri

2

当您需要精确计算时,请使用BigDecimal而不是double

有关更多详细信息,请参见此问题:Double vs. BigDecimal?

编辑:如果您不需要精度;您可以接受格式化输出..


10
不需要。他只需要对输出进行格式化。这些不是金融或火箭工程方程,而只是简单的浮点计算。使用带有格式化输出的double类型就可以了。 - Hovercraft Full Of Eels
@HovercraftFullOfEels:我们怎么知道呢?我们的提问者没有告诉我们这个的下游应用是什么。 - Jack Aidley

2

尝试格式化您的输出:

for(i=0;i<=20;i++){  
    System.out.format("%d. x=%.1f", i, a);   
    a=a+b;   
}  

更多关于格式化输出的信息,请参见文档


1
我的个人喜好是使用System.out.printf(),与C语言的类似,你需要定义要传递给它的变量类型,然后将其传递给这个类型。例如,System.out.printf("%.1f", yourDouble);应该就可以了。
资源: Printf速查表

1
记录一下,System.out.printfSystem.out.format完全相同。 - Eric Wilson

0
您可能正在为这些对象使用整数。 相反,当您要显示它们时,请先调用此方法:
public static double round(double value, int places) {
    if (places < 0) throw new IllegalArgumentException();

    BigDecimal bd = new BigDecimal(value);
    bd = bd.setScale(places, BigDecimal.ROUND_HALF_UP);
    return bd.doubleValue();
}

或者使用正确类型的对象而不是整数...


0

使用String.format或者直接在System.out.println中使用繁琐的十进制格式语法,你就可以看到想要的结果了。浮点数运算在内部以不同的方式表示。因此,对这些值进行简单的打印并不能总是给你所需的屏幕显示格式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接