std::fma, std::fmaf, std::fmal
| Definido en el archivo de encabezado <cmath>
|
||
float fma ( float x, float y, float z ); |
(1) | (desde C++11) (constexpr since C++23) |
float fmaf( float x, float y, float z ); |
(2) | (desde C++11) (constexpr since C++23) |
double fma ( double x, double y, double z ); |
(3) | (desde C++11) (constexpr since C++23) |
long double fma ( long double x, long double y, long double z ); |
(4) | (desde C++11) (constexpr since C++23) |
long double fmal( long double x, long double y, long double z ); |
(5) | (desde C++11) (constexpr since C++23) |
Promovido fma ( Aritmético1 x, Aritmético2 y, Arithmetic3 z ); |
(6) | (desde C++11) (constexpr since C++23) |
#define FP_FAST_FMA /* definido por la implementación */ |
(7) | (desde C++11) |
#define FP_FAST_FMAF /* definido por la implementación */ |
(8) | (desde C++11) |
#define FP_FAST_FMAL /* definido por la implementación */ |
(9) | (desde C++11) |
(x*y) + z como si tuviera una precisión infinita y lo redondea solo una vez para ajustarse al tipo de resultado.double. Si cualquier otro argumento es long double, entonces el tipo de retorno es long double, de lo contrario es double.FP_FAST_FMA, FP_FAST_FMAF, o FP_FAST_FMAL, la función std::fma se evalúa más rápidamente (además de ser más precisa) que la expresión x*y+z para argumentos float, double, y long double, respectivamente. Si estám definidas, estas macros se evalúan al entero 1.Parámetros
| x, y, z | - | Valores de tipos de punto flotante o tipos enteros. |
Valor de retorno
Si tiene éxito, devuelve el valor (x*y) + z como si se calculara con precisión infinita y se redondeara una vez para ajustarse al tipo de resultado (o, alternativamente, se calculara como una sola operación ternaria de punto flotante).
Si se produce un error de rango debido a desbordamiento, se devuelve HUGE_VAL, ±HUGE_VALF, o ±HUGE_VALL.
Si se produce un error de rango debido a subdesbordamiento, se devuelve el valor correcto (después del redondeo).
Manejo de errores
Los errores se informan como se especifica en math_errhandling.
Si la implementación admite la aritmética de punto flotante IEEE (IEC 60559):
- Si
xes cero eyes infinita o sixes infinita eyes cero, yzno es NaN, entonces se devuelve NaN y se genera FE_INVALID. - Si
xes cero eyes infinita o sixes infinita eyes cero, yzes NaN, entonces se devuelve NaN y puede generarse FE_INVALID. - Si
x*yes una infinidad exacta yzes una infinidad con el signo opuesto, se devuelve NaN y se genera FE_INVALID - Si
xoyson NaN, se devuelve NaN. - Si
zes NaN, yx*yno son 0*Inf o Inf*0, entonces se devuelve NaN (sin que se genere FE_INVALID).
Notas
Esta operación se implementa comúnmente en hardware como instrucción de CPU suma y multiplicación fusionada Si es compatible con el hardware, se espera que se definan las macros FP_FAST_FMA? apropiadas, pero muchas implementaciones generan el uso de la instrucción de la CPU incluso cuando las macros no están definidas.
POSIX además especifica que las situaciones especificadas para devolver FE_INVALID sean errores de dominio.
Debido a su infinita precisión intermedia, std::fma es un bloque de construcción común de otras operaciones matemáticas redondeadas correctamente, como std::sqrto incluso la división (donde no se proporciona por la CPU, por ejemplo, Itanium).
Al igual que con todas las expresiones de punto flotante, la expresión (x*y) + z se puede compilar como una suma y multiplicación fusionada a menos que
#pragma STDC FP_CONTRACT esté deshabilitado.
Ejemplo
#include <iostream>
#include <iomanip>
#include <cmath>
#include <cfenv>
#ifndef __GNUC__
#pragma STDC FENV_ACCESS ON
#endif
int main()
{
// demo de la diferencia entre fma y operadores integrados
const double in = 0.1;
std::cout << "0.1 double es " << std::setprecision(23) << in
<< " (" << std::hexfloat << in << std::defaultfloat << ")\n"
<< "0.1*10 es 1.0000000000000000555112 (0x8.0000000000002p-3), "
<< "o 1.0 si redondeado a 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 restado después del redondeo intermedio\n"
<< "fma(0.1, 10, -1) = " << std::setprecision(6) << fma_result << " ("
<< std::hexfloat << fma_result << std::defaultfloat << ")\n\n";
// fma se usa en aritmética double-double
const double high = 0.1 * 10;
const double low = std::fma(0.1, 10, -high);
std::cout << "en aritmética double-double, 0.1 * 10 es representable como "
<< high << " + " << low << "\n\n";
// manejo de errores
std::feclearexcept(FE_ALL_EXCEPT);
std::cout << "fma(+Inf, 10, -Inf) = " << std::fma(INFINITY, 10, -INFINITY) << '\n';
if(std::fetestexcept(FE_INVALID))
std::cout << " Se generó FE_INVALID\n";
}
Posible salida:
0.1 double es 0.10000000000000000555112 (0x1.999999999999ap-4)
0.1*10 es 1.0000000000000000555112 (0x8.0000000000002p-3), o 1.0 si redondeado a double
0.1 * 10 - 1 = 0 : 1 restado después del redondeo intermedio
fma(0.1, 10, -1) = 5.55112e-17 (0x1p-54)
en aritmética double-double, 0.1 * 10 es representable como 1 + 5.55112e-17
fma(+Inf, 10, -Inf) = -nan
Se generó FE_INVALID
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) |
Documentación de C para fma
| |