为什么使用double的for循环无法终止

时间:2013-11-11 13:07:26

标签: java for-loop floating-point-precision

我正在查看旧的考试题目(目前是大学的第一年)。我想知道是否有人可以更彻底地解释为什么后面的for循环不应该结束。为什么会这样?我知道它因为四舍五入错误而跳过100.0,但为什么呢?

for(double i = 0.0; i != 100; i = i +0.1){
    System.out.println(i);
}

5 个答案:

答案 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位等)存在长度限制。 以二进制形式表示整数很简单,相反我们不能对浮点表示同样的事情。 64 bits floating point representation

如上所示,有一种根据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)

尝试查看是否有效