std::fma, std::fmaf, std::fmal
提供: cppreference.com
ヘッダ <cmath> で定義 | ||
float fma (float x, float y, float z ); float fmaf(float x, float y, float z ); | (1) | (C++11以上) |
double fma (double x, double y, double z ); | (2) | (C++11以上) |
longdouble fma (longdouble x, longdouble y, longdouble z ); longdouble fmal(longdouble x, longdouble y, longdouble z ); | (3) | (C++11以上) |
昇格後の型 fma ( 算術型1 x, 算術型2 y, 算術型3 z ); | (4) | (C++11以上) |
#define FP_FAST_FMA /* implementation-defined */ | (5) | (C++11以上) |
#define FP_FAST_FMAF /* implementation-defined */ | (6) | (C++11以上) |
#define FP_FAST_FMAL /* implementation-defined */ | (7) | (C++11以上) |
1-3) 無限の精度で行い結果の型に収まるよう一度だけ丸めたかのように、 (x*y)+ z を計算します。
4) 1-3) でカバーされない算術型の引数すべての組み合わせに対するオーバーロード集合または関数テンプレート。 いずれかの引数が整数型の場合、それは double にキャストされます。 他のいずれかの引数が longdouble の場合、戻り値型は longdouble になり、そうでなければ double になります。
5-7) マクロ定数
FP_FAST_FMAF
, FP_FAST_FMA
または FP_FAST_FMAL
が定義されている場合、関数 std::fma
は、それぞれ float, double, longdouble 型の引数に対して式 x*y+z よりも (精度が高いことに加えて) 高速に評価します。 定義されている場合、これらのマクロは整数の 1 に評価されます。目次 |
[編集]引数
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
は std::sqrt や除算 (Itanium など CPU によって提供されない場合) のような、正確に丸める他の数学演算の共通のビルディングブロックになります。
すべての浮動小数点演算と同様に、 #pragmaSTDC FP_CONTRACT が OFF でなければ、式 (x*y)+ z は融合積和演算としてコンパイルされるかもしれません。
[編集]例
Run this code
#include <iostream>#include <iomanip>#include <cmath>#include <cfenv>#pragma STDC FENV_ACCESS ONint main(){// fma と組み込みの演算子の差をデモンストレーションします。double in =0.1;std::cout<<"0.1 double is "<<std::setprecision(23)<< in <<" ("<<std::hexfloat<< in <<std::defaultfloat<<")\n"<<"0.1*10 is 1.0000000000000000555112 (0x8.0000000000002p-3), "<<"or 1.0 if rounded to double\n";double expr_result =0.1*10-1;double fma_result = fma(0.1, 10, -1);std::cout<<"0.1 * 10 - 1 = "<< expr_result <<" : 1 subtracted after intermediate rounding\n"<<"fma(0.1, 10, -1) = "<<std::setprecision(6)<< fma_result <<" ("<<std::hexfloat<< fma_result <<std::defaultfloat<<")\n\n"; // fma は double-double 算術で使用されます。double high =0.1*10;double low = fma(0.1, 10, -high);std::cout<<"in double-double arithmetic, 0.1 * 10 is representable as "<< high <<" + "<< low <<"\n\n"; // エラー処理。std::feclearexcept(FE_ALL_EXCEPT);std::cout<<"fma(+Inf, 10, -Inf) = "<< std::fma(INFINITY, 10, -INFINITY)<<'\n';if(std::fetestexcept(FE_INVALID))std::cout<<" FE_INVALID raised\n";}
出力例:
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 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
[編集]関連項目
(C++11)(C++11)(C++11) | 除算の符号付きの余りを計算します (関数) |
(C++11)(C++11)(C++11) | 除算の下位3ビットと符号付きの余りを計算します (関数) |
fma の C言語リファレンス |