C++ funsafe数学优化,两行上相同的公式,不同的结果

C++ funsafe数学优化,两行上相同的公式,不同的结果,c++,math,gcc,optimization,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

我在循环中有以下代码:

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++;
    }
}
然后在循环中使用它:

    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并在两个位置上对其进行不同的优化


谢谢

在我看来,您似乎比较了浮点数字的机器精度以外的数字(浮点数字为1e-7,双精度数字为1e-16)。这意味着您输出的数字比应该的多。如果以二进制形式输出变量,而不是以数值形式输出,我想它们是相同的。如果你担心1e-7还不够,我建议你使用双打

偶数
x=y;如果(x==y).
不能保证使用这些优化。例如,它可能会将寄存器中的值与内存中的值进行比较,而内存中的值可能精度较低

这可能是造成问题的原因。在一种情况下,可以使用浮点寄存器中的值,而在另一种情况下,寄存器不足,必须将值写入内存,然后再读回。也许
i1
保留在最后一个可用寄存器中,但是
i2
必须进入内存


或者完全是别的什么东西。但这并不意外。

在查看了反汇编之后,funsafe优化似乎确实发生了变化

float i1 = ((values[y]+values[y+1])-values[1])*0.5f;
float i2 = ((values[y+1]+values[y+2])-values[1])*0.5f;
进入:

因为它可以只计算一次
(值[y+1]-值[1])

然后,现在计算y==127的i2和y==128的i1略有不同,fpu舍入使结果不同


将计算作为y的一个单独函数来编写可以解决这个问题。但是,如果编译器决定内联和优化,那么这个问题可能会再次出现。

索引
107
-
110
1
上的
values[]
数组中的值是什么?什么样的循环?如果你需要与其他任何东西相等的东西,不安全不适合你
x==x
可能有效,但我不确定。@stealthjong:values[]包含严格递增的值,增量约为0.01到1.0(没有非常小的值,也没有非常大的值)。这里的值[107到110]约为74,值[1]相当小,约为0.1“不安全的数学”优化称为“不安全”是有原因的。它可能给你更快的代码,但也可能给你“坏”的结果。这就是该功能的本质。不幸的是,虽然足够长,但您的问题没有足够的细节来实际回答编译器所做的工作……一段完整的代码,可以编译并生成一些合理的输出,包括出错所需的值——这样,我(和其他可能更了解此主题的人)可以使用gcc和其他编译器/工具编译和查看生成的代码。为什么不试着用内联编译代码呢?很难准确预测这里会发生什么,而且你可能不能指望将来会有所不同-内联在代码生成阶段很早就发生了,所以其他优化将在内联代码上发生。不,这似乎是因为不安全的数学优化不尊重操作顺序。例如,在三项或三项以上的总和中,他可以根据自己的喜好对部分总和进行分组。在这里,它似乎分组:(值[y+1]-值[1]),并放弃排序和括号,因为他可能会为两个计算行计算一次。不,这里导致问题的两个稍有不同的数字是浮点,它们的最后一个浮点尾数位不同。我不在乎有一个更精确的结果,只在乎对相同的输入值应用相同的数学公式,一点一点地产生相同的数字。这就是不安全优化的意义所在,因为它进行的优化破坏了这一点。
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;