C中的浮点运算是关联的吗?

加法在数学上保持关联属性:

(a + b) + c = a + (b + c) 

在一般情况下,此属性不适用于浮点数,因为它们表示有限精度的值。

作为优化的一部分,是否允许编译器在从C程序生成机器代码时进行上述替换? 它在C标准中的确切位置在哪里?

不允许编译器执行“优化”,这将导致计算的值不同于根据抽象机器语义计算的值。

5.1.2.3程序执行

[#1]本国际标准中的语义描述描述了抽象机器的行为,其中优化问题无关紧要。

[#3]在抽象机器中,所有表达式都按语义指定进行计算。

[#13]示例5由于精度和范围的限制,浮点表达式的重排通常受到限制。 由于舍入误差,即使在没有溢出和下溢的情况下,实现通常也不能应用加法或乘法的数学关联规则,也不能应用分布规则。

在你的例子中:

 (a + b) + c 

甚至没有括号:

 a + b + c 

我们有

  + / \ + c / \ ab 

并且编译器需要生成代码,好像ab相加,结果与c相加。

C中的浮点乘法不是关联的。

 In C, Floating point multiplication is not associative. 

一些证据是这个C代码:

选择三个随机浮点值。
检查a*(b*c)是否不等于(a*b)*c

 #include #include #include 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; } 

程序打印:

 Not equal Not equal Not equal Not equal DONE RUN FINISHED; exit value 0; real time: 10ms; user: 0ms; system: 0ms 

结论:

对于我的测试,三个随机选择的浮点乘法值在大约70%的时间内是关联的。

您可以将浮点运算与gcc选项关联起来:

-funsafe-math-optimizations -O2

示例:double test(double a,double b,double c){
return(a + b + c)*(a +(b + c)); }

这减少到:double temp = a +(b + c); return temp * temp;

类似地,(a + b + c) – (a +(b + c))减少到零,忽略了INF和NAN的可能性。

如果我用-fassociative-math -O2编译,我得到一个奇怪的消息:“警告:-fassociative-math disabled;其他选项优先”。

如果您不关心操作数的顺序,-funsafe-math-optimizations可以提高速度,但如果操作数的顺序很重要,它可能会导致精度损失,并且您可能会丢失NAN和INF结果。