std::fma, std::fmaf, std::fmal
Defined in header <cmath>
|
||
(1) | ||
float fma (
float x, float y, float z )
;
double fma ( double x, double y, double z ); |
(since C++11) (until C++23) |
|
constexpr
/* floating-point-type */
fma ( /* floating-point-type */ x, |
(since C++23) | |
float fmaf(
float x, float y, float z )
;
|
(2) | (since C++11) (constexpr since C++23) |
long
double fmal(
long
double x, long
double y, long
double z )
;
|
(3) | (since C++11) (constexpr since C++23) |
#define FP_FAST_FMA /* implementation-defined */ |
(4) | (since C++11) |
#define FP_FAST_FMAF /* implementation-defined */ |
(5) | (since C++11) |
#define FP_FAST_FMAL /* implementation-defined */ |
(6) | (since C++11) |
Defined in header <cmath>
|
||
template
<
class Arithmetic1, class Arithmetic2, class Arithmetic3 >
/* common-floating-point-type */ |
(A) | (since C++11) (constexpr since C++23) |
std::fma
for all cv-unqualified floating-point types as the type of the parameters x, y and z
(since C++23)
std::fma
evaluates faster (in addition to being more precise) than the expression x * y + z for double, float, and long double arguments, respectively. If defined, these macros evaluate to integer 1
Parameters
x, y, z | - | floating-point or integer values |
Return value
If successful, returns the value of x * y + z
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.
Error handling
Errors are reported as specified in math_errhandling.
If the implementation supports IEEE floating-point arithmetic (IEC 60559),
- If x is zero and y is infinite or if x is infinite and y is zero, and
- if z is not a NaN, then NaN is returned and FE_INVALID
- if z is a NaN, then NaN is returned and FE_INVALID
- If x * y is an exact infinity and z is an infinity with the opposite sign, NaN is returned and FE_INVALID
- If x or y are NaN, NaN is returned.
- If z is NaN, and x * y is not 0 * Inf or Inf * 0, then NaN is returned (without FE_INVALID
Notes
This operation is commonly implemented in hardware as fused multiply-add CPU instruction. If supported by hardware, the appropriate FP_FAST_FMA?
POSIX (fma
, fmaf
, fmal
) additionally specifies that the situations specified to return FE_INVALID
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
The additional overloads are not required to be provided exactly as (A). They only need to be sufficient to ensure that for their first argument num1, second argument num2 and third argument num3
|
(until C++23) |
If num1, num2 and num3 have arithmetic types, then std::fma(num1, num2, num3) has the same effect as
std::
fma
(
static_cast
<
/*common-floating-point-type*/
>
(num1)
If no such floating-point type with the greatest rank and subrank exists, then overload resolution |
(since C++23) |
Example
#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"; }
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
See also
(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
|