Namespaces
Variants

std:: remquo, std:: remquof, std:: remquol

From cppreference.net
Common mathematical functions
Nearest integer floating point operations
(C++11)
(C++11)
(C++11) (C++11) (C++11)
Floating point manipulation functions
(C++11) (C++11)
(C++11)
(C++11)
Classification and comparison
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
Types
(C++11)
(C++11)
(C++11)
Macro constants
定义于头文件 <cmath>
(1)
float remquo ( float x, float y, int * quo ) ;

double remquo ( double x, double y, int * quo ) ;

long double remquo ( long double x, long double y, int * quo ) ;
(C++11 起)
(C++23 前)
constexpr /* floating-point-type */

remquo ( /* floating-point-type */ x,

/* floating-point-type */ y, int * quo ) ;
(C++23 起)
float remquof ( float x, float y, int * quo ) ;
(2) (C++11 起)
(C++23 起为 constexpr)
long double remquol ( long double x, long double y, int * quo ) ;
(3) (C++11 起)
(C++23 起为 constexpr)
定义于头文件 <cmath>
template < class Arithmetic1, class Arithmetic2 >

/* common-floating-point-type */

remquo ( Arithmetic1 x, Arithmetic2 y, int * quo ) ;
(A) (C++11 起)
(C++23 起为 constexpr)
1-3) 计算除法运算 x / y 的浮点余数,实现方式与 std::remainder() 函数相同。此外,会将 x / y 的符号及最低有效三位存储到 quo 中,足以确定结果在周期内的八分圆象限。 标准库为所有无 cv 限定符的浮点类型提供了 std::remquo 的重载,这些类型对应参数 x y 的类型。 (C++23 起)
A) 为所有其他算术类型组合提供了额外的重载。

目录

参数

x, y - 浮点数或整数值
quo - 指向 int 的指针,用于存储 x / y 的符号和部分位

返回值

若成功,则返回定义于 std::remainder 的除法 x / y 的浮点余数,并在 * quo 中存储 x / y 的符号及至少三个最低有效位(形式上,存储值的符号与 x / y 的符号相同,其幅值在 模 2 n
下与 x / y 的整数商幅值同余,其中 n 是实现定义的整数且不小于 3 )。

如果 y 为零,则存储在 * quo 中的值是未指定的。

如果发生定义域错误,将返回一个由实现定义的值(在支持 NaN 的情况下返回 NaN)。

如果由于下溢发生范围错误,在支持次正规数的情况下将返回正确结果。

如果 y 为零但未发生定义域错误,则返回零。

错误处理

错误报告方式遵循 math_errhandling 中的规范。

y 为零时可能出现定义域错误。

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

  • 当前 舍入模式 不产生影响。
  • 永远不会引发 FE_INEXACT 异常。
  • x 为±∞且 y 非NaN,则返回NaN并引发 FE_INVALID 异常。
  • y 为±0且 x 非NaN,则返回NaN并引发 FE_INVALID 异常。
  • x y 为NaN,则返回NaN。

注释

POSIX 要求 x 为无穷大或 y 为零时发生定义域错误。

该函数在实现周期函数时非常有用,特别是当周期可以精确表示为浮点数值时:在计算 sin(πx) 时,若 x 值极大,直接调用 std::sin 可能导致较大误差。但若先使用 std::remquo 对函数参数进行归约处理,则可通过商值的低位比特确定周期内结果的符号和八分圆位置,同时利用余数进行高精度计算。

在某些平台上,该操作由硬件支持(例如,在Intel CPU上, FPREM1 指令完成时会在商中精确保留3位精度)。

额外的重载并不需要完全按照 (A) 的形式提供。只需确保对于它们的第一个参数 num1 和第二个参数 num2 满足以下条件:

  • num1 num2 具有类型 long double ,则 std :: remquo ( num1, num2, quo ) 的效果等同于 std :: remquo ( static_cast < long double > ( num1 ) ,
    static_cast < long double > ( num2 ) , quo )
  • 否则,若 num1 和/或 num2 具有类型 double 或整数类型,则 std :: remquo ( num1, num2, quo ) 的效果等同于 std :: remquo ( static_cast < double > ( num1 ) ,
    static_cast < double > ( num2 ) , quo )
  • 否则,若 num1 num2 具有类型 float ,则 std :: remquo ( num1, num2, quo ) 的效果等同于 std :: remquo ( static_cast < float > ( num1 ) ,
    static_cast < float > ( num2 ) , quo )
