我在循环中有以下代码:
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
评估该循环对于y = 108:
如您所见,当y = 107时,i2与y = 108时的i1略有不同,而计算这两个值的行是相同的。
据我所知,funsafe-math-optimizations使用代数规则重新组织数学公式,这可能导致由于有限精度导致的数值误差。但在这里,两个等效公式似乎有不同的优化。在这个例子中,导致一个无限循环(因为这个函数看起来,对于给定的浮点数t,y1值为i1&lt; = t&lt; i2)
这是一个错误的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并在两个地方对它进行不同的优化吗?
由于
答案 0 :(得分:2)
即使x=y; if (x==y) ...
也无法保证使用这些优化。例如,它可能会将寄存器中的值与内存中的值进行比较,并且内存中的值可能具有较低的精度。
这可能是导致此问题的原因。在一种情况下,可以使用浮点寄存器中的值,而在另一种情况下,没有足够的寄存器,必须将值写入存储器然后回读。也许i1
保留在最后一个可用的寄存器中,但i2
必须留在内存中。
或者它可能完全不同。但这并不意外。
答案 1 :(得分:2)
在查看反汇编之后,似乎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的单独函数可以解决问题。但是,如果编译器决定内联和优化,问题可能再次出现,那么问题仍然存在。
答案 2 :(得分:-1)
在我看来,你比较浮点数超出机器精度的数字(浮点数为1e-7,双精度为1e-16)。这意味着您输出的数字比您应该多。如果您要以二进制表示形式输出变量而不是数值,我猜它们是相同的。如果你担心1e-7还不够,我建议使用双打。