我正在查看旧的考试题目(目前是大学的第一年)。我想知道是否有人可以更彻底地解释为什么后面的for
循环不应该结束。为什么会这样?我知道它因为四舍五入错误而跳过100.0,但为什么呢?
for(double i = 0.0; i != 100; i = i +0.1){
System.out.println(i);
}
答案 0 :(得分:42)
数字0.1不能用二进制精确表示,很像1/3不能用十进制精确表示,因此你无法保证:
0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1==1
这是因为binary:
0.1=(binary)0.00011001100110011001100110011001....... forever
然而,double不能包含无限精度,因此,正如我们接近1/3到0.3333333所以二进制表示必须接近0.1。
小数点后你可能会发现
1/3+1/3+1/3
=0.333+0.333+0.333
=0.999
这是完全相同的问题。它不应被视为浮点数的弱点,因为我们自己的十进制系统具有相同的困难(但对于不同的数字,具有base-3系统的人会觉得奇怪,我们努力代表1/3)。然而,这是一个需要注意的问题。
Andrea Ligios提供的live demo显示了这些错误。
答案 1 :(得分:11)
计算机(至少是当前计算机)使用二进制数据。而且,计算机在其算术逻辑单元中处理(即32位,64位等)存在长度限制。 以二进制形式表示整数很简单,相反我们不能对浮点表示同样的事情。
如上所示,有一种根据IEEE-754表示浮点的特殊方式,它也被处理器生产商和软件人员接受为事实,这就是为什么每个人都知道它的重要性。
如果我们查看java中的double的最大值(Double.MAX_VALUE)是1.7976931348623157E308(> 10 ^ 307)。只有64位,可以表示大量数字,但问题是精度。
as'=='和'!='运算符按位比较数字,在你的情况下,0.1 + 0.1 + 0.1就其表示的位而言不等于0.3。
作为结论,为了在几位中适应巨大的浮点数,聪明的工程师决定牺牲精度。如果您正在处理浮点数,除非您确定自己在做什么,否则不应使用“==”或“!=”。
答案 2 :(得分:10)
作为一般规则,永远不要使用double
进行迭代,因为舍入错误(在基数10中写入时0.1可能看起来不错,但尝试将其写入基数2 - 这是double
使用的)。你应该做的是使用普通的int
变量来迭代并计算它的double
。
for (int i = 0; i < 1000; i++)
System.out.println(i/10.0);
答案 3 :(得分:8)
首先,我要解释一些关于双打的事情。这实际上将在十点进行,以便于理解。
取三分之一值并尝试在十分之一表达。你得到0.3333333333333 ....假设我们需要把它四舍五入到4个位置。我们得到0.3333。现在,让我们再添加1/3。我们得到0.6666333333333 ....其回合至0.6666。让我们再添加1/3。我们得到0.9999,不 1。
同样的事情发生在基数2和十分之一。因为你要经过0.1 10 而0.1 10 是一个重复的二进制值(如基数十的0.1666666 ...),你将有足够的错误错过当你到达那里时,有一百个。
1/2可以用十进制表示,也可以用1/5表示。这是因为分母的主要因素是基数因子的子集。对于基数为10的三分之一或基数为二的十分之一,情况并非如此。
答案 4 :(得分:0)
应为(双a = 0.0; a <100.0; a = a + 0.01)
尝试查看是否有效