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
/* floating-point-type */
remquo
(
/* floating-point-type */
x,
|
(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 */
|
(A) |
(C++11 起)
(C++23 起为 constexpr) |
std::remquo
的重载,这些类型对应参数
x
和
y
的类型。
(C++23 起)
目录 |
参数
| 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 满足以下条件:
|
(C++23 前) |
|
若
num1
和
num2
具有算术类型,则
std
::
remquo
(
num1, num2, quo
)
的效果等同于
std
::
remquo
(
static_cast
<
/*common-floating-point-type*/
>
(
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) 为正,(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++11)
|
除法运算的有符号余数
(函数) |
|
C 文档
for
remquo
|
|