跳到主要内容

Nextafter

定义于头文件 <cmath> 中。

描述

如果 from 等于 to,则返回 to
库为所有 cv 非限定浮点类型提供了 std::nextafter 的重载,作为参数 fromto 的类型  (C++23 起)

4-6) 如果 from 等于 to,则返回 to,从 long double 转换为函数的返回类型,且不损失范围或精度。
库为所有 cv 非限定浮点类型提供了 std::nexttoward 的重载,作为参数 from 的类型  (C++23 起)

  • A) 为所有其他算术类型组合提供了额外的 std::nextafter 重载。
  • B) 为所有整数类型提供了额外的 std::nexttoward 重载,这些类型被视为 double

声明

// 1)
constexpr /* floating-point-type */
nextafter ( /* floating-point-type */ from,
/* floating-point-type */ to );
// 2)
constexpr float nextafterf( float from, float to );
// 3)
constexpr long double nextafterl( long double from, long double to );
// 4)
constexpr /* floating-point-type */
nexttoward ( /* floating-point-type */ from,
long double to );
// 5)
constexpr float nexttowardf( float from, long double to );
// 6)
constexpr long double nexttowardl( long double from, long double to );
附加重载
// 7)
template< class Arithmetic1, class Arithmetic2 >
constexpr /* common-floating-point-type */
nextafter( Arithmetic1 from, Arithmetic2 to );
// 8)
template< class Integer >
constexpr double nexttoward( Integer from, long double to );

参数

from, to - 浮点或整数值

返回值

如果没有错误发生,则返回 fromto 方向上的下一个可表示值。如果 from 等于 to,则返回 to

如果发生由于溢出引起的范围错误,则返回 ±HUGE_VAL±HUGE_VALF±HUGE_VALL(与 from 具有相同的符号)。

如果发生由于下溢引起的范围错误,则返回正确的结果。

错误处理

错误按 math_errhandling 中指定的方式报告。

如果实现支持 IEEE 浮点运算(IEC 60559

如果 from 是有限的,但预期结果是无穷大,则如果 from 不等于 to 且结果为次正规数或零,则引发 FE_INEXACT 和 FE_OVERFLOW,在任何情况下,如果 fromto 为 NaN,则返回的值独立于当前舍入模式,如果 fromto 为 NaN,则返回 NaN

备注

[POSIX] (https://pubs.opengroup.org/onlinepubs/9699919799/functions/nextafter.html) 指定溢出和下溢条件是范围错误(可能设置 errno)。

IEC 60559 建议当 from == to 时返回 from。这些函数改为返回 to,这使得围绕零的行为保持一致。
std::nextafter(-0.0, +0.0) 返回 +0.0std::nextafter(+0.0, -0.0) 返回 -0.0

std::nextafter 通常通过操作 IEEE 表示来实现(glibc,musl)。

不需要严格按照额外重载提供额外的 std::nextafter 重载。它们只需要足以确保对于它们的第一个参数 num1 和第二个参数 num2

如果 num1num2 的类型是 long double,则
std::nextafter(num1, num2) 具有与
std::nextafter(static_cast<long double>(num1), static_cast<long double>(num2)) 相同的效果。

否则,如果 num1 和/或 num2 的类型是 double 或整数类型,则
std::nextafter(num1, num2) 具有与
std::nextafter(static_cast<double>(num1), static_cast<double>(num2))

否则,如果 num1num2 的类型为 float,则
std::nextafter(num1, num2) 具有与
std::nextafter(static_cast<float>(num1), static_cast<float>(num2)) 相同的效果。 (直到 C++23)

如果 num1num2 具有算术类型,则
std::nextafter(num1, num2) 具有与
std::nextafter(static_cast</* common-floating-point-type */>(num1), static_cast</* common-floating-point-type */>(num2)) ,

其中 /* common-floating-point-type */num1num2 类型之间具有最大浮点转换等级和最大浮点转换子等级的浮点类型,整数类型参数被视为具有与 double 相同的浮点转换等级。

如果不存在具有最大等级和子等级的浮点类型,则重载解析不会从提供的重载中产生可用的候选。(C++23 起)

不需要严格按照额外重载提供额外的 std::nexttoward 重载。它们只需要足以确保对于其整数类型的参数 numstd::nexttoward(num) 具有与 std::nexttoward(static_cast<double>(num)) 相同的效果。

示例

#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);
}

结果
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

Nextafter

定义于头文件 <cmath> 中。

描述

如果 from 等于 to,则返回 to
库为所有 cv 非限定浮点类型提供了 std::nextafter 的重载,作为参数 fromto 的类型  (C++23 起)

4-6) 如果 from 等于 to,则返回 to,从 long double 转换为函数的返回类型,且不损失范围或精度。
库为所有 cv 非限定浮点类型提供了 std::nexttoward 的重载,作为参数 from 的类型  (C++23 起)

  • A) 为所有其他算术类型组合提供了额外的 std::nextafter 重载。
  • B) 为所有整数类型提供了额外的 std::nexttoward 重载,这些类型被视为 double

