名稱空間
變體
操作

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

來自 cppreference.com
< cpp‎ | 數值‎ | 數學
 
 
 
常用數學函式
函式
基本操作
(C++11)  
(C++11)
fma
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)(C++11)(C++11)
指數函式
(C++11)
(C++11)

(C++11)
(C++11)
冪函式
(C++11)
(C++11)
三角
雙曲函式
(C++11)
(C++11)
(C++11)

誤差函式和伽馬函式
(C++11)
(C++11)
(C++11)
(C++11)
取整浮點運算
(C++11)(C++11)(C++11)
(C++11)
(C++11)
(C++11)(C++11)(C++11)
浮點操縱函式
(C++11)(C++11)
(C++11)
(C++11)
(C++11)(C++11)
(C++11)
分類和比較
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
型別
(C++11)
(C++11)
(C++11)
宏常量
分類
(C++11)(C++11)(C++11)(C++11)(C++11)


 
定義於標頭檔案 <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 /* 浮點型別 */

            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 >

/* common-floating-point-type */

    fma( Arithmetic1 x, Arithmetic2 y, Arithmetic3 z );
(A) (C++11 起)
(自 C++23 起為 constexpr)
1-3) 計算 x * y + z,如同以無限精度計算並僅舍入一次以適應結果型別。 庫為所有 cv-unqualified 浮點型別(作為引數 xyz 的型別)提供了 std::fma 的過載。(自 C++23 起)
4-6) 如果宏常量 FP_FAST_FMAFP_FAST_FMAFFP_FAST_FMAL 已定義,則函式 std::fmadoublefloatlong 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
  • 如果 xy 是 NaN,則返回 NaN。
  • 如果 z 是 NaN,並且 x * y 不是 0 * InfInf * 0,則返回 NaN(不引發 FE_INVALID)。

[編輯] 注意

此操作通常在硬體中實現為融合乘加 CPU 指令。如果硬體支援,則預期會定義相應的 FP_FAST_FMA? 宏,但許多實現即使在未定義宏的情況下也使用 CPU 指令。

POSIX fmafmaffmal還指定,指定返回 FE_INVALID 的情況是域錯誤。

由於其無限中間精度,std::fma 是其他正確舍入的數學運算(例如 std::sqrt 甚至除法(如果 CPU 不提供,例如 安騰))的常見構建塊。

與所有浮點表示式一樣,表示式 x * y + z 可能會被編譯為融合乘加,除非 #pragma STDC FP_CONTRACT 關閉。

不需要完全按照 (A) 提供額外的過載。它們只需足以確保對於它們的第一個引數 num1、第二個引數 num2 和第三個引數 num3

  • 如果 num1num2num3 的型別為 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))
    相同的效果。
  • 否則,如果 num1num2num3 的型別為 float,則 std::fma(num1, num2, num3) 具有與 std::fma(static_cast<float>(num1),
             static_cast<float>(num2),
             static_cast<float>(num3))
    相同的效果。
(直至 C++23)

如果 num1num2num3 具有算術型別,則 std::fma(num1, num2, num3) 具有與 std::fma(static_cast</*common-floating-point-type*/>(num1),
         static_cast</*common-floating-point-type*/>(num2),
         static_cast</*common-floating-point-type*/>(num3))
相同的效果,其中 /*common-floating-point-type*/ 是在 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)
帶符號餘數以及除法運算的最後三位
(函式) [編輯]
C 文件 用於 fma