名前空間
変種
操作

std::fma, std::fmaf, std::fmal

From cppreference.com
< cpp‎ | numeric‎ | math
 
 
 
 
ヘッダー <cmath> で定義
(1)
float       fma ( float x, float y, float z );

double      fma ( double x, double y, double z );

long double fma ( long double x, long double y, long double z );
(C++11以降)
(C++23まで)
constexpr /* floating-point-type */

            fma ( /* 浮動小数点型 */ x,
                  /* 浮動小数点型 */ y,

                  /* 浮動小数点型 */ z );
(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 >

/* 共通浮動小数点型 */

    fma( 算術型1 x, 算術型2 y, 算術型3 z );
(A) (C++11以降)
(C++23 以降 constexpr)
1-3) 無限精度で計算し、結果型に収めるために一度だけ丸めるかのように、x * y + z を計算します。ライブラリは、パラメータ xyz の型として、すべての cv 修飾されていない浮動小数点型に対する std::fma のオーバーロードを提供します。(C++23 以降)
4-6) マクロ定数 FP_FAST_FMAFP_FAST_FMAF、または FP_FAST_FMAL が定義されている場合、関数 std::fma は、それぞれ doublefloatlong double の引数に対して、式 x * y + z よりも高速(かつ高精度)に評価されます。定義されている場合、これらのマクロは整数 1 に評価されます。
A) その他の算術型の組み合わせすべてに対して、追加のオーバーロードが提供されます。

目次

[編集] パラメータ

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 * y0 * 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 に対して、以下のことを保証するのに十分であるだけでよいです。

  • num1num2、または num3 の型が long double の場合、std::fma(num1, num2, num3)std::fma(static_cast<long double>(num1), static_cast<long double>(num2), static_cast<long double>(num3)) と同等の効果を持ちます。
  • それ以外の場合、num1num2、および/または num3 の型が double または整数型の場合、std::fma(num1, num2, num3)std::fma(static_cast<double>(num1), static_cast<double>(num2), static_cast<double>(num3)) と同等の効果を持ちます。
  • それ以外の場合、num1num2、または num3 の型が float の場合、std::fma(num1, num2, num3)std::fma(static_cast<float>(num1), static_cast<float>(num2), static_cast<float>(num3)) と同等の効果を持ちます。
(C++23まで)

num1num2、および num3 が算術型の場合、std::fma(num1, num2, num3)std::fma(static_cast</*共通浮動小数点型*/>(num1), static_cast</*共通浮動小数点型*/>(num2), static_cast</*共通浮動小数点型*/>(num3)) と同等の効果を持ちます。ここで、/*共通浮動小数点型*/ は、num1num2num3 の型の中で、最も高い 浮動小数点変換ランク と最も高い 浮動小数点変換サブランク を持つ浮動小数点型です。整数型の引数は、double と同じ浮動小数点変換ランクを持つとみなされます。

そのような最高のランクとサブランクセを持つ浮動小数点型が存在しない場合、オーバーロード解決は提供されたオーバーロードから使用可能な候補を導出しません。

(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ビット
(関数) [編集]
English 日本語 中文(简体) 中文(繁體)