(C++23 前)

num1 num2 具有算术类型,则 std :: remquo ( num1, num2, quo ) 的效果等同于 std :: remquo ( static_cast < /*common-floating-point-type*/ > ( num1 ) ,
static_cast < /*common-floating-point-type*/ > ( num2 ) , quo )
,其中 /*common-floating-point-type*/ num1 num2 类型间具有最高 浮点转换等级 和最高 浮点转换子等级 的浮点类型,整数类型的实参被认为具有与 double 相同的浮点转换等级。

若不存在具有最高等级和子等级的此类浮点类型,则 重载决议 不会从提供的重载中得到可用候选。

(C++23 起)

示例

#include <cfenv>
#include <cmath>
#include <iostream>
#ifndef __GNUC__
#pragma STDC FENV_ACCESS ON
#endif
const double pi = std::acos(-1); // 或 C++20 起的 std::numbers::pi
double cos_pi_x_naive(double x)
{
    return std::cos(pi * x);
}
// 周期为 2,值在 (0;0.5) 为正,(0.5;1.5) 为负,(1.5,2) 为正
double cos_pi_x_smart(double x)
{
    int quadrant;
    double rem = std::remquo(x, 1, &quadrant);
    quadrant = static_cast<unsigned>(quadrant) % 2; // 周期为 2
    return quadrant == 0 ?  std::cos(pi * rem)
                         : -std::cos(pi * rem);
}
int main()
{
    std::cout << std::showpos
              << "naive:\n"
              << "  cos(pi * 0.25) = " << cos_pi_x_naive(0.25) << '\n'
              << "  cos(pi * 1.25) = " << cos_pi_x_naive(1.25) << '\n'
              << "  cos(pi * 2.25) = " << cos_pi_x_naive(2.25) << '\n'
              << "smart:\n"
              << "  cos(pi * 0.25) = " << cos_pi_x_smart(0.25) << '\n'
              << "  cos(pi * 1.25) = " << cos_pi_x_smart(1.25) << '\n'
              << "  cos(pi * 2.25) = " << cos_pi_x_smart(2.25) << '\n'
              << "naive:\n"
              << "  cos(pi * 1000000000000.25) = "
              << cos_pi_x_naive(1000000000000.25) << '\n'
              << "  cos(pi * 1000000000001.25) = "
              << cos_pi_x_naive(1000000000001.25) << '\n'
              << "smart:\n"
              << "  cos(pi * 1000000000000.25) = "
              << cos_pi_x_smart(1000000000000.25) << '\n'
              << "  cos(pi * 1000000000001.25) = "
              << cos_pi_x_smart(1000000000001.25) << '\n';
    // 错误处理
    std::feclearexcept(FE_ALL_EXCEPT);
    int quo;
    std::cout << "remquo(+Inf, 1) = " << std::remquo(INFINITY, 1, &quo) << '\n';
    if (fetestexcept(FE_INVALID))
        std::cout << "  FE_INVALID 已触发\n";
}

可能的输出:

naive:
  cos(pi * 0.25) = +0.707107
  cos(pi * 1.25) = -0.707107
  cos(pi * 2.25) = +0.707107
smart:
  cos(pi * 0.25) = +0.707107
  cos(pi * 1.25) = -0.707107
  cos(pi * 2.25) = +0.707107
naive:
  cos(pi * 1000000000000.25) = +0.707123
  cos(pi * 1000000000001.25) = -0.707117
smart:
  cos(pi * 1000000000000.25) = +0.707107
  cos(pi * 1000000000001.25) = -0.707107
remquo(+Inf, 1) = -nan
  FE_INVALID 已触发

参见

计算整数除法的商和余数
(函数)
(C++11) (C++11)
浮点除法运算的余数
(函数)
(C++11) (C++11) (C++11)
除法运算的有符号余数
(函数)
C 文档 for remquo