编译器是否允许优化浮点常数乘法

vla*_*sch 1 c floating-point compiler-optimization

可疑的代码如下:

float32_t f = someValueFromSomewhere;
f = f * 4;
Run Code Online (Sandbox Code Playgroud)

编译器会优化这个吗?根据C-Standard(如果我理解正确的话),必须将第二个操作数提升为float32_t; 因此,乘法必须使用FPU(或fp仿真)完成.

从理论上讲,只需添加一个立即(可能是溢出检查),就可以在普通硬件寄存器中完成操作.编译器是否允许进行此优化?是否有编译器可以这样做?如果是这样,他们也会认出这个表达

f = f * 4.0f;
Run Code Online (Sandbox Code Playgroud)

这是避免静态代码检查器有关隐式转换的警告所必需的吗?

一些补充:我知道从标准的角度来看两条线都是等价的.但显然编译器可以区分它们.所以问题是在哪个时候允许优化器第一次看到代码(或更好的内部表示).

Pas*_*uoq 6

不,它不起作用

如果原始值不是一个次正规值(包括公共零),不是无穷大或NaN,并且结果没有溢出,则将2加到指数而不是乘以4.0.通常,编译器没有此信息.当编译器确实拥有此信息时,允许进行此转换,这并不意味着它是一个好主意.

在大多数架构中,这不是一个好主意

除非你想到一个特定的执行平台,从中获取f浮点寄存器的值会更便宜,将它移到通用寄存器中,添加一个常量,测试特殊情况(见上文),并且返回到浮点寄存器,您可以假设所有这些步骤都比浮点乘法更昂贵.只有当浮点运算被模拟为一系列位和整数运算时才有意义以这种方式"乘以2"的乘法.

> [编译器]也会识别表达式 f = f * 4.0f;

f * 4相当于f * (float)4并因此相当于f * 4.0f.编译器可以将这些形式中的任何一个转换为它将转换另一个形式的相同代码,并且任何非玩具编译器都知道它们是等效的(例如,作为常量传播优化传递的应用(float)4).

  • 如果我要实现这个优化,我会基于浮点常量形式.减少不同案例的数量简化了优化.浮点情况更为通用 - 考虑乘以0.25 - 无论如何都必须转换为浮点数. (3认同)
  • @vlad_tepesch同样,在chux的注释的情况下,编写`4.0`强制编译器将赋值视为等效于`f =(float)((double)f*4.0);`,再次因为这是"通常的算术"转换"在标准中指定",然后意识到这是等效的.它等同于编译器可能无法实现的细微原因. (2认同)
  • @vlad_tepesch"表达式"`(float)4`在编译时是已知的.编译器**有**处理这样的"表达式"**,因为这是语言的定义方式**.实现编译器的第一条规则是让所有情况都正确,所以任何合理的编译器都会从插入`int`到`float`的转换开始. (2认同)