std::nextafter, std::nextafterf, std::nextafterl, std::nexttoward, std::nexttowardf, std::nexttowardl

来自cppreference.com
< cpp‎ | numeric‎ | math
 
 
 
常用数学函数
函数
基本运算
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)(C++11)(C++11)
指数函数
(C++11)
(C++11)
(C++11)
(C++11)
幂函数
(C++11)
(C++11)
三角与双曲函数
(C++11)
(C++11)
(C++11)
误差与伽马函数
(C++11)
(C++11)
(C++11)
(C++11)
临近整数的浮点运算
(C++11)(C++11)(C++11)
(C++11)
(C++11)
(C++11)(C++11)(C++11)
浮点操作函数
(C++11)(C++11)
(C++11)
(C++11)
nextafternexttoward
(C++11)(C++11)
(C++11)
分类/比较
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
宏常量
(C++11)(C++11)(C++11)(C++11)(C++11)
 
在标头 <cmath> 定义
(1)
float       nextafter ( float from, float to );

double      nextafter ( double from, double to );

long double nextafter ( long double from, long 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 );

long double nexttoward ( long 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)

返回 fromto 方向的下个可表示值。

1-3) 如果 from 等于 to,那么返回 to标准库提供所有以无 cv 限定的浮点类型作为参数 fromto 的类型的 std::nextafter 重载。 (C++23 起)
4-6) 如果 from 等于 to,那么返回从 long double 转换到函数返回类型的 to,而不带范围或精度的损失。

标准库提供所有以无 cv 限定的浮点类型作为参数 from 的类型的 std::nexttoward 重载。然而如果 from 对应的实参具有扩展浮点类型,那么对 std::nexttoward 的调用非良构,因为下个可表示值(或 to)不保证能以 long double 表示。

(C++23 起)
A) 为算术类型的所有其他组合提供额外的 std::nextafter 重载。
B) 为所有整数类型提供额外的 std::nexttoward 重载,将它们当做 double

参数

from, to - 浮点或整数值

返回值

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

如果发生上溢导致的值域错误,那么返回 ±HUGE_VAL±HUGE_VALF±HUGE_VALL(所带符号同 from)。

如果发生下溢导致的值域错误,那么返回正确结果。

错误处理

报告 math_errhandling 中指定的错误。

如果实现支持 IEEE 浮点算术(IEC 60559),那么

  • 如果 from 有限,但期待的结果无限,那么引发 FE_INEXACTFE_OVERFLOW
  • 如果 from 不等于 to 且结果非正规或为零,那么引发 FE_INEXACTFE_UNDERFLOW
  • 任何情况下,返回值独立于当前舍入模式。
  • 如果 fromto 为 NaN,那么返回 NaN。

注解

POSIX 指定上溢和下溢条件是值域错误(可以设置 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 表示实现(glibcmusl)。

std::nextafter 的额外重载不需要以 (A) 的形式提供。它们只需要能够对它们的第一个实参 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</* 公共浮点类型 */>(num1),
               static_cast</* 公共浮点类型 */>(num2))
的效果相同,其中 /* 公共浮点类型 */num1num2 的类型中浮点转换等级浮点转换子等级最高的浮点类型,整数类型的实参被视为具有与 double 相等的浮点转换等级。

如果不存在等级和子等级最高的浮点类型,那么在重载决议时不会从提供的重载中产生可用的候选。

(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

参阅