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) |
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.Contenido |
[editar] Parámetros
x, y, z | - | Valores de tipos de punto flotante o tipos enteros. |
[editar] 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).
[editar] 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
x
es cero ey
es infinita o six
es infinita ey
es cero, yz
no es NaN, entonces se devuelve NaN y se genera FE_INVALID. - Si
x
es cero ey
es infinita o six
es infinita ey
es cero, yz
es NaN, entonces se devuelve NaN y puede generarse FE_INVALID. - Si x*y es una infinidad exacta y
z
es una infinidad con el signo opuesto, se devuelve NaN y se genera FE_INVALID - Si
x
oy
son NaN, se devuelve NaN. - Si
z
es NaN, y x*y no son 0*Inf o Inf*0, entonces se devuelve NaN (sin que se genere FE_INVALID).
[editar] 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.
[editar] 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
[editar] 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
|