命名空间
变体
操作

fma、fmaf、fmal

来自 cppreference.com
< c‎ | numeric‎ | math
 
 
 
常用数学函数
类型
(C99)(C99)    

(C99)(C99)    

函数
基本操作
(C99)
fma
(C99)
(C99)
(C99)(C99)(C99)(C23)
最大/最小操作
(C99)
(C23)    
指数函数
(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)
(C99)
(C99)(C99)(C99)
(C23)(C23)(C23)(C23)
浮点操作函数
(C99)(C99)
(C99)(C23)
(C99)
缩窄操作
(C23)
(C23)
(C23)
(C23)
(C23)
(C23)
量子和量子指数函数
十进制重新编码函数
总排序和有效负载函数
分类
(C99)
(C99)
(C99)
(C23)
宏常量
特殊浮点值
(C99)(C23)
参数和返回值
(C99)(C99)(C99)(C99)(C99)    
错误处理
(C99)    

快速操作指示器
FP_FAST_FMAFFP_FAST_FMA
(C99)(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  /* 实现定义 */
(4) (自 C99)
#define FP_FAST_FMAF /* 实现定义 */
(5) (自 C99)
#define FP_FAST_FMAL /* 实现定义 */
(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

内容

[编辑] 参数

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 函数 (p: 待定)
  • 7.25 类型泛型数学 <tgmath.h> (p: 待定)
  • F.10.10.1 fma 函数 (p: 待定)
  • 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)

[编辑] 另请参阅

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