c++ - funsafe-math-optimizations,两行不同的公式,不同的结果

标签 c++ math gcc optimization

我在循环中有以下代码:

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/

相关文章:

c++ - 继承 SFML 中的 Transformable 和 Drawable

c++ - 关于 Boost::Python 和 Boost::Threads 的问题

c++ - 获取错误 : ‘this’ is unavailable for static member functions even when function is not static

math - 重写无限矩阵

string - 如何从位于该字符串中字符排列数量范围内的数字生成唯一字符串?

c - Debian 上没有 stdint.h 文件

c - 初始化线程局部变量

c++ - 在应用程序中包含正确的 C++ redist

javascript - 计算器应用程序浮点运算的解决方案

gcc - 浮点异常在新的 gfortran 版本中发出信号