为了账号安全,请及时绑定邮箱和手机立即绑定

浮点加法和乘法是关联的吗?

/ 猿问

浮点加法和乘法是关联的吗?

C++
倚天杖 2019-10-21 15:20:52

当我添加三个浮点值并将它们与1进行比较时出现问题。


cout << ((0.7 + 0.2 + 0.1)==1)<<endl;     //output is 0

cout << ((0.7 + 0.1 + 0.2)==1)<<endl;     //output is 1

为什么这些价值观会有所不同?


查看完整描述

3 回答

?
慕尼黑的夜晚无繁华

浮点加法不一定是关联的。如果更改添加顺序,则可以更改结果。


关于该主题的标准论文是每位计算机科学家都应了解的浮点算法。它给出以下示例:


另一个灰色区域涉及括号的解释。由于舍入误差,代数的关联定律不一定适用于浮点数。例如,当x = 1e30,y = -1e30和z = 1时,表达式(x + y)+ z的答案与x +(y + z)完全不同(前者为1,后者为0) )。


查看完整回答
反对 回复 2019-10-21
?
红颜莎娜

当前流行的机器和软件可能是:

编译器编码.7为0x1.6666666666666666-1(十六进制数字1.6666666666666乘以2等于-1的幂),.20x1.999999999999ap-3和.10x1.999999999999ap-4。这些数字中的每一个都是浮点可表示的数字,该数字最接近您编写的十进制数字。

请注意,每个十六进制浮点常量的有效位数都恰好有53位(“分数”部分,通常不正确地称为尾数)。有效数字的十六进制数字有一个“ 1”和另外十三个十六进制数字(每个四比特,总共52个,包括“ 1”的53个),这是IEEE-754标准为64位二进制浮点数提供的-点号。

让我们添加的号码.7.2:0x1.6666666666666p-1和0x1.999999999999ap-3。首先,缩放第二个数字的指数以匹配第一个数字。为此,我们将指数乘以4(将“ p-3”更改为“ p-1”),然后将有效数乘以1/4,得出0x0.66666666666668p-1。然后添加0x1.6666666666666p-1和0x0.66666666666668p-1,得到0x1.ccccccccccccc8p-1。请注意,该数字的有效位数超过53位:“ 8”是句点之后的第14位数字。浮点数不能返回这么多位数的结果,因此必须将其舍入为最接近的可表示数字。在这种情况下,有两个相等的数字,即0x1.cccccccccccccccp-1和0x1.ccccccccccccdp-1。出现平局时,使用在有效位数的最低位为零的数字。“ c”是偶数,“ d”是奇数,因此“

接下来,将.1(0x1.999999999999ap-4)的数字添加到该数字。同样,我们缩放以使指数匹配,因此0x1.999999999999ap-4变为0x.33333333333334p-1。然后将其添加到0x1.cccccccccccccp-1,得到0x1.fffffffffffff4p-1。将其四舍五入为53位将得到0x1.fffffffffffffpp-1,这是的最终结果.7+.2+.1

现在考虑.7+.1+.2。对于.7+.1,请添加0x1.6666666666666p-1和0x1.999999999999ap-4。记得后者缩放为0x.33333333333334p-1。那么确切的总和是0x1.99999999999994p-1。将其四舍五入为53位将得到0x1.9999999999999p-1。

然后添加.2(0x1.999999999999ap-3)的数字,该数字缩放为0x0.66666666666666668p-1。确切的总和是0x2.00000000000008p-1。浮点有效数始终按比例缩放以1开头(特殊情况除外:零,无穷大和可表示范围底部的非常小的数字),因此我们将其调整为0x1.00000000000004p0。最后,我们舍入到53位,得到0x1.0000000000000p0。

因此,由于四舍五入时发生的错误,.7+.2+.1返回0x1.fffffffffffffp-1(非常小于1),然后.7+.1+.2返回0x1.0000000000000p0(恰好为1)。


查看完整回答
反对 回复 2019-10-21
?
慕斯卡3215842

在C或C ++中,浮点乘法不相关。


证明:


#include<stdio.h>

#include<time.h>

#include<stdlib.h>

using namespace std;

int main() {

    int counter = 0;

    srand(time(NULL));

    while(counter++ < 10){

        float a = rand() / 100000;

        float b = rand() / 100000;

        float c = rand() / 100000;


        if (a*(b*c) != (a*b)*c){

            printf("Not equal\n");

        }

    }

    printf("DONE");

    return 0;

}

在此程序中,大约30%的时间(a*b)*c不等于a*(b*c)。


查看完整回答
反对 回复 2019-10-21

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信