fma, fmaf, fmal
From 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 /* 実装定義 */ |
(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_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 の 融合積和演算 (fused multiply-add) 命令としてハードウェアで実装されることが一般的です。ハードウェアがサポートしている場合、適切な 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 The fma functions (p: TBD)
- 7.25 Type-generic math <tgmath.h> (p: TBD)
- F.10.10.1 The fma functions (p: TBD)
- C17標準 (ISO/IEC 9899:2018)
- 7.12.13.1 The fma functions (p: 188-189)
- 7.25 型総称数学関数 <tgmath.h> (p: 272-273)
- F.10.10.1 The fma functions (p: 386)
- C11標準 (ISO/IEC 9899:2011)
- 7.12.13.1 The fma functions (p: 258)
- 7.25 型総称数学関数 <tgmath.h> (p: 373-375)
- F.10.10.1 The fma functions (p: 530)
- C99標準 (ISO/IEC 9899:1999)
- 7.12.13.1 The fma functions (p: 239)
- 7.22 型総称数学関数 <tgmath.h> (p: 335-337)
- F.9.10.1 The fma functions (p: 466)
[編集] 関連項目
| (C99)(C99)(C99) |
浮動小数点除算演算の符号付き余りを計算する (関数) |
| (C99)(C99)(C99) |
符号付き余りおよび除算演算の最後の3ビットを計算する (関数) |
| C++ ドキュメント fma
| |