命名空间
变体
操作

fma、fmaf、fmal

来自 cppreference.cn
< c‎ | 数值‎ | 数学
 
 
 
常用数学函数
函数
基本操作
(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 对于 doublefloatlong double 参数(分别为)的求值速度比表达式 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
    • 如果 z 是 NaN,则返回 NaN 并可能引发 FE_INVALID
  • 如果 x * y 是精确的无穷大且 z 是符号相反的无穷大,则返回 NaN 并引发 FE_INVALID
  • 如果 xy 是 NaN,则返回 NaN。
  • 如果 z 是 NaN,且 x * y 不是 0 * InfInf * 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 <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

[编辑] 参考

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

[编辑] 另请参阅

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