fma, fmaf, fmal
|
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Definido en el encabezado
<math.h>
|
||
|
float
fmaf
(
float
x,
float
y,
float
z
)
;
|
(1) | (desde C99) |
|
double
fma
(
double
x,
double
y,
double
z
)
;
|
(2) | (desde C99) |
|
long
double
fmal
(
long
double
x,
long
double
y,
long
double
z
)
;
|
(3) | (desde C99) |
|
#define FP_FAST_FMA /* implementation-defined */
|
(4) | (desde C99) |
|
#define FP_FAST_FMAF /* implementation-defined */
|
(5) | (desde C99) |
|
#define FP_FAST_FMAL /* implementation-defined */
|
(6) | (desde C99) |
|
Definido en el encabezado
<tgmath.h>
|
||
|
#define fma( x, y, z )
|
(7) | (desde C99) |
FP_FAST_FMA
,
FP_FAST_FMAF
, o
FP_FAST_FMAL
están definidas, la función correspondiente
fma
,
fmaf
, o
fmal
se evalúa más rápidamente (además de ser más precisa) que la expresión
x
*
y
+
z
para argumentos
double
,
float
, y
long
double
, respectivamente. Si están definidas, estas macros se evalúan al entero
1
.
fmal
es llamado. De lo contrario, si algún argumento tiene tipo entero o tiene tipo
double
,
fma
es llamado. De lo contrario,
fmaf
es llamado.
Contenidos |
Parámetros
| x, y, z | - | valores de punto flotante |
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 el 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 especifica que la situación donde el valor x * y es inválido y z es un NaN es un error de dominio.
Debido a su precisión intermedia infinita,
fma
es un componente común de otras operaciones matemáticas correctamente redondeadas, como
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 fused multiply-add a menos que el #pragma STDC FP_CONTRACT esté desactivado.
Ejemplo
#include <fenv.h> #include <float.h> #include <math.h> #include <stdio.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"); }
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 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
Referencias
- Estándar C23 (ISO/IEC 9899:2024):
-
- 7.12.13.1 Las funciones fma (p: TBD)
-
- 7.25 Matemáticas genéricas de tipos <tgmath.h> (p: TBD)
-
- F.10.10.1 Las funciones fma (p: TBD)
- Estándar C17 (ISO/IEC 9899:2018):
-
- 7.12.13.1 Las funciones fma (p: 188-189)
-
- 7.25 Matemáticas genéricas de tipos <tgmath.h> (p: 272-273)
-
- F.10.10.1 Las funciones fma (p: 386)
- Estándar C11 (ISO/IEC 9899:2011):
-
- 7.12.13.1 Las funciones fma (p: 258)
-
- 7.25 Matemáticas genéricas de tipos <tgmath.h> (p: 373-375)
-
- F.10.10.1 Las funciones fma (p: 530)
- Estándar C99 (ISO/IEC 9899:1999):
-
- 7.12.13.1 Las funciones fma (p: 239)
-
- 7.22 Matemáticas genéricas de tipo <tgmath.h> (p: 335-337)
-
- F.9.10.1 Las funciones fma (p: 466)
Véase también
|
(C99)
(C99)
(C99)
|
calcula el resto con signo de la operación de división de punto flotante
(función) |
|
(C99)
(C99)
(C99)
|
calcula el resto con signo así como los tres últimos bits de la operación de división
(función) |
|
Documentación de C++
para
fma
|
|