Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/numeric/math/nextafter"

From cppreference.com
< cpp‎ | numeric‎ | math
m (Notes: fmt; Example: +std::, +precision loss demo for big fp numbers using std::nextafter.)
m (., http -> https)
 
(8 intermediate revisions by 2 users not shown)
Line 2: Line 2:
 
{{cpp/numeric/math/navbar}}
 
{{cpp/numeric/math/navbar}}
 
{{dcl begin}}
 
{{dcl begin}}
{{dcl header | cmath}}
+
{{dcl header|cmath}}
{{dcl | since=c++11 | num=1|
+
{{dcl rev multi|num=1|since1=c++11|dcl1=
 
float      nextafter ( float from, float to );
 
float      nextafter ( float from, float to );
 +
double      nextafter ( double from, double to );
 +
long double nextafter ( long double from, long double to );
 +
|since2=c++23|dcl2=
 +
constexpr /* floating-point-type */
 +
            nextafter ( /* floating-point-type */ from,
 +
                        /* floating-point-type */ to );
 +
}}
 +
{{dcl|num=2|since=c++11|notes={{mark|constexpr since C++23}}|
 
float      nextafterf( float from, float to );
 
float      nextafterf( float from, float to );
 
}}
 
}}
{{dcl | since=c++11 | num=2|
+
{{dcl|num=3|since=c++11|notes={{mark|constexpr since C++23}}|
double      nextafter ( double from, double to );
+
}}
+
{{dcl | since=c++11 | num=3|
+
long double nextafter ( long double from, long double to );
+
 
long double nextafterl( long double from, long double to );
 
long double nextafterl( long double from, long double to );
 
}}
 
}}
{{dcl | since=c++11 | num=4|
+
{{dcl rev multi|num=4|since1=c++11|dcl1=
Promoted    nextafter ( Arithmetic1 from, Arithmetic2 to );
+
float      nexttoward ( float from, long double to );
 +
double      nexttoward ( double from, long double to );
 +
long double nexttoward ( long double from, long double to );
 +
|since2=c++23|dcl2=
 +
constexpr /* floating-point-type */
 +
            nexttoward ( /* floating-point-type */ from,
 +
                        long double to );
 
}}
 
}}
{{dcl | since=c++11 | num=5|
+
{{dcl|num=5|since=c++11|notes={{mark|constexpr since C++23}}|
float      nexttoward ( float from, long double to );
+
 
float      nexttowardf( float from, long double to );
 
float      nexttowardf( float from, long double to );
 
}}
 
}}
{{dcl | since=c++11 | num=6|
+
{{dcl|num=6|since=c++11|notes={{mark|constexpr since C++23}}|
double      nexttoward ( double from, long double to );
+
}}
+
{{dcl | since=c++11 | num=7|
+
long double nexttoward ( long double from, long double to );
+
 
long double nexttowardl( long double from, long double to );
 
long double nexttowardl( long double from, long double to );
 
}}
 
}}
{{dcl | since=c++11 | num=8|
+
{{dcl h|[[#Notes|Additional overloads]]}}
double     nexttoward ( IntegralType from, long double to );
+
{{dcl header|cmath}}
 +
{{dcl|num=A|since=c++11|notes={{mark|constexpr since C++23}}|
 +
template< class Arithmetic1, class Arithmetic2 >
 +
/* common-floating-point-type */
 +
    nextafter( Arithmetic1 from, Arithmetic2 to );
 +
}}
 +
{{dcl|num=B|since=c++11|notes={{mark|constexpr since C++23}}|
 +
template< class Integer >
 +
double nexttoward( Integer from, long double to );
 
}}
 
}}
 
{{dcl end}}
 
{{dcl end}}
  
Returns the next representable value of {{tt|from}} in the direction of {{tt|to}}.
+
Returns the next representable value of {{c|from}} in the direction of {{c|to}}.
  
@1-3@ If {{tt|from}} equals {{tt|to}}, {{tt|to}} is returned.
+
@1-3@ If {{c|from}} equals {{c|to}}, {{c|to}} is returned.{{rev inl|since=c++23| The library provides overloads of {{tt|std::nextafter}} for all cv-unqualified floating-point types as the type of the parameters {{c|from}} and {{c|to}}.}}
@5-7@ If {{tt|from}} equals {{tt|to}}, {{tt|to}} is returned, converted from {{c|long double}} to the return type of the function without loss of range or precision.
+
@4-6@ If {{c|from}} equals {{c|to}}, {{c|to}} is returned, converted from {{c/core|long double}} to the return type of the function without loss of range or precision.
@4@ A set of overloads or a function template for all combinations of arguments of arithmetic type not covered by {{v|1-3}}. If any argument has [[cpp/types/is_integral|integral type]], it is cast to {{c|double}}. If any argument is {{c|long double}}, then the return type {{tt|Promoted}} is also {{c|long double}}, otherwise the return type is always {{c|double}}.
+
{{rrev|since=c++23|The library provides overloads of {{tt|std::nexttoward}} for all cv-unqualified floating-point types as the type of the parameter {{c|from}}. However, an invocation of {{tt|std::nexttoward}} is ill-formed if the argument corresponding to {{c|from}} has [[cpp/language/types#Extended floating-point types|extended floating-point type]], because the next representable value (or {{c|to}}) is not guaranteed to be representable as {{c/core|long double}}.
@8@ A set of overloads or a function template accepting the {{tt|from}} argument of any [[cpp/types/is_integral|integral type]]. Equivalent to {{v|6}} (the argument is cast to {{c|double}}).
+
}}
 +
@A@ Additional {{tt|std::nextafter}} overloads are provided for all other combinations of arithmetic types.
 +
@B@ Additional {{tt|std::nexttoward}} overloads are provided for all integer types, which are treated as {{c/core|double}}.
  
 
===Parameters===
 
===Parameters===
 
{{par begin}}
 
{{par begin}}
{{par | from, to | floating point values}}
+
{{par|from, to|floating-point or integer values}}
 
{{par end}}
 
{{par end}}
  
 
===Return value===
 
===Return value===
If no errors occur, the next representable value of {{tt|from}} in the direction of {{tt|to}}. is returned. If {{tt|from}} equals {{tt|to}}, then {{tt|to}} is returned.
+
If no errors occur, the next representable value of {{c|from}} in the direction of {{c|to}}. is returned. If {{c|from}} equals {{c|to}}, then {{c|to}} is returned.
  
If a range error due to overflow occurs, {{tt|±HUGE_VAL}}, {{tt|±HUGE_VALF}}, or {{tt|±HUGE_VALL}} is returned (with the same sign as {{tt|from}})
+
If a range error due to overflow occurs, {{lc|HUGE_VAL|±HUGE_VAL}}, {{tt|±HUGE_VALF}}, or {{tt|±HUGE_VALL}} is returned (with the same sign as {{c|from}}).
  
 
If a range error occurs due to underflow, the correct result is returned.
 
If a range error occurs due to underflow, the correct result is returned.
Line 56: Line 71:
  
 
If the implementation supports IEEE floating-point arithmetic (IEC 60559),
 
If the implementation supports IEEE floating-point arithmetic (IEC 60559),
* if {{tt|from}} is finite, but the expected result is an infinity, raises {{lc|FE_INEXACT}} and {{lc|FE_OVERFLOW}}
+
* if {{c|from}} is finite, but the expected result is an infinity, raises {{lc|FE_INEXACT}} and {{lc|FE_OVERFLOW}}.
* if {{tt|from}} does not equal {{tt|to}} and the result is subnormal or zero, raises {{lc|FE_INEXACT}} and {{lc|FE_UNDERFLOW}}
+
* if {{c|from}} does not equal {{c|to}} and the result is subnormal or zero, raises {{lc|FE_INEXACT}} and {{lc|FE_UNDERFLOW}}.
* in any case, the returned value is independent of the current rounding mode
+
* in any case, the returned value is independent of the current rounding mode.
* if either {{tt|from}} or {{tt|to}} is NaN, NaN is returned
+
* if either {{c|from}} or {{c|to}} is NaN, NaN is returned.
  
 
===Notes===
 
===Notes===
[http://pubs.opengroup.org/onlinepubs/9699919799/functions/nextafter.html POSIX specifies] that the overflow and the underflow conditions are range errors (errno may be set)
+
[https://pubs.opengroup.org/onlinepubs/9699919799/functions/nextafter.html POSIX specifies] that the overflow and the underflow conditions are range errors ({{lc|errno}} may be set).
  
IEC 60559 recommends that {{tt|from}} is returned whenever {{tt|from{{==}}to}}. These functions return {{tt|to}} instead, which makes the behavior around zero consistent: {{tt|std::nextafter(-0.0, +0.0)}} returns {{c|+0.0}} and {{tt|std::nextafter(+0.0, -0.0)}} returns {{c|-0.0}}.
+
IEC 60559 recommends that {{c|from}} is returned whenever {{c|1= from == to}}. These functions return {{c|to}} instead, which makes the behavior around zero consistent: {{c|std::nextafter(-0.0, +0.0)}} returns {{c|+0.0}} and {{c|std::nextafter(+0.0, -0.0)}} returns {{c|-0.0}}.
  
{{tt|nextafter}} is typically implemented by manipulation of IEEE representation ([https://github.com/bminor/glibc/blob/master/math/s_nextafter.c glibc] [https://github.com/ifduyue/musl/blob/master/src/math/nextafter.c musl])
+
{{tt|std::nextafter}} is typically implemented by manipulation of IEEE representation ([https://github.com/bminor/glibc/blob/master/math/s_nextafter.c glibc], [https://github.com/ifduyue/musl/blob/master/src/math/nextafter.c musl]).
 +
 
 +
{{cpp/numeric/math/additional overload note|nextafter}}
 +
 
 +
{{cpp/numeric/math/additional integer overload note|nexttoward}}
  
 
===Example===
 
===Example===
{{example|
+
{{example
| code=
+
|code=
 
#include <cfenv>
 
#include <cfenv>
 
#include <cfloat>
 
#include <cfloat>
Line 84: Line 103:
 
               << " is " << to1
 
               << " is " << to1
 
               << std::hexfloat << " (" << to1 << ")\n" << std::defaultfloat;
 
               << std::hexfloat << " (" << to1 << ")\n" << std::defaultfloat;
 
+
   
 
     float from2 = 1, to2 = std::nextafter(from2, 2.f);
 
     float from2 = 1, to2 = std::nextafter(from2, 2.f);
 
     std::cout << "The next representable float after " << from2 << " is " << to2
 
     std::cout << "The next representable float after " << from2 << " is " << to2
 
               << std::hexfloat << " (" << to2 << ")\n" << std::defaultfloat;
 
               << std::hexfloat << " (" << to2 << ")\n" << std::defaultfloat;
 
+
   
 
     double from3 = std::nextafter(0.1, 0), to3 = 0.1;
 
     double from3 = std::nextafter(0.1, 0), to3 = 0.1;
 
     std::cout << "The number 0.1 lies between two valid doubles:\n"
 
     std::cout << "The number 0.1 lies between two valid doubles:\n"
Line 95: Line 114:
 
               << "\nand " << to3 << std::hexfloat << "  (" << to3 << ")\n"
 
               << "\nand " << to3 << std::hexfloat << "  (" << to3 << ")\n"
 
               << std::defaultfloat << std::setprecision(20);
 
               << std::defaultfloat << std::setprecision(20);
 
+
   
 
     std::cout << "\nDifference between nextafter and nexttoward:\n";
 
     std::cout << "\nDifference between nextafter and nexttoward:\n";
 
     long double dir = std::nextafter(from1, 1.0L); // first subnormal long double
 
     long double dir = std::nextafter(from1, 1.0L); // first subnormal long double
Line 102: Line 121:
 
     x = std::nexttoward(from1, dir);
 
     x = std::nexttoward(from1, dir);
 
     std::cout << "With nexttoward, next float after " << from1 << " is " << x << '\n';
 
     std::cout << "With nexttoward, next float after " << from1 << " is " << x << '\n';
 
+
   
 
     std::cout << "\nSpecial values:\n";
 
     std::cout << "\nSpecial values:\n";
 
     {
 
     {
Line 112: Line 131:
 
                   << std::defaultfloat << " is " << to4
 
                   << std::defaultfloat << " is " << to4
 
                   << std::hexfloat << " (" << to4 << ")\n" << std::defaultfloat;
 
                   << std::hexfloat << " (" << to4 << ")\n" << std::defaultfloat;
         if(std::fetestexcept(FE_OVERFLOW)) std::cout << "  raised FE_OVERFLOW\n";
+
       
         if(std::fetestexcept(FE_INEXACT)) std::cout << "  raised FE_INEXACT\n";
+
         if (std::fetestexcept(FE_OVERFLOW))
 +
            std::cout << "  raised FE_OVERFLOW\n";
 +
         if (std::fetestexcept(FE_INEXACT))
 +
            std::cout << "  raised FE_INEXACT\n";
 
     } // end FENV_ACCESS block
 
     } // end FENV_ACCESS block
 
+
   
 
     float from5 = 0.0, to5 = std::nextafter(from5, -0.0);
 
     float from5 = 0.0, to5 = std::nextafter(from5, -0.0);
 
     std::cout << "std::nextafter(+0.0, -0.0) gives " << std::fixed << to5 << '\n';
 
     std::cout << "std::nextafter(+0.0, -0.0) gives " << std::fixed << to5 << '\n';
 
+
   
     auto precision_loss_demo = []<std::floating_point Fp>(const auto rem, const Fp start) {
+
     auto precision_loss_demo = []<std::floating_point Fp>(const auto rem, const Fp start)
 +
    {
 
         std::cout << rem;
 
         std::cout << rem;
 
         for (Fp from = start, to, Δ;
 
         for (Fp from = start, to, Δ;
 
             (Δ = (to = std::nextafter(from, +INFINITY)) - from) < Fp(10.0);
 
             (Δ = (to = std::nextafter(from, +INFINITY)) - from) < Fp(10.0);
 
             from *= Fp(10.0))
 
             from *= Fp(10.0))
             std::cout << "nextafter(" << from << ", INF) gives " << to
+
             std::cout << "nextafter(" << std::scientific << std::setprecision(0) << from  
 +
                      << ", INF) gives " << std::fixed << std::setprecision(6) << to
 
                       << "; Δ = " << Δ << '\n';
 
                       << "; Δ = " << Δ << '\n';
 
     };
 
     };
 
+
   
 
     precision_loss_demo("\nPrecision loss demo for float:\n", 10.0f);
 
     precision_loss_demo("\nPrecision loss demo for float:\n", 10.0f);
 
     precision_loss_demo("\nPrecision loss demo for double:\n", 10.0e9);
 
     precision_loss_demo("\nPrecision loss demo for double:\n", 10.0e9);
 +
    precision_loss_demo("\nPrecision loss demo for long double:\n", 10.0e17L);
 
}
 
}
| output=
+
|output=
 
The next representable float after 0 is 1.4012984643248170709e-45 (0x1p-149)
 
The next representable float after 0 is 1.4012984643248170709e-45 (0x1p-149)
 
The next representable float after 1 is 1.0000001192092895508 (0x1.000002p+0)
 
The next representable float after 1 is 1.0000001192092895508 (0x1.000002p+0)
Line 149: Line 174:
  
 
Precision loss demo for float:
 
Precision loss demo for float:
nextafter(10.000000, INF) gives 10.000001; Δ = 0.000001
+
nextafter(1e+01, INF) gives 10.000001; Δ = 0.000001
nextafter(100.000000, INF) gives 100.000008; Δ = 0.000008
+
nextafter(1e+02, INF) gives 100.000008; Δ = 0.000008
nextafter(1000.000000, INF) gives 1000.000061; Δ = 0.000061
+
nextafter(1e+03, INF) gives 1000.000061; Δ = 0.000061
nextafter(10000.000000, INF) gives 10000.000977; Δ = 0.000977
+
nextafter(1e+04, INF) gives 10000.000977; Δ = 0.000977
nextafter(100000.000000, INF) gives 100000.007812; Δ = 0.007812
+
nextafter(1e+05, INF) gives 100000.007812; Δ = 0.007812
nextafter(1000000.000000, INF) gives 1000000.062500; Δ = 0.062500
+
nextafter(1e+06, INF) gives 1000000.062500; Δ = 0.062500
nextafter(10000000.000000, INF) gives 10000001.000000; Δ = 1.000000
+
nextafter(1e+07, INF) gives 10000001.000000; Δ = 1.000000
nextafter(100000000.000000, INF) gives 100000008.000000; Δ = 8.000000
+
nextafter(1e+08, INF) gives 100000008.000000; Δ = 8.000000
  
 
Precision loss demo for double:
 
Precision loss demo for double:
nextafter(10000000000.000000, INF) gives 10000000000.000002; Δ = 0.000002
+
nextafter(1e+10, INF) gives 10000000000.000002; Δ = 0.000002
nextafter(100000000000.000000, INF) gives 100000000000.000015; Δ = 0.000015
+
nextafter(1e+11, INF) gives 100000000000.000015; Δ = 0.000015
nextafter(1000000000000.000000, INF) gives 1000000000000.000122; Δ = 0.000122
+
nextafter(1e+12, INF) gives 1000000000000.000122; Δ = 0.000122
nextafter(10000000000000.000000, INF) gives 10000000000000.001953; Δ = 0.001953
+
nextafter(1e+13, INF) gives 10000000000000.001953; Δ = 0.001953
nextafter(100000000000000.000000, INF) gives 100000000000000.015625; Δ = 0.015625
+
nextafter(1e+14, INF) gives 100000000000000.015625; Δ = 0.015625
nextafter(1000000000000000.000000, INF) gives 1000000000000000.125000; Δ = 0.125000
+
nextafter(1e+15, INF) gives 1000000000000000.125000; Δ = 0.125000
nextafter(10000000000000000.000000, INF) gives 10000000000000002.000000; Δ = 2.000000
+
nextafter(1e+16, INF) gives 10000000000000002.000000; Δ = 2.000000
 +
 
 +
Precision loss demo for long double:
 +
nextafter(1e+18, INF) gives 1000000000000000000.062500; Δ = 0.062500
 +
nextafter(1e+19, INF) gives 10000000000000000001.000000; Δ = 1.000000
 +
nextafter(1e+20, INF) gives 100000000000000000008.000000; Δ = 8.000000
 
}}
 
}}
  
 
===See also===
 
===See also===
 
{{dsc begin}}
 
{{dsc begin}}
{{dsc see c | c/numeric/math/nextafter}}
+
{{dsc see c|c/numeric/math/nextafter}}
 
{{dsc end}}
 
{{dsc end}}
  
 
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}
 
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}

Latest revision as of 22:57, 14 September 2023

 
 
 
 
Defined in header <cmath>
(1)
float       nextafter ( float from, float to );

double      nextafter ( double from, double to );

long double nextafter ( long double from, long double to );
(since C++11)
(until C++23)
constexpr /* floating-point-type */

            nextafter ( /* floating-point-type */ from,

                        /* floating-point-type */ to );
(since C++23)
float       nextafterf( float from, float to );
(2) (since C++11)
(constexpr since C++23)
long double nextafterl( long double from, long double to );
(3) (since C++11)
(constexpr since C++23)
(4)
float       nexttoward ( float from, long double to );

double      nexttoward ( double from, long double to );

long double nexttoward ( long double from, long double to );
(since C++11)
(until C++23)
constexpr /* floating-point-type */

            nexttoward ( /* floating-point-type */ from,

                         long double to );
(since C++23)
float       nexttowardf( float from, long double to );
(5) (since C++11)
(constexpr since C++23)
long double nexttowardl( long double from, long double to );
(6) (since C++11)
(constexpr since C++23)
Defined in header <cmath>
template< class Arithmetic1, class Arithmetic2 >

/* common-floating-point-type */

    nextafter( Arithmetic1 from, Arithmetic2 to );
(A) (since C++11)
(constexpr since C++23)
template< class Integer >
double nexttoward( Integer from, long double to );
(B) (since C++11)
(constexpr since C++23)

Returns the next representable value of from in the direction of to.

1-3) If from equals to, to is returned. The library provides overloads of std::nextafter for all cv-unqualified floating-point types as the type of the parameters from and to.(since C++23)
4-6) If from equals to, to is returned, converted from long double to the return type of the function without loss of range or precision.

The library provides overloads of std::nexttoward for all cv-unqualified floating-point types as the type of the parameter from. However, an invocation of std::nexttoward is ill-formed if the argument corresponding to from has extended floating-point type, because the next representable value (or to) is not guaranteed to be representable as long double.

(since C++23)
A) Additional std::nextafter overloads are provided for all other combinations of arithmetic types.
B) Additional std::nexttoward overloads are provided for all integer types, which are treated as double.

Contents

[edit] Parameters

from, to - floating-point or integer values

[edit] Return value

If no errors occur, the next representable value of from in the direction of to. is returned. If from equals to, then to is returned.

If a range error due to overflow occurs, ±HUGE_VAL, ±HUGE_VALF, or ±HUGE_VALL is returned (with the same sign as from).

If a range error occurs due to underflow, the correct result is returned.

[edit] Error handling

Errors are reported as specified in math_errhandling.

If the implementation supports IEEE floating-point arithmetic (IEC 60559),

  • if from is finite, but the expected result is an infinity, raises FE_INEXACT and FE_OVERFLOW.
  • if from does not equal to and the result is subnormal or zero, raises FE_INEXACT and FE_UNDERFLOW.
  • in any case, the returned value is independent of the current rounding mode.
  • if either from or to is NaN, NaN is returned.

[edit] Notes

POSIX specifies that the overflow and the underflow conditions are range errors (errno may be set).

IEC 60559 recommends that from is returned whenever from == to. These functions return to instead, which makes the behavior around zero consistent: std::nextafter(-0.0, +0.0) returns +0.0 and std::nextafter(+0.0, -0.0) returns -0.0.

std::nextafter is typically implemented by manipulation of IEEE representation (glibc, musl).

The additional std::nextafter overloads are not required to be provided exactly as (A). They only need to be sufficient to ensure that for their first argument num1 and second argument num2:

  • If num1 or num2 has type long double, then std::nextafter(num1, num2) has the same effect as std::nextafter(static_cast<long double>(num1),
                   static_cast<long double>(num2))
    .
  • Otherwise, if num1 and/or num2 has type double or an integer type, then std::nextafter(num1, num2) has the same effect as std::nextafter(static_cast<double>(num1),
                   static_cast<double>(num2))
    .
  • Otherwise, if num1 or num2 has type float, then std::nextafter(num1, num2) has the same effect as std::nextafter(static_cast<float>(num1),
                   static_cast<float>(num2))
    .
(until C++23)

If num1 and num2 have arithmetic types, then std::nextafter(num1, num2) has the same effect as std::nextafter(static_cast</* common-floating-point-type */>(num1),
               static_cast</* common-floating-point-type */>(num2))
, where /* common-floating-point-type */ is the floating-point type with the greatest floating-point conversion rank and greatest floating-point conversion subrank between the types of num1 and num2, arguments of integer type are considered to have the same floating-point conversion rank as double.

If no such floating-point type with the greatest rank and subrank exists, then overload resolution does not result in a usable candidate from the overloads provided.

(since C++23)

The additional std::nexttoward overloads are not required to be provided exactly as (B). They only need to be sufficient to ensure that for their argument num of integer type, std::nexttoward(num) has the same effect as std::nexttoward(static_cast<double>(num)).

[edit] Example

#include <cfenv>
#include <cfloat>
#include <cmath>
#include <concepts>
#include <iomanip>
#include <iostream>
 
int main()
{
    float from1 = 0, to1 = std::nextafter(from1, 1.f);
    std::cout << "The next representable float after " << std::setprecision(20) << from1
              << " is " << to1
              << std::hexfloat << " (" << to1 << ")\n" << std::defaultfloat;
 
    float from2 = 1, to2 = std::nextafter(from2, 2.f);
    std::cout << "The next representable float after " << from2 << " is " << to2
              << std::hexfloat << " (" << to2 << ")\n" << std::defaultfloat;
 
    double from3 = std::nextafter(0.1, 0), to3 = 0.1;
    std::cout << "The number 0.1 lies between two valid doubles:\n"
              << std::setprecision(56) << "    " << from3
              << std::hexfloat << " (" << from3 << ')' << std::defaultfloat
              << "\nand " << to3 << std::hexfloat << "  (" << to3 << ")\n"
              << std::defaultfloat << std::setprecision(20);
 
    std::cout << "\nDifference between nextafter and nexttoward:\n";
    long double dir = std::nextafter(from1, 1.0L); // first subnormal long double
    float x = std::nextafter(from1, dir); // first converts dir to float, giving 0
    std::cout << "With nextafter, next float after " << from1 << " is " << x << '\n';
    x = std::nexttoward(from1, dir);
    std::cout << "With nexttoward, next float after " << from1 << " is " << x << '\n';
 
    std::cout << "\nSpecial values:\n";
    {
        // #pragma STDC FENV_ACCESS ON
        std::feclearexcept(FE_ALL_EXCEPT);
        double from4 = DBL_MAX, to4 = std::nextafter(from4, INFINITY);
        std::cout << "The next representable double after " << std::setprecision(6)
                  << from4 << std::hexfloat << " (" << from4 << ')'
                  << std::defaultfloat << " is " << to4
                  << std::hexfloat << " (" << to4 << ")\n" << std::defaultfloat;
 
        if (std::fetestexcept(FE_OVERFLOW))
            std::cout << "   raised FE_OVERFLOW\n";
        if (std::fetestexcept(FE_INEXACT))
            std::cout << "   raised FE_INEXACT\n";
    } // end FENV_ACCESS block
 
    float from5 = 0.0, to5 = std::nextafter(from5, -0.0);
    std::cout << "std::nextafter(+0.0, -0.0) gives " << std::fixed << to5 << '\n';
 
    auto precision_loss_demo = []<std::floating_point Fp>(const auto rem, const Fp start)
    {
        std::cout << rem;
        for (Fp from = start, to, Δ;
            (Δ = (to = std::nextafter(from, +INFINITY)) - from) < Fp(10.0);
            from *= Fp(10.0))
            std::cout << "nextafter(" << std::scientific << std::setprecision(0) << from 
                      << ", INF) gives " << std::fixed << std::setprecision(6) << to
                      << "; Δ = " << Δ << '\n';
    };
 
    precision_loss_demo("\nPrecision loss demo for float:\n", 10.0f);
    precision_loss_demo("\nPrecision loss demo for double:\n", 10.0e9);
    precision_loss_demo("\nPrecision loss demo for long double:\n", 10.0e17L);
}

Output:

The next representable float after 0 is 1.4012984643248170709e-45 (0x1p-149)
The next representable float after 1 is 1.0000001192092895508 (0x1.000002p+0)
The number 0.1 lies between two valid doubles:
    0.09999999999999999167332731531132594682276248931884765625 (0x1.9999999999999p-4)
and 0.1000000000000000055511151231257827021181583404541015625  (0x1.999999999999ap-4)
 
Difference between nextafter and nexttoward:
With nextafter, next float after 0 is 0
With nexttoward, next float after 0 is 1.4012984643248170709e-45
 
Special values:
The next representable double after 1.79769e+308 (0x1.fffffffffffffp+1023) is inf (inf)
   raised FE_OVERFLOW
   raised FE_INEXACT
std::nextafter(+0.0, -0.0) gives -0.000000
 
Precision loss demo for float:
nextafter(1e+01, INF) gives 10.000001; Δ = 0.000001
nextafter(1e+02, INF) gives 100.000008; Δ = 0.000008
nextafter(1e+03, INF) gives 1000.000061; Δ = 0.000061
nextafter(1e+04, INF) gives 10000.000977; Δ = 0.000977
nextafter(1e+05, INF) gives 100000.007812; Δ = 0.007812
nextafter(1e+06, INF) gives 1000000.062500; Δ = 0.062500
nextafter(1e+07, INF) gives 10000001.000000; Δ = 1.000000
nextafter(1e+08, INF) gives 100000008.000000; Δ = 8.000000
 
Precision loss demo for double:
nextafter(1e+10, INF) gives 10000000000.000002; Δ = 0.000002
nextafter(1e+11, INF) gives 100000000000.000015; Δ = 0.000015
nextafter(1e+12, INF) gives 1000000000000.000122; Δ = 0.000122
nextafter(1e+13, INF) gives 10000000000000.001953; Δ = 0.001953
nextafter(1e+14, INF) gives 100000000000000.015625; Δ = 0.015625
nextafter(1e+15, INF) gives 1000000000000000.125000; Δ = 0.125000
nextafter(1e+16, INF) gives 10000000000000002.000000; Δ = 2.000000
 
Precision loss demo for long double:
nextafter(1e+18, INF) gives 1000000000000000000.062500; Δ = 0.062500
nextafter(1e+19, INF) gives 10000000000000000001.000000; Δ = 1.000000
nextafter(1e+20, INF) gives 100000000000000000008.000000; Δ = 8.000000

[edit] See also

C documentation for nextafter