std:: fma, std:: fmaf, std:: fmal
|
定义于头文件
<cmath>
|
||
| (1) | ||
|
float
fma
(
float
x,
float
y,
float
z
)
;
double
fma
(
double
x,
double
y,
double
z
)
;
|
(C++11 起)
(C++23 前) |
|
|
constexpr
/* floating-point-type */
fma
(
/* floating-point-type */
x,
|
(C++23 起) | |
|
float
fmaf
(
float
x,
float
y,
float
z
)
;
|
(2) |
(C++11 起)
(C++23 起为 constexpr) |
|
long
double
fmal
(
long
double
x,
long
double
y,
long
double
z
)
;
|
(3) |
(C++11 起)
(C++23 起为 constexpr) |
|
#define FP_FAST_FMA /* implementation-defined */
|
(4) | (C++11 起) |
|
#define FP_FAST_FMAF /* implementation-defined */
|
(5) | (C++11 起) |
|
#define FP_FAST_FMAL /* implementation-defined */
|
(6) | (C++11 起) |
|
定义于头文件
<cmath>
|
||
|
template
<
class
Arithmetic1,
class
Arithmetic2,
class
Arithmetic3
>
/* common-floating-point-type */
|
(A) |
(C++11 起)
(C++23 起为 constexpr) |
std::fma
的重载,作为参数
x
、
y
和
z
的类型。
(C++23 起)
std::fma
相较于表达式
x
*
y
+
z
分别针对
double
、
float
及
long
double
参数具有更快的求值速度(同时精度更高)。若已定义,这些宏的求值结果为整型
1
。
目录 |
参数
| x, y, z | - | 浮点数或整数值 |
返回值
若成功,返回 x * y + z 的值,该值的计算过程如同以无限精度运算后,一次性舍入以适应结果类型(或者,等效地作为单个三元浮点运算执行)。
如果发生因溢出导致的范围错误,将返回
±HUGE_VAL
、
±HUGE_VALF
或
±HUGE_VALL
。
如果发生因下溢导致的范围错误,将返回正确值(四舍五入后)。
错误处理
错误报告方式遵循 math_errhandling 中的规范。
如果实现支持 IEEE 浮点算术 (IEC 60559),
-
如果
x
为零且
y
为无穷大,或
x
为无穷大且
y
为零,并且
- 如果 z 不是 NaN,则返回 NaN 并引发 FE_INVALID ,
- 如果 z 是 NaN,则返回 NaN 并可能引发 FE_INVALID 。
- 如果 x * y 是精确无穷大且 z 是符号相反的无穷大,则返回 NaN 并引发 FE_INVALID 。
- 如果 x 或 y 是 NaN,则返回 NaN。
- 如果 z 是 NaN,且 x * y 不是 0 * Inf 或 Inf * 0 ,则返回 NaN(不引发 FE_INVALID )。
注释
该操作在硬件中通常以 融合乘加 CPU指令实现。若硬件支持,预期会定义相应的 FP_FAST_FMA ? 宏,但许多实现即使未定义这些宏仍会使用CPU指令。
POSIX
(
fma
,
fmaf
,
fmal
)
额外规定,特定情况下返回
FE_INVALID
的情形属于定义域错误。
由于其无限的中间精度,
std::fma
是其他正确舍入数学运算(如
std::sqrt
甚至除法(在CPU未提供该功能时,例如
Itanium
))的常见构建模块。
与所有浮点表达式一样,表达式 x * y + z 可能被编译为融合乘加运算,除非 #pragma STDC FP_CONTRACT 处于关闭状态。
额外的重载不需要完全按照 (A) 提供。只需确保对于它们的第一个参数 num1 、第二个参数 num2 和第三个参数 num3 能够满足:
|
(C++23 前) |
|
如果
num1
、
num2
和
num3
具有算术类型,则
std
::
fma
(
num1, num2, num3
)
的效果等同于
std
::
fma
(
static_cast
<
/*common-floating-point-type*/
>
(
num1
)
,
如果不存在具有最高等级和子等级的此类浮点类型,则 重载决议 不会从提供的重载中产生可用的候选函数。 |
(C++23 起) |
示例
#include <cfenv> #include <cmath> #include <iomanip> #include <iostream> #ifndef __GNUC__ #pragma STDC FENV_ACCESS ON #endif int main() { // 演示 fma 与内置运算符的区别 const double in = 0.1; std::cout << "0.1 double is " << std::setprecision(23) << in << " (" << std::hexfloat << in << std::defaultfloat << ")\n" << "0.1*10 is 1.0000000000000000555112 (0x8.0000000000002p-3), " << "or 1.0 if rounded to double\n"; const double expr_result = 0.1 * 10 - 1; const double fma_result = std::fma(0.1, 10, -1); std::cout << "0.1 * 10 - 1 = " << expr_result << " : 1 subtracted after intermediate rounding\n" << "fma(0.1, 10, -1) = " << std::setprecision(6) << fma_result << " (" << std::hexfloat << fma_result << std::defaultfloat << ")\n\n"; // fma 在双精度算术中的应用 const double high = 0.1 * 10; const double low = std::fma(0.1, 10, -high); std::cout << "in double-double arithmetic, 0.1 * 10 is representable as " << high << " + " << low << "\n\n"; // 错误处理 std::feclearexcept(FE_ALL_EXCEPT); std::cout << "fma(+Inf, 10, -Inf) = " << std::fma(INFINITY, 10, -INFINITY) << '\n'; if (std::fetestexcept(FE_INVALID)) std::cout << " FE_INVALID raised\n"; }
可能的输出:
0.1 double is 0.10000000000000000555112 (0x1.999999999999ap-4)
0.1*10 is 1.0000000000000000555112 (0x8.0000000000002p-3), or 1.0 if rounded to double
0.1 * 10 - 1 = 0 : 1 subtracted after intermediate rounding
fma(0.1, 10, -1) = 5.55112e-17 (0x1p-54)
in double-double arithmetic, 0.1 * 10 is representable as 1 + 5.55112e-17
fma(+Inf, 10, -Inf) = -nan
FE_INVALID raised
参见
|
(C++11)
(C++11)
(C++11)
|
除法运算的有符号余数
(函数) |
|
(C++11)
(C++11)
(C++11)
|
有符号余数及除法运算的最后三位
(函数) |
|
C 文档
关于
fma
|
|