std::fma,std::fmaf,std::fmal (3) - Linux Manuals

std::fma,std::fmaf,std::fmal: std::fma,std::fmaf,std::fmal

NAME

std::fma,std::fmaf,std::fmal - std::fma,std::fmaf,std::fmal

Synopsis


Defined in header <cmath>
float fma ( float x, float y, float z ); (1) (since C++11)
float fmaf( float x, float y, float z );
double fma ( double x, double y, double z ); (2) (since C++11)
long double fma ( long double x, long double y, long double z ); (3) (since C++11)
long double fmal( long double x, long double y, long double z );
Promoted fma ( Arithmetic1 x, Arithmetic2 y, Arithmetic3 z ); (4) (since C++11)
#define FP_FAST_FMA /* implementation-defined */ (5) (since C++11)
#define FP_FAST_FMAF /* implementation-defined */ (6) (since C++11)
#define FP_FAST_FMAL /* implementation-defined */ (7) (since C++11)


1-3) Computes (x*y) + z as if to infinite precision and rounded only once to fit the result type.
4) A set of overloads or a function template for all combinations of arguments of arithmetic_type not covered by 1-3). If any argument has integral_type, it is cast to double. If any other argument is long double, then the return type is long double, otherwise it is double.
5-7) If the macro constants FP_FAST_FMAF, FP_FAST_FMA, 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 - values of floating-point or integral_types

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 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)

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_additionally_specifies that the situations specified to return FE_INVALID are domain errors.
Due to its infinite intermediate precision, 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.

Example


// Run this code


  #include <iostream>
  #include <iomanip>
  #include <cmath>
  #include <cfenv>
  #pragma STDC FENV_ACCESS ON
  int main()
  {
      // demo the difference between fma and built-in operators
      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";
      double expr_result = 0.1 * 10 - 1;
      double fma_result = 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
      double high = 0.1 * 10;
      double low = 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


remainder
remainderf
remainderl signed remainder of the division operation
           (function)
(C++11)
(C++11)
(C++11)


remquo
remquof
remquol signed remainder as well as the three last bits of the division operation
           (function)
(C++11)
(C++11)
(C++11)