Optimization 优化编译器是否会删除对结果将乘以零的方法的调用?

Optimization 优化编译器是否会删除对结果将乘以零的方法的调用?,optimization,Optimization,假设您有一个计算开销很大的方法,Compute(p),它返回一些浮点值,还有另一个方法,Falloff(p),它返回另一个从零到一的浮点值 如果您计算衰减(p)*compute(p),当衰减(p)返回零时,compute(p)是否仍会运行?或者您是否需要编写一个特殊的案例来防止Compute(p)不必要地运行 理论上,优化编译器可以确定当衰减返回零时忽略计算对程序没有影响。然而,这有点难以测试,因为如果您有计算输出一些调试数据来确定它是否正在运行,编译器将知道不要因为调试信息而忽略它,从而导致某

假设您有一个计算开销很大的方法,
Compute(p)
,它返回一些浮点值,还有另一个方法,
Falloff(p)
,它返回另一个从零到一的浮点值

如果您计算衰减(p)*compute(p),当衰减(p)返回零时,
compute(p)
是否仍会运行?或者您是否需要编写一个特殊的案例来防止Compute(p)不必要地运行

理论上,优化编译器可以确定当衰减返回零时忽略计算对程序没有影响。然而,这有点难以测试,因为如果您有计算输出一些调试数据来确定它是否正在运行,编译器将知道不要因为调试信息而忽略它,从而导致某种薛定谔猫的情况


我知道这个问题的安全解决方案只是添加特殊情况,但我只是好奇。

一般来说,编译器会知道函数调用可能会产生副作用(无限循环、异常等),并且不会对其进行优化。另一方面,有一些东西,如整个程序优化器,可以确定一个函数没有副作用,从而在不使用其返回值时忽略它


请注意,如果您的函数返回IEEE浮点值并将其乘以0,则不能安全地忽略函数调用,除非您可以确定它始终返回实数。如果它可以返回一个
Inf
NaN
,则与0的乘法不是nop,必须执行。

除非在编译时已知该项为0,否则不会优化出任何结果

另外,请注意分支是昂贵的,因此除非
Fallout()
足够频繁地返回0,否则如果进行显式测试,程序将变得较慢,因此最好的答案是“测试它!”

编辑:那么如果
衰减
频繁返回0,它不是有特殊的

if (something) return 0.0f;
??如果是这样,那么一个好主意是从
Falloff()
有条件地调用
Compute()
。 另外,如果
Falloff()
声明为
inline
,则

if (rez = Falloff())
     rez *= Compute();

可以自动做到这一点。

这实际上不是一个找出副作用的问题:毕竟,您可以用至少gcc和clang将函数标记为纯函数(即没有副作用)。这甚至不是编译器编写人员即将添加此优化的情况,但该死的是,他们在最后一刻还记得浮点问题:毕竟,他们甚至没有对整数进行此优化

真正的问题是,大多数编译器不够聪明,无法考虑上下文,因此他们只能有点短视地说“我这里有一个乘法,一般情况下什么样的优化适用于乘法?”因为在程序乘法的情况下,您的优化几乎总是会严重降低性能(比较和分支需要时间,毕竟,它甚至没有列出的要考虑的优化。


既然你可以考虑上下文,你几乎必须手动添加优化。

HMM,±无穷大*0=Na。这有点奇怪,我想它会给零。无论如何,我的函数只返回实数,所以这不是一个问题。Falloff在大多数情况下返回零,这就是我好奇的原因。