声明

// 1)
constexpr /* floating-point-type */
nextafter ( /* floating-point-type */ from,
/* floating-point-type */ to );
// 2)
constexpr float nextafterf( float from, float to );
// 3)
constexpr long double nextafterl( long double from, long double to );
// 4)
constexpr /* floating-point-type */
nexttoward ( /* floating-point-type */ from,
long double to );
// 5)
constexpr float nexttowardf( float from, long double to );
// 6)
constexpr long double nexttowardl( long double from, long double to );
附加重载
// 7)
template< class Arithmetic1, class Arithmetic2 >
constexpr /* common-floating-point-type */
nextafter( Arithmetic1 from, Arithmetic2 to );
// 8)
template< class Integer >
constexpr double nexttoward( Integer from, long double to );

参数

from, to - 浮点或整数值

返回值

如果没有错误发生,则返回 fromto 方向上的下一个可表示值。如果 from 等于 to,则返回 to

如果发生由于溢出引起的范围错误,则返回 ±HUGE_VAL±HUGE_VALF±HUGE_VALL(与 from 具有相同的符号)。

如果发生由于下溢引起的范围错误,则返回正确的结果。

错误处理

错误按 math_errhandling 中指定的方式报告。

如果实现支持 IEEE 浮点运算(IEC 60559

如果 from 是有限的,但预期结果是无穷大,则如果 from 不等于 to 且结果为次正规数或零,则引发 FE_INEXACT 和 FE_OVERFLOW,在任何情况下,如果 fromto 为 NaN,则返回的值独立于当前舍入模式,如果 fromto 为 NaN,则返回 NaN

备注

[POSIX] (https://pubs.opengroup.org/onlinepubs/9699919799/functions/nextafter.html) 指定溢出和下溢条件是范围错误(可能设置 errno)。

IEC 60559 建议当 from == to 时返回 from。这些函数改为返回 to,这使得围绕零的行为保持一致。
std::nextafter(-0.0, +0.0) 返回 +0.0std::nextafter(+0.0, -0.0) 返回 -0.0

std::nextafter 通常通过操作 IEEE 表示来实现(glibc,musl)。

不需要严格按照额外重载提供额外的 std::nextafter 重载。它们只需要足以确保对于它们的第一个参数 num1 和第二个参数 num2

如果 num1num2 的类型是 long double,则
std::nextafter(num1, num2) 具有与
std::nextafter(static_cast<long double>(num1), static_cast<long double>(num2)) 相同的效果。

否则,如果 num1 和/或 num2 的类型是 double 或整数类型,则
std::nextafter(num1, num2) 具有与
std::nextafter(static_cast<double>(num1), static_cast<double>(num2))

否则,如果 num1num2 的类型为 float,则
std::nextafter(num1, num2) 具有与
std::nextafter(static_cast<float>(num1), static_cast<float>(num2)) 相同的效果。 (直到 C++23)

如果 num1num2 具有算术类型,则
std::nextafter(num1, num2) 具有与
std::nextafter(static_cast</* common-floating-point-type */>(num1), static_cast</* common-floating-point-type */>(num2)) ,

其中 /* common-floating-point-type */num1num2 类型之间具有最大浮点转换等级和最大浮点转换子等级的浮点类型,整数类型参数被视为具有与 double 相同的浮点转换等级。

如果不存在具有最大等级和子等级的浮点类型,则重载解析不会从提供的重载中产生可用的候选。(C++23 起)

不需要严格按照额外重载提供额外的 std::nexttoward 重载。它们只需要足以确保对于其整数类型的参数 numstd::nexttoward(num) 具有与 std::nexttoward(static_cast<double>(num)) 相同的效果。

示例

#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);
}

结果
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