fma, fmaf, fmal

来自cppreference.com
< c‎ | numeric‎ | math
 
 
 
常用数学函数
函数
基本运算
remainder(C99)
remquo(C99)
fma(C99)
fmax(C99)
fmin(C99)
fdim(C99)
nan
nanf
nanl
(C99)
(C99)
(C99)
指数函数
exp
exp2(C99)
expm1(C99)
log
log10
log1p(C99)
log2(C99)
幂函数
sqrt
cbrt(C99)
hypot(C99)
pow
三角及双曲函数
sinh
cosh
tanh
asinh(C99)
acosh(C99)
atanh(C99)
误差及伽马函数
erf(C99)
erfc(C99)
lgamma(C99)
tgamma(C99)
临近整数的浮点运算
ceil
floor
round
lround
llround
(C99)
(C99)
(C99)
trunc(C99)
nearbyint(C99)
rint
lrint
llrint
(C99)
(C99)
(C99)
浮点数操作函数
ldexp
scalbn
scalbln
(C99)
(C99)
ilogb(C99)
logb(C99)
分类
fpclassify(C99)
isfinite(C99)
isinf(C99)
isnan(C99)
isnormal(C99)
signbit(C99)
宏常量
 
定义于头文件 <math.h>
float       fmaf( float x, float y, float z );
(1) (C99起)
double      fma( double x, double y, double z );
(2) (C99起)
long double fmal( long double x, long double y, long double z );
(3) (C99起)
#define FP_FAST_FMA  /* implementation-defined */
(4) (C99起)
#define FP_FAST_FMAF /* implementation-defined */
(5) (C99起)
#define FP_FAST_FMAL /* implementation-defined */
(6) (C99起)
定义于头文件 <tgmath.h>
#define fma( x, y, z )
(7) (C99起)
1-3) 像有无限精度一样计算(x*y) + z,并只舍入一次以符合结果类型。
4-6) 各自对于floatdoublelong double参数,若宏常量FP_FAST_FMAFFP_FAST_FMAFP_FAST_FMAL得到定义,则对应的函数fmaffmafmal求值快于(另外精度也高于)表达式x*y+z。若被定义,则这些宏求值得整数1
7) 通用类型宏:若任一参数拥有long double类型,则调用fmal。否则若任一参数拥有整数类型或double类型则调用fma。否则调用fmaf

目录

[编辑] 参数

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
  • 若x为零而y为无穷大或x为无穷大而y为零,且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指定x*y非法且z是NaN的情况为定义域错误。

因为其无限中间精度,fma通常用于构建其他正确舍入的数学运算块,譬如sqrt甚至是除法(当不为CPU所提供时,例如Itanium)。

与所有浮点表达式一样,表达式(x*y) + z可以编译成融合乘加,除非#pragma STDC FP_CONTRACT是关闭的。

[编辑] 示例

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
int main(void)
{
    // 演示fma和内建运算符之间的区别
    double in = 0.1;
    printf("0.1 double is %.23f (%a)\n", in, in);
    printf("0.1*10 is 1.0000000000000000555112 (0x8.0000000000002p-3),"
           " or 1.0 if rounded to double\n");
    double expr_result = 0.1 * 10 - 1;
    printf("0.1 * 10 - 1 = %g : 1 subtracted after "
           "intermediate rounding to 1.0\n", expr_result);
    double fma_result = fma(0.1, 10, -1);
    printf("fma(0.1, 10, -1) = %g (%a)\n", fma_result, fma_result);
 
    // fma使用double-double算术
    printf("\nin double-double arithmetic, 0.1 * 10 is representable as ");
    double high = 0.1 * 10;
    double low = fma(0.1, 10, -high);
    printf("%g + %g\n\n", high, low);
 
    //错误处理
    feclearexcept(FE_ALL_EXCEPT);
    printf("fma(+Inf, 10, -Inf) = %f\n", fma(INFINITY, 10, -INFINITY));
    if(fetestexcept(FE_INVALID)) puts("    FE_INVALID raised");
}

可能的输出:

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 to 1.0
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

[编辑] 参考

  • C11 standard (ISO/IEC 9899:2011):
  • 7.12.13.1 The fma functions (p: 258)
  • 7.25 Type-generic math <tgmath.h> (p: 373-375)
  • F.10.10.1 The fma functions (p: 530)
  • C99 standard (ISO/IEC 9899:1999):
  • 7.12.13.1 The fma functions (p: 239)
  • 7.22 Type-generic math <tgmath.h> (p: 335-337)
  • F.9.10.1 The fma functions (p: 466)

[编辑] 参阅

计算浮点除法运算的带符号余数
(函数) [edit]
(C99)
(C99)
(C99)
计算除法运算的带符号余数,以及商的后三位
(函数) [edit]
fmaC++文档