fma, fmaf, fmal

From cppreference.com
< c‎ | numeric‎ | math
 
 
 
Common mathematical functions
Functions
Basic operations
(C99)
(C99)
fma
(C99)
(C99)
(C99)
(C99)
(C99)(C99)(C99)
Exponential functions
(C99)
(C99)
(C99)
(C99)
Power functions
(C99)
(C99)
Trigonometric and hyperbolic functions
(C99)
(C99)
(C99)
Error and gamma functions
(C99)
(C99)
(C99)
(C99)
Nearest integer floating point operations
(C99)(C99)(C99)
(C99)
(C99)
(C99)(C99)(C99)
Floating point manipulation functions
(C99)(C99)
(C99)
(C99)
Classification
(C99)
(C99)
(C99)
(C99)
(C99)
(C99)
Macro constants
 
Defined in header <math.h>
float       fmaf( float x, float y, float z );
(1) (since C99)
double      fma( double x, double y, double z );
(2) (since C99)
long double fmal( long double x, long double y, long double z );
(3) (since C99)
#define FP_FAST_FMA  /* implementation-defined */
(4) (since C99)
#define FP_FAST_FMAF /* implementation-defined */
(5) (since C99)
#define FP_FAST_FMAL /* implementation-defined */
(6) (since C99)
Defined in header <tgmath.h>
#define fma( x, y )
(7) (since C99)
1-3) Computes (x*y) + z as if to infinite precision and rounded only once to fit the result type.
4-6) If the macro constants FP_FAST_FMAF, FP_FAST_FMA, or FP_FAST_FMAL are defined, the corresponding function fmaf, fma, or fmal 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.
7) Type-generic macro: If any argument has type long double, fminl is called. Otherwise, if any argument has integer type or has type double, fmin is called. Otherwise, fminf is called.

Contents

[edit] Parameters

x, y, z - floating point values

[edit] 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.

[edit] 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 z is not a NaN, then NaN is returned and FE_INVALID is raised
  • If x is zero and y is infinite or if x is infinite and y is zero, and 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 aren't 0*Inf or Inf*0, then NaN is returned (without FE_INVALID)

[edit] 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)

[edit] Example

#include <stdio.h>
#include <math.h>
#include <float.h>
#include <fenv.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");
}

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 to 1.0
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

[edit] See also

computes signed remainder of the floating-point division operation
(function)
(C99)(C99)(C99)
computes signed remainder as well as the three last bits of the division operation
(function)