C++ next float with numeric_limits / epsilon?

落爺英雄遲暮 提交于 2019-12-10 16:59:40

问题


Consider a "normal" real number TREAL x in C++ (not subnormal and not NaN/Infinite) (TREAL = float, double, long double)
Is the following the good solution to find the previous and next x from a floating-point point of view ?

TREAL xprev = (((TREAL)(1.)) - std::numeric_limits<TREAL>::epsilon()) * x;
TREAL xnext = (((TREAL)(1.)) + std::numeric_limits<TREAL>::epsilon()) * x;

Thank you very much.


回答1:


C99 and C++11 have nextafter, nextafterl and nextafterf functions in <math.h> and <cmath>. Implementing them with basic arithmetic and epsilon would be tedious as you'd need to take rounding into account. Working on the binary representation is probably easier, but I wonder about the effect of the sign and magnitude representation and the existence of -0.0 (see Fred's answer for what is needed).




回答2:


Getting the next floating point number is a lot easier on the binary level:

float next(float f)
{
    unsigned x;
    memcpy(&x, &f, 4);
    ++x;
    memcpy(&f, &x, 4);
    return f;
}

Of course this will only work for systems where floating point numbers are stored "in ascending order", which happens to be the case for IEEE754.

Negative numbers will go towards negative infinity. Want them to go to zero instead? Use this:

float next(float f)
{
    int x;
    memcpy(&x, &f, 4);
    x += x >> 31 | 1;   // this will add 1 for positive f and -1 for negative f
    memcpy(&f, &x, 4);
    return f;
}



回答3:


No, the ratio between "consecutive" floating point values is not uniform; this approach may miss some out, or leave you stuck at a point where xnext == x.

To move from one value to the next-largest value, you'd have to:

  • extract the mantissa and exponent;
  • increment the mantissa;
  • if that overflows, reset it and increment the exponent;
  • reconstruct the value from the exponent and mantissa.

The details are quite fiddly, and will probably require some knowledge of the floating point representation.

However, assuming a representation similar to IEEE, you could achieve this by reinterpreting the bit pattern as a large enough integer, and incrementing that integer. That will increment the mantissa, with any overflow going into the exponent, just as we want.




回答4:


The following nextFloat function gives the correct result for all floats of at least minV (that is, floats for which the intermediate values in nextFloat stay out of the denormal range). I tested it for all floats starting at minV, up to FLT_MAX and the result was always equal to the result of nextFloatRef.

float nextFloatRef(float v)
{
    uint32_t vBits = reinterpret_cast<uint32_t&>(v);
    vBits++;
    return reinterpret_cast<float&>(vBits);
}

float nextFloat(float v)
{
    return v + v * nextFloatRef(FLT_EPSILON / 2);
}

float minV = FLT_MIN / (FLT_EPSILON / 2);

nextFloatRef(FLT_EPSILON / 2) is a constant so can be precomputed.



来源:https://stackoverflow.com/questions/11159774/c-next-float-with-numeric-limits-epsilon

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!