std:: fma, std:: fmaf, std:: fmal
|
Défini dans l'en-tête
<cmath>
|
||
| (1) | ||
|
float
fma
(
float
x,
float
y,
float
z
)
;
double
fma
(
double
x,
double
y,
double
z
)
;
|
(depuis C++11)
(jusqu'à C++23) |
|
|
constexpr
/* floating-point-type */
fma
(
/* floating-point-type */
x,
|
(depuis C++23) | |
|
float
fmaf
(
float
x,
float
y,
float
z
)
;
|
(2) |
(depuis C++11)
(constexpr depuis C++23) |
|
long
double
fmal
(
long
double
x,
long
double
y,
long
double
z
)
;
|
(3) |
(depuis C++11)
(constexpr depuis C++23) |
|
#define FP_FAST_FMA /* implementation-defined */
|
(4) | (depuis C++11) |
|
#define FP_FAST_FMAF /* implementation-defined */
|
(5) | (depuis C++11) |
|
#define FP_FAST_FMAL /* implementation-defined */
|
(6) | (depuis C++11) |
|
Défini dans l'en-tête
<cmath>
|
||
|
template
<
class
Arithmetic1,
class
Arithmetic2,
class
Arithmetic3
>
/* common-floating-point-type */
|
(A) |
(depuis C++11)
(constexpr depuis C++23) |
std::fma
pour tous les types à virgule flottante non qualifiés cv comme type des paramètres
x
,
y
et
z
.
(depuis C++23)
std::fma
s'évalue plus rapidement (en plus d'être plus précise) que l'expression
x
*
y
+
z
pour les arguments de type
double
,
float
, et
long
double
, respectivement. Si définies, ces macros s'évaluent à l'entier
1
.
Table des matières |
Paramètres
| x, y, z | - | valeurs à virgule flottante ou entières |
Valeur de retour
En cas de succès, retourne la valeur de x * y + z comme si elle était calculée avec une précision infinie puis arrondie une fois pour correspondre au type de résultat (ou, alternativement, calculée comme une seule opération ternaire en virgule flottante).
Si une erreur de plage due à un dépassement de capacité se produit,
±HUGE_VAL
,
±HUGE_VALF
, ou
±HUGE_VALL
est renvoyé.
Si une erreur de plage due à un dépassement inférieur se produit, la valeur correcte (après arrondi) est retournée.
Gestion des erreurs
Les erreurs sont signalées comme spécifié dans math_errhandling .
Si l'implémentation prend en charge l'arithmétique à virgule flottante IEEE (IEC 60559),
-
Si
x
est nul et
y
est infini ou si
x
est infini et
y
est nul, et
- si z n'est pas un NaN, alors NaN est retourné et FE_INVALID est déclenché,
- si z est un NaN, alors NaN est retourné et FE_INVALID peut être déclenché.
- Si x * y est un infini exact et z est un infini de signe opposé, NaN est retourné et FE_INVALID est déclenché.
- Si x ou y sont NaN, NaN est retourné.
- Si z est NaN, et x * y n'est pas 0 * Inf ou Inf * 0 , alors NaN est retourné (sans FE_INVALID ).
Notes
Cette opération est couramment implémentée en matériel sous la forme d'une instruction CPU de multiplication-addition fusionnée . Si elle est prise en charge par le matériel, les macros appropriées FP_FAST_FMA ? sont censées être définies, mais de nombreuses implémentations utilisent l'instruction CPU même lorsque les macros ne sont pas définies.
POSIX
(
fma
,
fmaf
,
fmal
)
spécifie en outre que les situations spécifiées pour renvoyer
FE_INVALID
sont des erreurs de domaine.
En raison de sa précision intermédiaire infinie,
std::fma
est un composant commun d'autres opérations mathématiques correctement arrondies, telles que
std::sqrt
ou même la division (lorsqu'elle n'est pas fournie par le CPU, par exemple sur
Itanium
).
Comme pour toutes les expressions en virgule flottante, l'expression x * y + z peut être compilée comme une multiplication-addition fusionnée, sauf si le #pragma STDC FP_CONTRACT est désactivé.
Les surcharges supplémentaires ne sont pas tenues d'être fournies exactement comme (A) . Elles doivent seulement être suffisantes pour garantir que pour leur premier argument num1 , deuxième argument num2 et troisième argument num3 :
|
(jusqu'à C++23) |
|
Si
num1
,
num2
et
num3
ont des types arithmétiques, alors
std
::
fma
(
num1, num2, num3
)
a le même effet que
std
::
fma
(
static_cast
<
/*common-floating-point-type*/
>
(
num1
)
,
Si aucun tel type à virgule flottante avec le rang et la sous-catégorie les plus élevés n'existe, alors la résolution de surcharge ne produit aucun candidat utilisable parmi les surcharges fournies. |
(depuis C++23) |
Exemple
#include <cfenv> #include <cmath> #include <iomanip> #include <iostream> #ifndef __GNUC__ #pragma STDC FENV_ACCESS ON #endif int main() { // démontre la différence entre fma et les opérateurs intégrés const double in = 0.1; std::cout << "0.1 en double vaut " << std::setprecision(23) << in << " (" << std::hexfloat << in << std::defaultfloat << ")\n" << "0.1*10 vaut 1.0000000000000000555112 (0x8.0000000000002p-3), " << "ou 1.0 si arrondi en 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 soustrait après arrondi intermédiaire\n" << "fma(0.1, 10, -1) = " << std::setprecision(6) << fma_result << " (" << std::hexfloat << fma_result << std::defaultfloat << ")\n\n"; // fma est utilisé en arithmétique double-double const double high = 0.1 * 10; const double low = std::fma(0.1, 10, -high); std::cout << "en arithmétique double-double, 0.1 * 10 est représentable par " << high << " + " << low << "\n\n"; // gestion des erreurs 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 levée\n"; }
Sortie possible :
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
Voir aussi
|
(C++11)
(C++11)
(C++11)
|
reste signé de l'opération de division
(fonction) |
|
(C++11)
(C++11)
(C++11)
|
reste signé ainsi que les trois derniers bits de l'opération de division
(fonction) |
|
Documentation C
pour
fma
|
|