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