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 ); long double fma ( long double x, long double y, long double z ); |
(since C++11) (until C++23) | |
constexpr /* floating-point-type */ fma ( /* floating-point-type */ x, /* floating-point-type */ y, /* floating-point-type */ z ); | (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) |
Additional overloads | ||
Defined in header <cmath> | ||
template< class Arithmetic1, class Arithmetic2, class Arithmetic3 > /* common-floating-point-type */ fma( Arithmetic1 x, Arithmetic2 y, Arithmetic3 z ); | (A) | (since C++11) (constexpr since C++23) |
x * y + z
as if to infinite precision and rounded only once to fit the result type. The library provides overloads of std::fma
for all cv-unqualified floating-point types as the type of the parameters x
, y
and z
.(since C++23)
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
.Parameters
x, y, z | - | floating-point or integer values |
Return value
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.
Error handling
Errors are reported as specified in math_errhandling
.
If the implementation supports IEEE floating-point arithmetic (IEC 60559),
- If
x
is zero andy
is infinite or ifx
is infinite andy
is zero, and- if
z
is not a NaN, then NaN is returned andFE_INVALID
is raised. - if
z
is a NaN, then NaN is returned andFE_INVALID
may be raised.
- if
- If
x * y
is an exact infinity andz
is an infinity with the opposite sign, NaN is returned andFE_INVALID
is raised. - If
x
ory
are NaN, NaN is returned. - If
z
is NaN, andx * y
is not 0 * Inf or Inf * 0, then NaN is returned (withoutFE_INVALID
).
Notes
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 (fma
, fmaf
, fmal
) 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.
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 If no such floating-point type with the greatest rank and subrank exists, then overload resolution does not result in a usable candidate from the overloads provided. | (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 |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/numeric/math/fma