[英]IEEE-754 floating point computations, equality and narrowing
在以下代码中,函数foo1,foo2和foo3旨在等效。 但是当运行foo3没有从循环终止时,是否有这种情况的原因?
template <typename T>
T foo1()
{
T x = T(1);
T y = T(0);
for (;;)
{
if (x == y) break;
y = x;
++x;
}
return x;
}
template <typename T>
T foo2()
{
T x = T(0);
for (;;)
{
T y = x + T(1);
if (!(x != y)) break;
++x;
}
return x;
}
template <typename T>
T foo3()
{
T x = T(0);
while (x != (x + T(1))) ++x;
return x;
}
int main()
{
printf("1 float: %20.5f\n", foo1<float>());
printf("2 float: %20.5f\n", foo2<float>());
printf("3 float: %20.5f\n", foo3<float>());
return 0;
}
注意:这是使用VS2010在发布模式下使用/ fp精确编译的。 不确定GCC等如何处理这些代码,任何信息都会很棒。 这可能是一个问题,在foo3中,x和x + 1值以某种方式变为NaN?
最有可能发生的事情如下。 在x86 arch上,可以使用80位精度完成中间计算(long double是相应的C / C ++类型)。 编译器将所有80位用于(+ 1)操作和(!=)操作,但在存储之前截断结果。
那么你的编译器真正做的是:
while ((long double)(x) != ((long double)(x) + (long double)(1))) {
x = (float)((long double)(x) + (long double)(1));
}
这绝对不符合IEEE标准,并且会给每个人带来无尽的麻烦,但这是MSVC的默认设置。 使用/fp:strict
编译标志来禁用此行为。
这是我对大约10年前问题的回忆所以请原谅我,如果这不完全正确的话。 请参阅此文档以获取Microsoft官方文档 。
编辑我非常惊讶地发现默认情况下g ++表现出完全相同的行为(在i386 linux上,但不是例如-mfpmath = sse)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.