计算机如何进行浮点运算?

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

查看"每个计算机科学家应该了解浮点算术的内容"一文

  • @Narek:浮点运算是*不简单,如果你打算做任何不平凡的事情,你一定要读这个.我建议你询问有关它的具体问题,而不是问一个广泛的问题. (9认同)
  • @Narek:你需要它来理解这个简单的例子. (9认同)
  • @Alexandre C,现在我不需要整个理论.我只需要了解这个简单的例子. (2认同)

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 :)

  • 但结果恰好是1.0的事实只是运气.它们可以很容易地关闭1或2个LSB,并且他的程序仍然会显示1,因为默认情况下,浮点转换的精度只有6. (2认同)

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分数来表示.事实上,很少有人.