Is there a standard way to get the nth `nextafter` floating-point value in C++

As far as I know, there is no standard function for this. Boost has you covered though: See boost::math::float_advance. If you're using this for comparing two floats, you probably want boost::math::float_distance instead.


A naive approach could be to multiply by 8 the distance between a value and the next representable float, instead of calling 8 times std::nextafter

double advance_float(double x, int d)
{
    double step = std::copysign((std::nextafter(x, x + d) - x) * d, d);
    return x + step;
}

Here there are some tests, but it's up to you to determine if this is suitable for your use case.

Edit

As noted by Steve Hollash, x may be so big that x + d == d. Daniel Jour suggested to take advantage of frexp (and ldexp), but in the following attempt, I'll use a different approach to determine the direction.

double advance_float(double x, int d)
{
    const double to = std::copysign(std::numeric_limits<double>::infinity(), d);
    const double next = std::nextafter(x, to);
    return x + std::copysign(d * (next - x), d);
}

Note that it assumes that std::numeric_limits<double>::has_infinity == true, otherwise ::lowest() and ::max() must be used.

Those are some results

         x    d             previous                     x                   next
------------------------------------------------------------------------------------------
           1  1     0x1.fffffffffffffp-1                   0x1p+0     0x1.0000000000001p+0
           1  8     0x1.ffffffffffff8p-1                   0x1p+0     0x1.0000000000008p+0
     3.14159  8      0x1.921fb54442d1p+1     0x1.921fb54442d18p+1      0x1.921fb54442d2p+1
      100.01  8     0x1.900a3d70a3d69p+6     0x1.900a3d70a3d71p+6     0x1.900a3d70a3d79p+6
     -100.01  8    -0x1.900a3d70a3d79p+6    -0x1.900a3d70a3d71p+6    -0x1.900a3d70a3d69p+6
       1e+67  8   0x1.7bd29d1c87a11p+222   0x1.7bd29d1c87a19p+222   0x1.7bd29d1c87a21p+222
       1e-59  8    0x1.011c2eaabe7dp-196   0x1.011c2eaabe7d8p-196    0x1.011c2eaabe7ep-196
           0  8 -0x0.0000000000008p-1022                   0x0p+0  0x0.0000000000008p-1022
4.94066e-324  8 -0x0.0000000000007p-1022  0x0.0000000000001p-1022  0x0.0000000000009p-1022