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 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 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 is raised,
- if z is a NaN, then NaN is returned and FE_INVALID may be raised.
- If x * y is an exact infinity and z is an infinity with the opposite sign, NaN is returned and FE_INVALID is raised.
- 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 ? 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
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 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
|