std::fma
性病:FMA
Defined in header | | |
---|---|---|
float fma( float x, float y, float z | (1) | (since C++11) |
double fma( double x, double y, double z | (2) | (since C++11) |
long double fma( long double x, long double y, long double z | (3) | (since C++11) |
Promoted fma( Arithmetic1 x, Arithmetic2 y, Arithmetic3 z | (4) | (since C++11) |
#define FP_FAST_FMA /* implementation-defined */ | (5) | (since C++11) |
#define FP_FAST_FMAF /* implementation-defined */ | (6) | (since C++11) |
#define FP_FAST_FMAL /* implementation-defined */ | (7) | (since C++11) |
1-3%29次计算(x*y) + z
好像要达到无限的精度,并且只舍入一次,以适应结果类型。
的所有参数组合的一组重载或函数模板算术类型不包括在1-3%29。如果有任何争论积分型,它被铸造成double
.如果任何其他论点是long double
,则返回类型为long double
,否则就是double
...
5-7%29如果宏常量FP_FAST_FMAF
,,,FP_FAST_FMA
,或FP_FAST_FMAL
定义的函数std::fma
除了比表达式更精确的%29之外,计算速度更快的%28x*y+z
为float
,,,double
,和long double
分别争论。如果定义了这些宏,则这些宏将计算为整数。1
...
参数
x, y, z | - | values of floating-point or integral types |
---|
返回值
如果成功,则返回(x*y) + z
似乎计算到无限精度,并舍入一次以适应结果类型%28,或者,或者,计算为单个三元浮点操作%29。
如果溢出导致范围错误,±HUGE_VAL
,,,±HUGE_VALF
,或±HUGE_VALL
会被归还。
如果由于下流发生范围错误,则返回舍入%29后的正确值%28。
错误处理
错误按数学[医]错误处理...
如果实现支持ieee浮点算法%28IEC 60559%29,
- 如果x是零,y是无限的,或者x是无穷的,y是零,而z不是NaN,则NaN返回
FE_INVALID
提出来
- 如果x是零,y是无穷的,或者x是无穷的,y是零,z是NaN,则NaN返回
FE_INVALID
可能被提高
- 如果x%2Ay是一个精确的无穷大,z是带相反符号的无穷大,NaN返回,
FE_INVALID
提出来
- 如果x或y为nan,则返回nan。
- 如果z是nan,则x%2Ay=%27T0%2Ainf或inf%2A0,则NaN返回%28而不使用FE。[医]无效%29
注记
此操作通常在硬件中实现,如融合相加CPU指令。如果硬件支持,则适当的FP_FAST_FMA*
宏是需要定义的,但是即使没有定义宏,许多实现也会使用CPU指令。
POSIX额外指定指定返回的情况FE_INVALID
是域错误。
由于其无限的中间精度,fma
是其他正确四舍五入的数学操作的一个常见的构建块,例如std::sqrt
甚至分割%28,在CPU不提供的地方,例如Itanium%29。
与所有浮点表达式一样,表达式(x*y) + z
可以编译为一个融合的乘法添加,除非#语用STDC FP_CONTRACT
已经关机了。
例
二次
#include <iostream>
#include <iomanip>
#include <cmath>
#include <cfenv>
#pragma STDC FENV_ACCESS ON
int main()
{
// demo the difference between fma and built-in operators
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";
double expr_result = 0.1 * 10 - 1;
double fma_result = 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 is used in double-double arithmetic
double high = 0.1 * 10;
double low = fma(0.1, 10, -high
std::cout << "in double-double arithmetic, 0.1 * 10 is representable as "
<< high << " + " << low << "\n\n";
// error handling
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
二次
另见
remainder (C++11) | signed remainder of the division operation (function) |
---|---|
remquo (C++11) | signed remainder as well as the three last bits of the division operation (function) |
c FMA文件
© cppreference.com
在CreativeCommonsAttribution下授权-ShareAlike未移植许可v3.0。