std:: fma, std:: fmaf, std:: fmal
|
Definido en el encabezado
<cmath>
|
||
| (1) | ||
|
float
fma
(
float
x,
float
y,
float
z
)
;
double
fma
(
double
x,
double
y,
double
z
)
;
|
(desde C++11)
(hasta C++23) |
|
|
constexpr
/* floating-point-type */
fma
(
/* floating-point-type */
x,
|
(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 */
|
(A) |
(desde C++11)
(constexpr desde C++23) |
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)
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
.
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 :
|
(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
)
,
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) |
|
Documentación C
para
fma
|
|