std::fma, std::fmaf, std::fmal
| ヘッダー <cmath> で定義 |
||
| (1) | ||
float fma ( float x, float y, float z ); double fma ( double x, double y, double z ); |
(C++11以降) (C++23まで) |
|
| constexpr /* floating-point-type */ fma ( /* 浮動小数点型 */ x, |
(C++23から) | |
| float fmaf( float x, float y, float z ); |
(2) | (C++11以降) (C++23 以降 constexpr) |
| long double fmal( long double x, long double y, long double z ); |
(3) | (C++11以降) (C++23 以降 constexpr) |
| #define FP_FAST_FMA /* 実装定義 */ |
(4) | (C++11以降) |
| #define FP_FAST_FMAF /* 実装定義 */ |
(5) | (C++11以降) |
| #define FP_FAST_FMAL /* 実装定義 */ |
(6) | (C++11以降) |
| ヘッダー <cmath> で定義 |
||
| template< class Arithmetic1, class Arithmetic2, class Arithmetic3 > /* 共通浮動小数点型 */ |
(A) | (C++11以降) (C++23 以降 constexpr) |
x * y + z を計算します。ライブラリは、パラメータ x、y、z の型として、すべての cv 修飾されていない浮動小数点型に対する std::fma のオーバーロードを提供します。(C++23 以降)FP_FAST_FMA、FP_FAST_FMAF、または FP_FAST_FMAL が定義されている場合、関数 std::fma は、それぞれ double、float、long double の引数に対して、式 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が発生します。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 の (fma, fmaf, fmal) では、さらに FE_INVALID を返すように指定されている状況は、ドメインエラーであると規定しています。
無限の中間精度により、std::fma は、std::sqrt や、CPU で提供されていない場合の除算(例: Itanium)などの、正しく丸められた他の数学的演算の一般的な構成要素となっています。
すべての浮動小数点式と同様に、式 x * y + z は、 #pragma STDC FP_CONTRACT がオフでない限り、融合積和演算としてコンパイルされる可能性があります。
追加のオーバーロードは、(A) とまったく同じように提供される必要はありません。それらは、最初の引数 num1、2番目の引数 num2、3番目の引数 num3 に対して、以下のことを保証するのに十分であるだけでよいです。
|
(C++23まで) |
|
そのような最高のランクとサブランクセを持つ浮動小数点型が存在しない場合、オーバーロード解決は提供されたオーバーロードから使用可能な候補を導出しません。 |
(C++23から) |
[編集] 例
#include <cfenv> #include <cmath> #include <iomanip> #include <iostream> #ifndef __GNUC__ #pragma STDC FENV_ACCESS ON #endif int main() { // demo the difference between fma and built-in operators const 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"; const double expr_result = 0.1 * 10 - 1; const double fma_result = std::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 is used in double-double arithmetic const double high = 0.1 * 10; const double low = std::fma(0.1, 10, -high); std::cout << "in double-double arithmetic, 0.1 * 10 is representable as " << high << " + " << low << "\n\n"; // error handling 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ビット (関数) |
| C のドキュメント (
fma) | |