命名空间
变体
操作

fma, fmaf, fmal

来自 cppreference.cn
< c‎ | numeric‎ | math
 
 
 
常用数学函数
函数
基本运算
(C99)
fma
(C99)
(C99)
(C99)(C99)(C99)(C23)
最大/最小值运算
(C99)
(C99)
指数函数
(C23)
(C99)
(C99)
(C23)
(C23)

(C99)
(C99)(C23)
(C23)
(C23)
幂函数
(C99)
(C23)
(C23)

(C99)
(C23)
(C23)
三角函数和双曲函数
(C23)
(C23)
(C23)
(C23)
(C99)
(C99)
(C99)
最近整数浮点
(C99)(C99)(C99)
(C99)

(C99)(C99)(C99)
(C23)(C23)(C23)(C23)
浮点操作
(C99)(C99)
(C99)(C23)
(C99)
窄化运算
(C23)
(C23)
(C23)
(C23)
(C23)
(C23)
量子和量子指数
十进制重编码函数
总阶数和有效载荷函数
分类
(C99)
(C99)
(C99)
(C23)
错误函数和伽玛函数
(C99)
(C99)
(C99)
(C99)
类型
宏常量
特殊浮点值
(C99)(C23)
参数和返回值
错误处理
快速运算指示符
 
定义于头文件 <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) 如果定义了宏常量 FP_FAST_FMAFP_FAST_FMAFFP_FAST_FMAL,则对应的函数 fmafmaffmal 的求值速度更快(除了更精确之外),而不是表达式 x * y + z,分别用于 doublefloatlong double 参数。 如果已定义,则这些宏求值为整数 1
7) 类型泛型宏:如果任何参数具有类型 long double,则调用 fmal。 否则,如果任何参数具有整数类型或类型 double,则调用 fma。 否则,调用 fmaf

内容

[edit] 参数

x, y, z - 浮点值

[edit] 返回值

如果成功,则返回 (x * y) + z 的值,如同以无限精度计算,并舍入一次以适应结果类型(或者,作为单个三元浮点运算计算)。

如果发生溢出的范围错误,则返回 ±HUGE_VAL±HUGE_VALF±HUGE_VALL

如果发生下溢的范围错误,则返回正确的值(舍入后)。

[edit] 错误处理

错误按照 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
  • 如果 xy 是 NaN,则返回 NaN。
  • 如果 z 是 NaN,并且 x * y 不是 0 * InfInf * 0,则返回 NaN(不带 FE_INVALID)。

[edit] 注解

此操作通常在硬件中作为融合乘加 CPU 指令实现。 如果硬件支持,则应定义相应的 FP_FAST_FMA* 宏,但即使未定义宏,许多实现也使用 CPU 指令。

POSIX 指定,当值 x * y 无效且 z 为 NaN 时,是域错误。

由于其无限的中间精度,fma 是其他正确舍入的数学运算(例如 sqrt 甚至除法)的常用构建块(在 CPU 未提供的情况下,例如 Itanium)。

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

[edit] 示例

#include <fenv.h>
#include <float.h>
#include <math.h>
#include <stdio.h>
// #pragma STDC FENV_ACCESS ON
 
int main(void)
{
    // demo the difference between fma and built-in operators
    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 use in double-double arithmetic
    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);
 
    // error handling
    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

[edit] 参考

  • C23 标准 (ISO/IEC 9899:2024)
  • 7.12.13.1 fma 函数 (p: TBD)
  • 7.25 类型泛型数学 <tgmath.h> (p: TBD)
  • F.10.10.1 fma 函数 (p: TBD)
  • C17 标准 (ISO/IEC 9899:2018)
  • 7.12.13.1 fma 函数 (p: 188-189)
  • 7.25 类型泛型数学 <tgmath.h> (p: 272-273)
  • F.10.10.1 fma 函数 (p: 386)
  • C11 标准 (ISO/IEC 9899:2011)
  • 7.12.13.1 fma 函数 (p: 258)
  • 7.25 类型泛型数学 <tgmath.h> (p: 373-375)
  • F.10.10.1 fma 函数 (p: 530)
  • C99 标准 (ISO/IEC 9899:1999)
  • 7.12.13.1 fma 函数 (p: 239)
  • 7.22 类型泛型数学 <tgmath.h> (p: 335-337)
  • F.9.10.1 fma 函数 (p: 466)

[edit] 参见

计算浮点除法运算的带符号余数
(函数) [编辑]
(C99)(C99)(C99)
计算带符号余数以及除法运算的最后三位
(函数) [编辑]
C++ 文档,关于 fma