如何循环浮点数的精确表示?

时间:2014-12-06 08:50:28

标签: c++ loops ieee-754

我试图从一个浮点数到下一个完全循环。比如,我需要从std::numeric_limits<float>::epsilon()循环到1,它们都是可以代表的IEEE754数字。我的代码是:

 using nld = std::numeric_limits<float>;
 auto h = nld::epsilon();
 for (; h < 1; h = std::nextafter(h, 1)) {
     std::cerr << "h: " << h << std::endl;
 }

无限循环,因为h是完全可表示的,所以nextafter会一直返回它。我也知道在循环中将机器epsilon添加到h不会削减它:浮点数不是等间隔的。如何循环IEEE754数字的确切表示?

not equally spaced问题出现在这里:

 using nld = std::numeric_limits<float>;
 auto h = nld::epsilon();
 for (; h < 4; h += nld::epsilon()) {
     if (h = h + nld::epsilon()) {
         std::cerr << "h: " << h << std::endl;
     }
 }

为我保留打印2

2 个答案:

答案 0 :(得分:2)

根据评论:

使用nextafter的方法正是您应该做的。但是,它有一些可能导致意外结果的并发症。

引用cppreference std::nextafter

  

float nextafter( float from, float to );(1)(自C ++ 11起)
  double nextafter( double from, double to );(2)(自C ++ 11起)
  long double nextafter( long double from, long double to );(3)(自C ++ 11起)
  Promoted nextafter( Arithmetic from, Arithmetic to );(4)(自C ++ 11起)

     

...

     

4)(1-3)未涵盖的算术类型的所有参数组合的一组重载或函数模板。如果任何参数具有整数类型,则将其强制转换为double。如果任何参数为long double,则返回类型Promoted也为long double,否则返回类型始终为double

由于您的to1,类型为int,因此您将获得重载版本4,其返回类型为double。现在,完全有可能给定一个浮点f(float)nextafter((double)f, 1)与原始f完全相同:它很可能是类型中的下一个可表示数字无法在double中表示float,并且转换回float的结果将向下舍入。

返回float的唯一重载是to类型为float的重载。要使用该重载,请使用1.0f代替1

答案 1 :(得分:0)

将它们视为整数将适用于正常的正浮标, 负浮点数将走错方向,非正规数和零点可能是一个特例。

例如:对于正常正常浮标:

float nextfloat(float in)
{   
   union { float f; uint32_t i; } a;
   a.f=in;
   a.i++;
   return(a.f);
}

这依赖于具有与整数相同的字节序和大小的浮点数,这里我对float和uint32_t配对,但你可以对double和uint64_t做同样的事情......这实际上可能是一类未定义的行为,测试它的操作可能应该是构建过程的一部分。