fma、fmaf、fmal
來自 cppreference.com
定義於標頭檔案 <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_FMA
、FP_FAST_FMAF
或 FP_FAST_FMAL
已定義,則對應的函式 fma
、fmaf
或 fmal
對於 double、float 和 long 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。
- 如果 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 <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) |
計算浮點除法運算的帶符號餘數 (函式) |
(C99)(C99)(C99) |
計算帶符號餘數以及除法運算的最後三位 (函式) |
C++ 文件 適用於 fma
|