fma, fmaf, fmal
提供: cppreference.com
<tbody>
</tbody>
| ヘッダ <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_FMAF, FP_FAST_FMA または FP_FAST_FMAL が定義されている場合、対応する関数 fmaf, fma または fmal は、それぞれ float, double, 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 が発生します。
- x がゼロで y が無限大、または x が無限大で y がゼロで、かつ 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 は FE_INVALID を返すと規定されている状況は定義域エラーであると規定しています。
その無限の中間精度のため、 fma は sqrt や除算 (Itanium など CPU によって提供されない場合) のような、正確に丸める他の数学演算の共通のビルディングブロックになります。
すべての浮動小数点演算と同様に、 #pragma STDC FP_CONTRACT が OFF でなければ、式 (x*y) + z は融合積和演算としてコンパイルされるかもしれません。
例
Run this code
#include <stdio.h>
#include <math.h>
#include <float.h>
#include <fenv.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
参考文献
- C11 standard (ISO/IEC 9899:2011):
- 7.12.13.1 The fma functions (p: 258)
- 7.25 Type-generic math <tgmath.h> (p: 373-375)
- F.10.10.1 The fma functions (p: 530)
- C99 standard (ISO/IEC 9899:1999):
- 7.12.13.1 The fma functions (p: 239)
- 7.22 Type-generic math <tgmath.h> (p: 335-337)
- F.9.10.1 The fma functions (p: 466)
関連項目
(C99)(C99)(C99) |
浮動小数点除算の符号付きの余りを計算します (関数) |
(C99)(C99)(C99) |
除算の下位3ビットと符号付きの余りを計算します (関数) |
fma の C++リファレンス
| |