C++ Gotw 67中的一个示例
这方面有一个例子 当您将double更改为float时,它在VS2008中是一个无限循环。 根据Gotw的解释: 如果float不能准确地表示从0到0的所有整数值,该怎么办 1e8?然后修改后的程序将开始倒计时,但 最终达到一个无法表示的值N,并且 N-1==N(由于浮点精度不足)。。。然后 循环将一直停留在该值上,直到 程序正在运行,电源耗尽 据我所知,IEEE754浮点为单精度(32位),浮点范围应为+/-3.4e+/-38,有效位数应为7位 但我仍然不明白这到底是怎么发生的:“最终达到一个无法表示的值N,并且N-1==N(由于浮点精度不足)。”有人能解释一下这个位吗 一点额外的信息:当我使用double x=1e8时,当我将其更改为 float x=1e8,运行时间更长(5分钟后仍在运行),如果我将其更改为C++ Gotw 67中的一个示例,c++,floating-point,precision,gotw,C++,Floating Point,Precision,Gotw,这方面有一个例子 当您将double更改为float时,它在VS2008中是一个无限循环。 根据Gotw的解释: 如果float不能准确地表示从0到0的所有整数值,该怎么办 1e8?然后修改后的程序将开始倒计时,但 最终达到一个无法表示的值N,并且 N-1==N(由于浮点精度不足)。。。然后 循环将一直停留在该值上,直到 程序正在运行,电源耗尽 据我所知,IEEE754浮点为单精度(32位),浮点范围应为+/-3.4e+/-38,有效位数应为7位 但我仍然不明白这到底是怎么发生的:“最终达到一个
float x=1e7代码>,大约在1秒内完成
我的测试环境是VS2008
顺便说一句,我不是在问基本的IEEE 754格式解释,因为我已经理解了
感谢如果n-1和n由于浮点数的近似性质而具有相同的表示形式,那么n-1的结果是什么?关于“达到”一个无法表示的值,我认为Herb包含了相当深奥的浮点表示的可能性
对于任何普通的浮点表示法,您要么从该值开始(即停留在第一个值上),要么在以零为中心的连续整数范围内的某个位置,可以精确表示,以便倒计时成功
对于IEEE 754,32位表示,通常是C++中的代码>浮点< /C> >,有23位尾数,而C++中的64位表示,通常是代码>双,有52位尾数。这意味着使用double
至少可以精确表示范围-(2^52-1)中的整数。。。2^52-1. 我不太确定这个范围是否可以用另一个因子2来扩展。想起来我有点头晕。:-)
干杯,好吧,为了便于讨论,让我们假设我们有一个处理器,它代表一个具有7个有效十进制数字的浮点数,以及一个具有2个十进制数字的尾数。所以现在数字1e8将存储为
1.000 000 e 08
(其中,“.”和“e”不需要实际存储。)
现在你要计算“1e8-1”。1表示为
1.000 000 e 00
现在,为了进行减法,我们首先以无限精度进行减法,然后进行规格化,使“.”之前的第一个数字介于1和9之间,最后四舍五入到最接近的可表示值(例如,收支平衡)。“1e8-1”的无限精度结果为
还是正常化
9.9 999 999 e 07
可以看出,无限精度结果需要比我们的体系结构实际提供的有效位多一位数字;因此,我们需要将无限精确的结果舍入(并重新规格化)为7位有效数字,从而产生
1.000 000 e 08
因此,您以“1e8-1==1e8”结束,并且您的循环永远不会终止
现在,实际上您使用的是IEEE 754二进制浮点,虽然有点不同,但原理大致相同。操作x--
相当于x=x-1
。这意味着取x
的原始值,减去1
(按照IEEE 754-1985的规定,使用无限精度),然后将结果四舍五入到浮点值空间的下一个值
以下[-10;10]
中的i给出了数字1.0e8f+i
的四舍五入结果:
-10: 9.9999992E7 (binary +|10011001|01111101011110000011111)
-9: 9.9999992E7 (binary +|10011001|01111101011110000011111)
-8: 9.9999992E7 (binary +|10011001|01111101011110000011111)
-7: 9.9999992E7 (binary +|10011001|01111101011110000011111)
-6: 9.9999992E7 (binary +|10011001|01111101011110000011111)
-5: 9.9999992E7 (binary +|10011001|01111101011110000011111)
-4: 1.0E8 (binary +|10011001|01111101011110000100000)
-3: 1.0E8 (binary +|10011001|01111101011110000100000)
-2: 1.0E8 (binary +|10011001|01111101011110000100000)
-1: 1.0E8 (binary +|10011001|01111101011110000100000)
0: 1.0E8 (binary +|10011001|01111101011110000100000)
1: 1.0E8 (binary +|10011001|01111101011110000100000)
2: 1.0E8 (binary +|10011001|01111101011110000100000)
3: 1.0E8 (binary +|10011001|01111101011110000100000)
4: 1.0E8 (binary +|10011001|01111101011110000100000)
5: 1.00000008E8 (binary +|10011001|01111101011110000100001)
6: 1.00000008E8 (binary +|10011001|01111101011110000100001)
7: 1.00000008E8 (binary +|10011001|01111101011110000100001)
8: 1.00000008E8 (binary +|10011001|01111101011110000100001)
9: 1.00000008E8 (binary +|10011001|01111101011110000100001)
10: 1.00000008E8 (binary +|10011001|01111101011110000100001)
因此,您可以看到1.0e8f
和1.0e8f+4
以及其他一些数字具有相同的表示形式。既然您已经知道IEEE 754-1985浮点格式的详细信息,那么您也知道剩余的数字必须已被舍入。这并没有回答他的问题“这到底是如何发生的”[sic]。也就是说,n-1==n怎么可能。你的答案是关于浮点精度的一般答案,而不是这个特定的问题…@巴特:它确实回答了你指出的问题,但不是OP提出的“最终到达”的问题。确实很难想象“最终到达”是有意义的。我想我会称这种说法为“反常的”:-@Alf这是我的观点,尽管措辞可能很糟糕。Thanks@Francesco:形式数学推理基于鸽子洞原理。FLOAT_MAX>10^38,因此有超过10^38个正整数1.000 000 e 08
-10: 9.9999992E7 (binary +|10011001|01111101011110000011111)
-9: 9.9999992E7 (binary +|10011001|01111101011110000011111)
-8: 9.9999992E7 (binary +|10011001|01111101011110000011111)
-7: 9.9999992E7 (binary +|10011001|01111101011110000011111)
-6: 9.9999992E7 (binary +|10011001|01111101011110000011111)
-5: 9.9999992E7 (binary +|10011001|01111101011110000011111)
-4: 1.0E8 (binary +|10011001|01111101011110000100000)
-3: 1.0E8 (binary +|10011001|01111101011110000100000)
-2: 1.0E8 (binary +|10011001|01111101011110000100000)
-1: 1.0E8 (binary +|10011001|01111101011110000100000)
0: 1.0E8 (binary +|10011001|01111101011110000100000)
1: 1.0E8 (binary +|10011001|01111101011110000100000)
2: 1.0E8 (binary +|10011001|01111101011110000100000)
3: 1.0E8 (binary +|10011001|01111101011110000100000)
4: 1.0E8 (binary +|10011001|01111101011110000100000)
5: 1.00000008E8 (binary +|10011001|01111101011110000100001)
6: 1.00000008E8 (binary +|10011001|01111101011110000100001)
7: 1.00000008E8 (binary +|10011001|01111101011110000100001)
8: 1.00000008E8 (binary +|10011001|01111101011110000100001)
9: 1.00000008E8 (binary +|10011001|01111101011110000100001)
10: 1.00000008E8 (binary +|10011001|01111101011110000100001)