简体   繁体   English

IEEE-754浮点计算,相等和缩小

[英]IEEE-754 floating point computations, equality and narrowing

In the following code, the functions foo1,foo2 and foo3 are intended to be equivalent. 在以下代码中,函数foo1,foo2和foo3旨在等效。 However when run foo3 does not terminate from the loop, is there a reason why this is the case? 但是当运行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;
}

Note: This was compiled using VS2010 with /fp precise in release mode. 注意:这是使用VS2010在发布模式下使用/ fp精确编译的。 Not sure how GCC etc would treat this code, any information would be great. 不确定GCC等如何处理这些代码,任何信息都会很棒。 Could this be an issue where in foo3, the x and x+1 values become NaN somehow? 这可能是一个问题,在foo3中,x和x + 1值以某种方式变为NaN?

What happens is most likely the following. 最有可能发生的事情如下。 On the x86 arch, intermediate calculations can be done with 80 bits of precision (long double is the corresponding C/C++ type). 在x86 arch上,可以使用80位精度完成中间计算(long double是相应的C / C ++类型)。 The compiler uses all 80 bits for the (+1) operation and for the (!=) operation, but truncates the results before storage. 编译器将所有80位用于(+ 1)操作和(!=)操作,但在存储之前截断结果。

So what your compiler really does is this: 那么你的编译器真正做的是:

while ((long double)(x) != ((long double)(x) + (long double)(1))) {
  x = (float)((long double)(x) + (long double)(1));
} 

This is absolutely non-IEEE-conforming and causes endless headaches for everyone, but this is the default for MSVC. 这绝对不符合IEEE标准,并且会给每个人带来无尽的麻烦,但这是MSVC的默认设置。 Use /fp:strict compiler flag to disable this behaviour. 使用/fp:strict编译标志来禁用此行为。

This is my recollection of the problem from about 10 years ago so please forgive me if this is somehow not entirely correct. 这是我对大约10年前问题的回忆所以请原谅我,如果这不完全正确的话。 See this for the official Microsoft documentation . 请参阅此文档以获取Microsoft官方文档

EDIT I was very surprised to learn that g++ by default exhibits exactly the same behaviour (on i386 linux, but not with eg -mfpmath=sse). 编辑我非常惊讶地发现默认情况下g ++表现出完全相同的行为(在i386 linux上,但不是例如-mfpmath = sse)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM