fma, fmaf, fmal
Header: <math.h>
1-3) Computes (x * y) + z as if to infinite precision and rounded only once to fit the result type.
# Declarations
float fmaf( float x, float y, float z );
(since C99)
double fma( double x, double y, double z );
(since C99)
long double fmal( long double x, long double y, long double z );
(since C99)
#define FP_FAST_FMA /* implementation-defined */
(since C99)
#define FP_FAST_FMAF /* implementation-defined */
(since C99)
#define FP_FAST_FMAL /* implementation-defined */
(since C99)
#define fma( x, y, z )
(since C99)
# Parameters
x, y, z: floating-point 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).
# 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 specifies that the situation where the value x * y is invalid and z is a NaN is a domain error.
Due to its infinite intermediate precision, fma is a common building block of other correctly-rounded mathematical operations, such as 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 mutiply-add unless the #pragma STDC FP_CONTRACT is off.
# Example
#include <fenv.h>
#include <float.h>
#include <math.h>
#include <stdio.h>
// #pragma STDC FENV_ACCESS ON
int main(void)
{
// demo the difference between fma and built-in operators
double in = 0.1;
printf("0.1 double is %.23f (%a)\n", in, in);
printf("0.1*10 is 1.0000000000000000555112 (0x8.0000000000002p-3),"
" or 1.0 if rounded to double\n");
double expr_result = 0.1 * 10 - 1;
printf("0.1 * 10 - 1 = %g : 1 subtracted after "
"intermediate rounding to 1.0\n", expr_result);
double fma_result = fma(0.1, 10, -1);
printf("fma(0.1, 10, -1) = %g (%a)\n", fma_result, fma_result);
// fma use in double-double arithmetic
printf("\nin double-double arithmetic, 0.1 * 10 is representable as ");
double high = 0.1 * 10;
double low = fma(0.1, 10, -high);
printf("%g + %g\n\n", high, low);
// error handling
feclearexcept(FE_ALL_EXCEPT);
printf("fma(+Inf, 10, -Inf) = %f\n", fma(INFINITY, 10, -INFINITY));
if (fetestexcept(FE_INVALID))
puts(" FE_INVALID raised");
}