Namespaces
Variants

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

From cppreference.net
Common mathematical functions
Nearest integer floating point operations
(C++11)
(C++11)
(C++11) (C++11) (C++11)
Floating point manipulation functions
(C++11) (C++11)
(C++11)
(C++11)
Classification and comparison
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
Types
(C++11)
(C++11)
(C++11)
Macro constants
Definido en el encabezado <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 ) ;
(desde C++11)
(hasta C++23)
constexpr /* floating-point-type */

fma ( /* floating-point-type */ x,
/* floating-point-type */ y,

/* floating-point-type */ z ) ;
(desde C++23)
float fmaf ( float x, float y, float z ) ;
(2) (desde C++11)
(constexpr desde C++23)
long double fmal ( long double x, long double y, long double z ) ;
(3) (desde C++11)
(constexpr desde C++23)
#define FP_FAST_FMA  /* implementation-defined */
(4) (desde C++11)
#define FP_FAST_FMAF /* implementation-defined */
(5) (desde C++11)
#define FP_FAST_FMAL /* implementation-defined */
(6) (desde C++11)
Definido en el encabezado <cmath>
template < class Arithmetic1, class Arithmetic2, class Arithmetic3 >

/* common-floating-point-type */

fma ( Arithmetic1 x, Arithmetic2 y, Arithmetic3 z ) ;
(A) (desde C++11)
(constexpr desde C++23)
1-3) Calcula x * y + z como si fuera con precisión infinita y redondeado solo una vez para ajustarse al tipo de resultado. La biblioteca proporciona sobrecargas de std::fma para todos los tipos de punto flotante sin calificación cv como el tipo de los parámetros x , y y z . (desde C++23)
4-6) Si las constantes de macro FP_FAST_FMA , FP_FAST_FMAF , o FP_FAST_FMAL están definidas, la función std::fma se evalúa más rápido (además de ser más precisa) que la expresión x * y + z para argumentos de tipo double , float , y long double , respectivamente. Si están definidas, estas macros se evalúan al entero 1 .
A) Se proporcionan sobrecargas adicionales para todas las demás combinaciones de tipos aritméticos.

Contenidos

Parámetros

x, y, z - valores de punto flotante o enteros

Valor de retorno

Si tiene éxito, devuelve el valor de x * y + z como si se calculara con precisión infinita y se redondeara una vez para ajustarse al tipo de resultado (o, alternativamente, calculado como una única operación ternaria de punto flotante).

Si ocurre un error de rango debido a desbordamiento, ±HUGE_VAL , ±HUGE_VALF , o ±HUGE_VALL es devuelto.

Si ocurre un error de rango debido a desbordamiento inferior, se devuelve el valor correcto (después del redondeo).

Manejo de errores

Los errores se reportan como se especifica en math_errhandling .

Si la implementación soporta aritmética de punto flotante IEEE (IEC 60559),

  • Si x es cero y y es infinito o si x es infinito y y es cero, y
    • si z no es un NaN, entonces se retorna NaN y se genera FE_INVALID ,
    • si z es un NaN, entonces se retorna NaN y puede generarse FE_INVALID .
  • Si x * y es un infinito exacto y z es un infinito con signo opuesto, se retorna NaN y se genera FE_INVALID .
  • Si x o y son NaN, se retorna NaN.
  • Si z es NaN, y x * y no es 0 * Inf o Inf * 0 , entonces se retorna NaN (sin FE_INVALID ).

Notas

Esta operación comúnmente se implementa en hardware como la instrucción de CPU fused multiply-add . Si es compatible con el hardware, se espera que las macros apropiadas FP_FAST_FMA ? estén definidas, pero muchas implementaciones utilizan la instrucción de CPU incluso cuando las macros no están definidas.

POSIX ( fma , fmaf , fmal ) especifica adicionalmente que las situaciones especificadas para retornar FE_INVALID son errores de dominio.

Debido a su precisión intermedia infinita, std::fma es un componente común de otras operaciones matemáticas correctamente redondeadas, como std::sqrt o incluso la división (cuando no está proporcionada por la CPU, por ejemplo Itanium ).

Como con todas las expresiones de punto flotante, la expresión x * y + z puede ser compilada como una operación fusionada de multiplicación y suma a menos que el #pragma STDC FP_CONTRACT esté desactivado.

Las sobrecargas adicionales no requieren ser proporcionadas exactamente como (A) . Solo necesitan ser suficientes para garantizar que para su primer argumento num1 , segundo argumento num2 y tercer argumento num3 :

  • Si num1 , num2 o num3 tiene tipo long double , entonces std :: fma ( num1, num2, num3 ) tiene el mismo efecto que std :: fma ( static_cast < long double > ( num1 ) ,
    static_cast < long double > ( num2 ) ,
    static_cast < long double > ( num3 ) )
    .
  • En caso contrario, si num1 , num2 y/o num3 tiene tipo double o un tipo entero, entonces std :: fma ( num1, num2, num3 ) tiene el mismo efecto que std :: fma ( static_cast < double > ( num1 ) ,
    static_cast < double > ( num2 ) ,
    static_cast < double > ( num3 ) )
    .
  • En caso contrario, si num1 , num2 o num3 tiene tipo float , entonces std :: fma ( num1, num2, num3 ) tiene el mismo efecto que std :: fma ( static_cast < float > ( num1 ) ,
    static_cast < float > ( num2 ) ,
    static_cast < float > ( num3 ) )
    .
(hasta C++23)

Si num1 , num2 y num3 tienen tipos aritméticos, entonces std :: fma ( num1, num2, num3 ) tiene el mismo efecto que std :: fma ( static_cast < /*common-floating-point-type*/ > ( num1 ) ,
static_cast < /*common-floating-point-type*/ > ( num2 ) ,
static_cast < /*common-floating-point-type*/ > ( num3 ) )
, donde /*common-floating-point-type*/ es el tipo de punto flotante con el mayor rango de conversión de punto flotante y mayor subrango de conversión de punto flotante entre los tipos de num1 , num2 y num3 , los argumentos de tipo entero se consideran con el mismo rango de conversión de punto flotante que double .

Si no existe tal tipo de punto flotante con el mayor rango y subrango, entonces la resolución de sobrecarga no resulta en un candidato utilizable de las sobrecargas proporcionadas.

(desde C++23)

Ejemplo

#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";
}

Salida posible:

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

Véase también

(C++11) (C++11) (C++11)
resto con signo de la operación de división
(función)
(C++11) (C++11) (C++11)
resto con signo así como los tres últimos bits de la operación de división
(función)