std::remquo, std::remquof, std::remquol
在标头 <cmath> 定义
|
||
(1) | ||
float remquo ( float x, float y, int* quo ); double remquo ( double x, double y, int* quo ); |
(C++11 起) (C++23 前) |
|
constexpr /* 浮点类型 */ remquo ( /* 浮点类型 */ x, /* 浮点类型 */ 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 > /* 公共浮点类型 */ remquo( Arithmetic1 x, Arithmetic2 y, int* quo ); |
(A) | (C++11 起) (C++23 起 constexpr) |
std::remquo
重载。 (C++23 起)参数
x, y | - | 浮点或整数值 |
quo | - | 用来存储 x / y 的符号和某些位的指向 int 的指针 |
返回值
在成功时返回定义于 std::remainder 的 x / y 的余数,并将 x / y 的符号和至少后三位有效数字存储到 *quo(正式而言,存储的值的符号是 x / y 的符号,而绝对值与 x / y 的整数商的绝对值对于 modulo 2n
同余,其中 n 是由实现定义的大于或等于 3 的整数)。
如果 y 为零,那么不指定存储到 *quo 的值。
如果发生定义域错误,那么返回值由实现定义(受支持的平台上是 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 为零时发生定义域错误。
此函数在实现周期可准确表示为浮点值的周期函数时有用:对非常大的 x 计算 sin(πx) 时,直接调用 std::sin 可能导致巨大误差,但如果首先以 std::remquo
减小参数,吗,那么商的低位可用来确定结果在周期中的八分位,同时余数可用来计算拥有高精度的值。
某些平台上硬件支持此运算(而例如在 Intel CPU 上,FPREM1
在完成时于商中准确保留 3 位精度)。
额外重载不需要以 (A) 的形式提供。它们只需要能够对它们的第一个实参 num1 和第二个实参 num2 满足以下要求:
|
(C++23 前) |
如果 num1 和 num2 具有算术类型,那么 std::remquo(num1, num2, quo) 和 std::remquo(static_cast</* 公共浮点类型 */>(num1), 如果不存在等级和子等级最高的浮点类型,那么在重载决议时不会从提供的重载中产生可用的候选。 |
(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) 和 (1.5,2) 中为正,在 (0.5;1.5) 中为负 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 << "朴素实现:\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' << "优秀实现:\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' << "朴素实现:\n" << " cos(pi * 1000000000000.25) = " << cos_pi_x_naive(1000000000000.25) << '\n' << " cos(pi * 1000000000001.25) = " << cos_pi_x_naive(1000000000001.25) << '\n' << "优秀实现:\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"; }
可能的输出:
朴素实现: cos(pi * 0.25) = +0.707107 cos(pi * 1.25) = -0.707107 cos(pi * 2.25) = +0.707107 优秀实现: cos(pi * 0.25) = +0.707107 cos(pi * 1.25) = -0.707107 cos(pi * 2.25) = +0.707107 朴素实现: cos(pi * 1000000000000.25) = +0.707123 cos(pi * 1000000000001.25) = -0.707117 优秀实现: 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++11) |
除法运算的有符号余数 (函数) |