Gob*_*0st 6 c++ floating-point precision gotw
http://www.gotw.ca/gotw/067.htm中有一个例子
int main()
{
double x = 1e8;
//float x = 1e8;
while( x > 0 )
{
--x;
}
}
Run Code Online (Sandbox Code Playgroud)
当你将double改为float时,它在VS2008中是一个无限循环.根据Gotw的解释:
如果float不能准确表示0到1e8之间的所有整数值,该怎么办?然后修改后的程序将开始倒计时,但最终将达到无法表示的值N和N-1 == N(由于浮点精度不足)......然后循环将保持卡住状态在该值上,直到运行程序的机器耗尽电量.
根据我的理解,IEEE754浮点数是单精度(32位),浮点数范围应为+/- 3.4e +/- 38,它应该有7位数字.
但我仍然不明白这究竟是怎么发生的:"最终达到一个无法表示的值N和N-1 == N(由于浮点精度不足)." 有人可以尝试解释这一点吗?
一些额外的信息:当我使用双x = 1e8时,它在大约1秒内完成,当我将其更改为浮动x = 1e8时,它运行的时间更长(5分钟后仍然运行),如果我将其更改为float x = 1e7;,它在大约1秒钟内完成.
我的测试环境是VS2008.
顺便说一句,我不是要求基本的IEEE 754格式解释,因为我已经明白了.
谢谢
好吧,为了论证,我们假设我们有一个处理器,它代表一个带有7个有效十进制数字的浮点数,以及一个尾数,例如2个十进制数字.所以现在数字1e8将被存储为
1.000 000 e 08
Run Code Online (Sandbox Code Playgroud)
(无需实际存储"."和"e".)
所以现在你要计算"1e8 - 1".1表示为
1.000 000 e 00
Run Code Online (Sandbox Code Playgroud)
现在,为了做减法,我们首先做一个减法与无限的精度,然后正常化,使前第一个数字"" 在1到9之间,最后四舍五入到最接近的可表示值(比如说,偶数就是中断)."1e8 - 1"的无限精度结果是
0.99 999 999 e 08
Run Code Online (Sandbox Code Playgroud)
或标准化
9.9 999 999 e 07
Run Code Online (Sandbox Code Playgroud)
可以看出,无限精度结果在有效数中需要比我们的体系结构实际提供的数字多一个数字; 因此我们需要将无限精确的结果舍入(并重新标准化)为7位有效数字,从而产生
1.000 000 e 08
Run Code Online (Sandbox Code Playgroud)
因此,你最终得到"1e8 - 1 == 1e8",你的循环永远不会终止.
现在,实际上你使用的是IEEE 754二进制浮点数,它们有点不同,但原理大致相同.
| 归档时间: |
|
| 查看次数: |
495 次 |
| 最近记录: |