std::nextaf...exttowardf,(3)
π std::nextafter, std::nextafterf, std::nextafterl, std::nexttoward, std::nexttowardf β C++ Standard Libary (section 3) π
okay bestie, part 1 of 2 is here. The page header is literally std::nextaf...exttowardf,(3) β yes, itβs giving truncated man-page chaos β and the manual name is C++ Standard Libary, section 3. (The source spells it βLibaryβ; we are not fixing it, we are respecting the iconique typo.) β¨
β¨ NAME β¨
The NAME line prints this exact list twice, with a hyphen in the middle:
std::nextafter,std::nextafterf,std::nextafterl,std::nexttoward,std::nexttowardf, β std::nextafter,std::nextafterf,std::nextafterl,std::nexttoward,std::nexttowardf,
So the named crew is std::nextafter, std::nextafterf, std::nextafterl, std::nexttoward, and std::nexttowardf. The NAME line does not list std::nexttowardl, but the synopsis later absolutely brings std::nexttowardl into the group chat β keep that in your notes, iykyk. π¦
πΈ Synopsis πΈ
All of this lives in #include <cmath>. Hereβs the synopsis code, with the overload numbers and since-tags spelled out right after, because the original formatting is doing The Most.
Defined in header <cmath>
float nextafter ( float from, float to );
double nextafter ( double from, double to );
long double nextafter ( long double from, long double to );
constexpr /* floating-point-type */ nextafter ( /* floating-point-type */ from, /* floating-point-type */ to );
float nextafterf( float from, float to );
long double nextafterl( long double from, long double to );
float nexttoward ( float from, long double to );
double nexttoward ( double from, long double to );
long double nexttoward ( long double from, long double to );
constexpr /* floating-point-type */ nexttoward ( /* floating-point-type */ from, long double to );
float nexttowardf( float from, long double to );
long double nexttowardl( long double from, long double to );
Additional overloads
Defined in header <cmath>
template< class Arithmetic1, class Arithmetic2 >
/* common-floating-point-type */ nextafter( Arithmetic1 from, Arithmetic2 to );
template< class Integer >
double nexttoward( Integer from, long double to );
Now the annotations, fr fr:
(1)is floating around thenexttowardlines in the original synopsis. Itβs there, we keep it.- The first
float nextafteroverload has no extra tag printed beside it. - The
double nextafteroverload is(since C++11)and(until C++23). - The
constexpr /* floating-point-type */ nextafteroverload is(since C++23). nextafterfis(since C++11),(2), and(constexpr since C++23).nextafterlis(since C++11),(3), and(constexpr since C++23).- The
double nexttowardoverload is(since C++11)and(until C++23). - The
constexpr /* floating-point-type */ nexttowardoverload is(since C++23). nexttowardfis(since C++11),(4) (5), and(constexpr since C++23)β yes, two numbers, we donβt make the rules.nexttowardlis(since C++11),(6), and(constexpr since C++23).- The additional
std::nextaftertemplate is(since C++11),(A), and(constexpr since C++23). - The additional
std::nexttowardtemplate is(since C++11),(B), and(constexpr since C++23).
The actual vibe of these functions: return the next representable value of from in the direction of to. Thatβs the whole mission. π―
1-3)β iffromequalsto,tois returned. Also,(since C++23)the library provides overloads ofstd::nextafterfor all cv-unqualified floating-point types as the type of the parametersfromandto.4-6)β iffromequalsto,tois returned, converted fromlong doubleto the return type of the function without loss of range or precision.
(since C++23) 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. Thatβs not a drill, bestie. π
A)β additionalstd::nextafteroverloads are provided for all other combinations of arithmetic types.B)β additionalstd::nexttowardoverloads are provided for all integer types, which are treated asdouble.
π Parameters π
from, toβ floating-point or integer values.
π 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.
π Error handling π
Errors are reported as specified in math_errhandling.
If the implementation supports IEEE floating-point arithmetic (IEC 60559):
- if
fromis finite, but the expected result is an infinity, raisesFE_INEXACTandFE_OVERFLOW. - if
fromdoes not equaltoand the result is subnormal or zero, raisesFE_INEXACTandFE_UNDERFLOW. - in any case, the returned value is independent of the current rounding mode.
- if either
fromortoisNaN,NaNis returned.
π¦ 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
num1ornum2has typelong double, thenstd::nextafter(num1, num2)has the same effect asstd::nextafter(static_cast<long double>(num1), static_cast<long double>(num2)). - Otherwise, if
num1and/ornum2has typedoubleor an integer type, thenstd::nextafter(num1, num2)has the same effect asstd::nextafter(static_cast<double>(num1), static_cast<double>(num2)).(until C++23) - Otherwise, if
num1ornum2has typefloat, thenstd::nextafter(num1, num2)has the same effect asstd::nextafter(static_cast<float>(num1), static_cast<float>(num2)).
(since 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.
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)).
π Example π
// Run this code
#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);
}
Part 1 ends here, bestie β part 2 is pulling up next, so keep scrolling. π«Ά
Okay so here's what that whole program spits out when you actually run it β and honestly? icon status. Look at all these digits, she's giving precision π
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
Let's walk through it because some of this is so good π
The next representable float after 0 is 1.4012984643248170709e-45, which is 0x1p-149 β tiny little baby number, we love her. And the next representable float after 1 is 1.0000001192092895508, aka 0x1.000002p+0.
Then the number 0.1 β our girl β turns out to be lowkey homeless, just chilling between two valid doubles: 0.09999999999999999167332731531132594682276248931884765625 (0x1.9999999999999p-4) and 0.1000000000000000055511151231257827021181583404541015625 (0x1.999999999999ap-4). Not me getting emotional about a decimal π₯²
Then the difference between nextafter and nexttoward, spelled out for the girlies: with nextafter, next float after 0 is 0. With nexttoward, next float after 0 is 1.4012984643248170709e-45. Different behaviour, same vibe.
Special values section, and okay this one's a little dramatic π₯: the next representable double after 1.79769e+308 (0x1.fffffffffffffp+1023) is inf (inf), and it raised FE_OVERFLOW and raised FE_INEXACT. Also std::nextafter(+0.0, -0.0) gives -0.000000 β yes, negative zero, she said what she said.
And then the precision loss demos, which are genuinely the main character of this whole page π β watch the delta grow as the exponent climbs:
For float: from nextafter(1e+01, INF) giving 10.000001 with Ξ = 0.000001 all the way up to nextafter(1e+08, INF) giving 100000008.000000 with Ξ = 8.000000.
For double: from nextafter(1e+10, INF) giving 10000000000.000002 with Ξ = 0.000002 up to nextafter(1e+16, INF) giving 10000000000000002.000000 with Ξ = 2.000000.
For long double: from nextafter(1e+18, INF) giving 1000000000000000000.062500 with Ξ = 0.062500, through nextafter(1e+19, INF) giving 10000000000000000001.000000 with Ξ = 1.000000, to nextafter(1e+20, INF) giving 100000000000000000008.000000 with Ξ = 8.000000.
Bigger numbers, bigger jumps. That's the whole tea β
π See also π
- C documentation for
nextafterβ go read the C version too bestie, she's the blueprint π«Ά
That's the page, bestie! This one's from http://cppreference.com, dated 2024.06.10 β so if anything looks off, take it up with them and not me π Anyway, go forth and nudge your floats, one representable value at a time πβ¨π
π¦ where this page comes from
- nixpkgs unstable: stdman 2024.07.05
- opensuse-leap 16.0: stdman 2024.07.05-bp160.1.9 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms