std::nextafter, std::nextafterf, std::nextafterl, std::nexttoward, std::nexttowardf, std::nexttowardl
在标头 <cmath> 定义
|
||
(1) | ||
float nextafter ( float from, float to ); double nextafter ( double from, double to ); |
(C++11 起) (C++23 前) |
|
constexpr /* 浮点类型 */ nextafter ( /* 浮点类型 */ from, /* 浮点类型 */ to ); |
(C++23 起) | |
float nextafterf( float from, float to ); |
(2) | (C++11 起) (C++23 起 constexpr) |
long double nextafterl( long double from, long double to ); |
(3) | (C++11 起) (C++23 起 constexpr) |
(4) | ||
float nexttoward ( float from, long double to ); double nexttoward ( double from, long double to ); |
(C++11 起) (C++23 前) |
|
constexpr /* 浮点类型 */ nexttoward ( /* 浮点类型 */ from, long double to ); |
(C++23 起) | |
float nexttowardf( float from, long double to ); |
(5) | (C++11 起) (C++23 起 constexpr) |
long double nexttowardl( long double from, long double to ); |
(6) | (C++11 起) (C++23 起 constexpr) |
在标头 <cmath> 定义
|
||
template< class Arithmetic1, class Arithmetic2 > /* 公共浮点类型 */ nextafter( Arithmetic1 from, Arithmetic2 to ); |
(A) | (C++11 起) (C++23 起 constexpr) |
template< class Integer > double nexttoward( Integer from, long double to ); |
(B) | (C++11 起) (C++23 起 constexpr) |
返回 from 往 to 方向的下个可表示值。
std::nextafter
重载。 (C++23 起)
标准库提供所有以无 cv 限定的浮点类型作为参数 from 的类型的 |
(C++23 起) |
std::nextafter
重载。std::nexttoward
重载,将它们当做 double。参数
from, to | - | 浮点或整数值 |
返回值
如果没有发生错误,那么返回 from 往 to 的方向的下个可表示值。如果 from 等于 to ,那么返回 to。
如果发生上溢导致的值域错误,那么返回 ±HUGE_VAL
、±HUGE_VALF
或 ±HUGE_VALL
(所带符号同 from)。
如果发生下溢导致的值域错误,那么返回正确结果。
错误处理
报告 math_errhandling 中指定的错误。
如果实现支持 IEEE 浮点算术(IEC 60559),那么
- 如果 from 有限,但期待的结果无限,那么引发 FE_INEXACT 和 FE_OVERFLOW。
- 如果 from 不等于 to 且结果非正规或为零,那么引发 FE_INEXACT 和 FE_UNDERFLOW。
- 任何情况下,返回值独立于当前舍入模式。
- 如果 from 或 to 为 NaN,那么返回 NaN。
注解
POSIX 指定上溢和下溢条件是值域错误(可以设置 errno)。
IEC 60559 推荐凡在 from == to 时返回 from。这些函数改成返回 to,这使得围绕零的行为一致:std::nextafter(-0.0, +0.0) 返回 +0.0 而 std::nextafter(+0.0, -0.0) 返回 -0.0。
std::nextafter
常通过操纵 IEEE 表示实现(glibc,musl)。
std::nextafter
的额外重载不需要以 (A) 的形式提供。它们只需要能够对它们的第一个实参 num1 和第二个实参 num2 满足以下要求:
|
(C++23 前) |
如果 num1 和 num2 具有算术类型,那么 std::nextafter(num1, num2) 和 std::nextafter(static_cast</* 公共浮点类型 */>(num1), 如果不存在等级和子等级最高的浮点类型,那么在重载决议时不会从提供的重载中产生可用的候选。 |
(C++23 起) |
std::nexttoward
的额外重载不需要以 (B) 的形式提供。它们只需要能够对它们的整数类型实参 num 确保 std::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 << "在 " << std::setprecision(20) << from1 << " 后的下个可表示的 float 是 " << to1 << std::hexfloat << "(" << to1 << ")\n" << std::defaultfloat; float from2 = 1, to2 = std::nextafter(from2, 2.f); std::cout << "在 " << from2 << " 后的下个可表示的 float 是 " << to2 << std::hexfloat << "(" << to2 << ")\n" << std::defaultfloat; double from3 = std::nextafter(0.1, 0), to3 = 0.1; std::cout << "数字 0.1 位于两个有效 double 之间:\n" << std::setprecision(56) << " " << from3 << std::hexfloat << "(" << from3 << ")" << std::defaultfloat << "\n和 " << to3 << std::hexfloat << " (" << to3 << ")\n" << std::defaultfloat << std::setprecision(20); std::cout << "\nnextafter 和 nexttoward 的区别:\n"; long double dir = std::nextafter(from1, 1.0L); // 第一个次正规 long double float x = std::nextafter(from1, dir); // 首先将 dir 转换到 float,得到 0 std::cout << "通过 nextafter 得到的 " << from1 << " 之后的下一个 float 是 " << x << '\n'; x = std::nexttoward(from1, dir); std::cout << "通过 nexttoward 得到的 " << from1 << " 之后的下一个 float 是 " << x << '\n'; std::cout << "\n特殊值:\n"; { // #pragma STDC FENV_ACCESS ON std::feclearexcept(FE_ALL_EXCEPT); double from4 = DBL_MAX, to4 = std::nextafter(from4, INFINITY); std::cout << "在 " << std::setprecision(6) << from4 << std::hexfloat << "(" << from4 << ")" << std::defaultfloat << " 后的下个可表示的 double 是 " << to4 << std::hexfloat << "(" << to4 << ")\n" << std::defaultfloat; if (std::fetestexcept(FE_OVERFLOW)) std::cout << " 发生 FE_OVERFLOW\n"; if (std::fetestexcept(FE_INEXACT)) std::cout << " 发生 FE_INEXACT\n"; } // 结束 FENV_ACCESS 块 float from5 = 0.0, to5 = std::nextafter(from5, -0.0); std::cout << "std::nextafter(+0.0, -0.0) 给出 " << 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) 给出 " << std::fixed << std::setprecision(6) << to << ";Δ = " << Δ << '\n'; }; precision_loss_demo("\nfloat 精度损失演示:\n", 10.0f); precision_loss_demo("\ndouble 精度损失演示:\n", 10.0e9); precision_loss_demo("\nlong double 精度损失演示:\n", 10.0e17L); }
输出:
在 0 后的下个可表示的 float 是 1.4012984643248170709e-45(0x1p-149) 在 1 后的下个可表示的 float 是 1.0000001192092895508(0x1.000002p+0) 数字 0.1 位于两个有效 double 之间: 0.09999999999999999167332731531132594682276248931884765625(0x1.9999999999999p-4) 和 0.1000000000000000055511151231257827021181583404541015625 (0x1.999999999999ap-4) nextafter 和 nexttoward 的区别: 通过 nextafter 得到的 0 之后的下一个 float 是 0 通过 nexttoward 得到的 0 之后的下一个 float 是 1.4012984643248170709e-45 特殊值: 在 1.79769e+308(0x1.fffffffffffffp+1023)后的下个可表示的 double 是 inf(inf) 发生 FE_OVERFLOW 发生 FE_INEXACT std::nextafter(+0.0, -0.0) 给出 -0.000000 float 精度损失演示: nextafter(1e+01, INF) 给出 10.000001;Δ = 0.000001 nextafter(1e+02, INF) 给出 100.000008;Δ = 0.000008 nextafter(1e+03, INF) 给出 1000.000061;Δ = 0.000061 nextafter(1e+04, INF) 给出 10000.000977;Δ = 0.000977 nextafter(1e+05, INF) 给出 100000.007812;Δ = 0.007812 nextafter(1e+06, INF) 给出 1000000.062500;Δ = 0.062500 nextafter(1e+07, INF) 给出 10000001.000000;Δ = 1.000000 nextafter(1e+08, INF) 给出 100000008.000000;Δ = 8.000000 double 精度损失演示: nextafter(1e+10, INF) 给出 10000000000.000002;Δ = 0.000002 nextafter(1e+11, INF) 给出 100000000000.000015;Δ = 0.000015 nextafter(1e+12, INF) 给出 1000000000000.000122;Δ = 0.000122 nextafter(1e+13, INF) 给出 10000000000000.001953;Δ = 0.001953 nextafter(1e+14, INF) 给出 100000000000000.015625;Δ = 0.015625 nextafter(1e+15, INF) 给出 1000000000000000.125000;Δ = 0.125000 nextafter(1e+16, INF) 给出 10000000000000002.000000;Δ = 2.000000 long double 精度损失演示: nextafter(1e+18, INF) 给出 1000000000000000000.062500;Δ = 0.062500 nextafter(1e+19, INF) 给出 10000000000000000001.000000;Δ = 1.000000 nextafter(1e+20, INF) 给出 100000000000000000008.000000;Δ = 8.000000