我在循环中有以下代码:
while(true)
{
float i1, i2;
if(y==0)
{
i1 = 0;
}
else
{
//if y==108, this gives 74.821136 (note the two last digits)
i1 = ((values[y]+values[y+1])-values[1])*0.5f;
}
if(y+2==values.size())
{
i2 = values[y+1];
}
else
{
//if y==107, this gives 74.821129 (note the two last digits)
i2 = ((values[y+1]+values[y+2])-values[1])*0.5f;
}
if(i1<=t && t<i2) {
break;
}
else if(t<i1) {
y--;
}
else {
y++;
}
}
此循环针对 y=107、t=74.821133 进行评估
- i1:74.773773,i2:74.821129
对于 y=108:
- i1:74.821136,i2:74.868484
如您所见,y=107 时的 i2 与 y=108 时的 i1 略有不同,但计算这两个值的行是相同的。
我知道 funsafe-math-optimizations 使用代数规则重新组织数学公式,这可能会由于有限的精度而导致数值错误。但在这里,两个等价的公式似乎得到了不同的优化。在此示例中,这会导致无限循环(如该函数所示,对于给定的 float t,i1 <= t < i2 的 y 值)
这是 gcc 4.8.0 的错误行为吗?
如果我创建一个函数:
float getDifValue(y) const { (values[y]+values[y+1])-values[1])*0.5f; }
然后在循环中使用它:
if(y==0)
{
i1 = 0;
}
else
{
i1 = getDifValue(y);
}
if(y+2==values.size())
{
i2 = values[y+1];
}
else
{
i2 = getDifValue(y+1);
}
我能确保 y=107 的 i2 和 y=108 的 i1 会产生相同的结果吗?或者编译器可以内联 getDifValue 并在两个地方进行不同的优化吗?
谢谢
最佳答案
看了反汇编,好像funsafe-optimization确实变了
float i1 = ((values[y]+values[y+1])-values[1])*0.5f;
float i2 = ((values[y+1]+values[y+2])-values[1])*0.5f;
进入:
float i1 = ((values[y+1]-values[1])+values[y])*0.5f;
float i2 = ((values[y+1]-values[1])+values[y+2])*0.5f;
因为它可能只计算一次 (values[y+1]-values[1])
。
然后,y==127 的 i2 和 y==128 的 i1 现在计算略有不同,fpu 舍入使结果不同。
将计算写成一个单独的 y 函数解决了这个问题。但是,如果编译器决定内联和优化,这个问题可能会再次出现,这个问题仍然悬而未决。
关于c++ - funsafe-math-optimizations,两行不同的公式,不同的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25053186/