Defined in header <cmath> | ||
---|---|---|
float fma ( float x, float y, float z ); | (1) | (since C++11) (constexpr since C++23) |
float fmaf( float x, float y, float z ); | (2) | (since C++11) (constexpr since C++23) |
double fma ( double x, double y, double z ); | (3) | (since C++11) (constexpr since C++23) |
long double fma ( long double x, long double y, long double z ); | (4) | (since C++11) (constexpr since C++23) |
long double fmal( long double x, long double y, long double z ); | (5) | (since C++11) (constexpr since C++23) |
Promoted fma ( Arithmetic1 x, Arithmetic2 y, Arithmetic3 z ); | (6) | (since C++11) (constexpr since C++23) |
#define FP_FAST_FMA /* implementation-defined */ | (7) | (since C++11) |
#define FP_FAST_FMAF /* implementation-defined */ | (8) | (since C++11) |
#define FP_FAST_FMAL /* implementation-defined */ | (9) | (since C++11) |
(x*y) + z
as if to infinite precision and rounded only once to fit the result type.double
. If any other argument is long double
, then the return type is long double
, otherwise it is double
.FP_FAST_FMA
, FP_FAST_FMAF
, or FP_FAST_FMAL
are defined, the function std::fma
evaluates faster (in addition to being more precise) than the expression x*y+z
for float
, double
, and long double
arguments, respectively. If defined, these macros evaluate to integer 1
.x, y, z | - | values of floating-point or integral types |
If successful, returns the value of (x*y) + z
as if calculated to infinite precision and rounded once to fit the result type (or, alternatively, calculated as a single ternary floating-point operation).
If a range error due to overflow occurs, ±HUGE_VAL
, ±HUGE_VALF
, or ±HUGE_VALL
is returned.
If a range error due to underflow occurs, the correct value (after rounding) is returned.
Errors are reported as specified in math_errhandling
.
If the implementation supports IEEE floating-point arithmetic (IEC 60559),
FE_INVALID
is raised FE_INVALID
may be raised x*y
is an exact infinity and z is an infinity with the opposite sign, NaN is returned and FE_INVALID
is raised x*y
aren't 0*Inf or Inf*0, then NaN is returned (without FE_INVALID
). This operation is commonly implemented in hardware as fused multiply-add CPU instruction. If supported by hardware, the appropriate FP_FAST_FMA?
macros are expected to be defined, but many implementations make use of the CPU instruction even when the macros are not defined.
POSIX additionally specifies that the situations specified to return FE_INVALID
are domain errors.
Due to its infinite intermediate precision, std::fma
is a common building block of other correctly-rounded mathematical operations, such as std::sqrt
or even the division (where not provided by the CPU, e.g. Itanium).
As with all floating-point expressions, the expression (x*y) + z
may be compiled as a fused multiply-add unless the #pragma
STDC FP_CONTRACT
is off.
#include <iostream> #include <iomanip> #include <cmath> #include <cfenv> #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"; }
Possible output:
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) | signed remainder of the division operation (function) |
(C++11)(C++11)(C++11) | signed remainder as well as the three last bits of the division operation (function) |
C documentation for fma |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/numeric/math/fma