Nar*_*rek 34 c++ math floating-point ieee-754
我已经看过很长的文章,解释了如何存储浮点数以及这些数字的算法是如何完成的,但请简要说明为什么我写的时候
cout << 1.0 / 3.0 <<endl;
Run Code Online (Sandbox Code Playgroud)
我看到0.333333,但是当我写的时候
cout << 1.0 / 3.0 + 1.0 / 3.0 + 1.0 / 3.0 << endl;
Run Code Online (Sandbox Code Playgroud)
我明白了1.
电脑如何做到这一点?请解释这个简单的例子.这对我来说已经足够了.
Pra*_*rav 28
Mar*_*utz 17
我们来做数学吧.为简洁起见,我们假设您只有四个重要(基数为2)的数字.
当然,因为gcd(2,3)=1
,1/3
在base-2中表示是周期性的.特别是,它无法准确表示,因此我们需要满足于近似
A := 1×1/4 + 0×1/8 + 1×1/16 + 1*1/32
Run Code Online (Sandbox Code Playgroud)
更靠近的实际价值1/3
比
A' := 1×1/4 + 0×1/8 + 1×1/16 + 0×1/32
Run Code Online (Sandbox Code Playgroud)
因此,A
以十进制打印给出0.34375(在您的示例中您看到0.33333的事实只是证明了a中有效数字的更大数字double
).
当我们添加这些三次时,我们得到了
A + A + A
= ( A + A ) + A
= ( (1/4 + 1/16 + 1/32) + (1/4 + 1/16 + 1/32) ) + (1/4 + 1/16 + 1/32)
= ( 1/4 + 1/4 + 1/16 + 1/16 + 1/32 + 1/32 ) + (1/4 + 1/16 + 1/32)
= ( 1/2 + 1/8 + 1/16 ) + (1/4 + 1/16 + 1/32)
= 1/2 + 1/4 + 1/8 + 1/16 + 1/16 + O(1/32)
Run Code Online (Sandbox Code Playgroud)
该O(1/32)
术语无法在结果中表示,因此它被丢弃并且我们得到了
A + A + A = 1/2 + 1/4 + 1/8 + 1/16 + 1/16 = 1
Run Code Online (Sandbox Code Playgroud)
QED :)
Dig*_*oss 17
问题是浮点格式表示基数2中的分数.
第一个分数位是½,第二个分数是1/4,它继续为1/2 n.
和这个问题即是,并非每一个有理数(可以表示成两个整数之比的数)实际上具有在该基部2格式的有限表示.
(这使得浮点格式难以用于货币值.虽然这些值总是有理数(n/100),但只有.00,.25,.50和.75实际上具有任意数字位数的精确表示.基础两部分.)
无论如何,当你添加它们时,系统最终有机会将结果四舍五入到它可以准确表示的数字.
在某些时候,它发现自己将.666 ...数字添加到.333 ...中,就像这样:
00111110 1 .o10101010 10101010 10101011
+ 00111111 0 .10101010 10101010 10101011o
------------------------------------------
00111111 1 (1).0000000 00000000 0000000x # the x isn't in the final result
Run Code Online (Sandbox Code Playgroud)
最左边的位是符号,接下来的8位是指数,剩下的位是分数.在指数和分数之间是一个假定的"1",它始终存在,因此实际上不存储,作为归一化的最左边分数位.我写的零实际上不是单独的位o
.
这里发生了很多事情,每一步,FPU采取了相当英勇的措施来围绕结果.已经保留了两个额外的精度数字(超出了结果中适合的数字),并且FPU在许多情况下知道剩下的最右边位中的任何一个或至少一个是否为1.如果是这样,则该部分的那部分超过0.5(缩放),因此它向上舍入.中间舍入值允许FPU将最右边的位一直传送到整数部分,最后舍入到正确的答案.
这没有发生,因为任何人都增加了0.5; FPU在格式的限制范围内尽力而为.实际上,浮点不是不准确的.这是完全准确的,但我们期望在我们的基数10,有理数世界观中看到的大多数数字不能用格式的基数2分数来表示.事实上,很少有人.