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

zr.*_*zr. 22 c math floating-point compiler-optimization

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

(a + b) + c = a + (b + c)
Run Code Online (Sandbox Code Playgroud)

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

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

chi*_*ill 14

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

5.1.2.3程序执行

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

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

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

在你的例子中:

(a + b) + c
Run Code Online (Sandbox Code Playgroud)

甚至没有括号:

a + b + c
Run Code Online (Sandbox Code Playgroud)

我们有

   +
  / \
  +  c
 / \
 a  b
Run Code Online (Sandbox Code Playgroud)

并且编译器需要生成代码,就像a总结一样,b结果与之相加c.

  • 但请注意,虽然运算符优先级已明确定义,但子表达式的求值顺序并未指定。换句话说,程序可以从右到左或从左到右开始评估这个二叉树,它甚至不需要以一致的方式保持这个顺序,也不需要记录它。因此,如果 a、b 或 c 包含影响结果的副作用,那么代码就会有问题。比如说c是一个修改a的函数:那么我们就无法知道结果。 (2认同)

A F*_*Fog 6

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

-funsafe-math-optimizations -O2
Run Code Online (Sandbox Code Playgroud)

例:

double test (double a, double b, double c) {    
  return (a + b + c) * (a + (b + c));
}
Run Code Online (Sandbox Code Playgroud)

减少为:

double temp = a + (b + c);
return temp * temp;
Run Code Online (Sandbox Code Playgroud)

类似地,(a + b + c) - (a + (b + c))减小到零,而忽略的可能性INFNAN

如果我-fassociative-math -O2改为使用它,则会收到奇怪的消息:

警告:-fassociative-math已禁用;其他选项优先

-funsafe-math-optimizations能提高速度,如果你不关心操作数的顺序无论如何,但它可能会导致精度损失,如果操作数的顺序是非常重要的,你可能会失去NANINF结果。