fma, fmaf, fmal
|
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Défini dans l'en-tête
<math.h>
|
||
|
float
fmaf
(
float
x,
float
y,
float
z
)
;
|
(1) | (depuis C99) |
|
double
fma
(
double
x,
double
y,
double
z
)
;
|
(2) | (depuis C99) |
|
long
double
fmal
(
long
double
x,
long
double
y,
long
double
z
)
;
|
(3) | (depuis C99) |
|
#define FP_FAST_FMA /* implementation-defined */
|
(4) | (depuis C99) |
|
#define FP_FAST_FMAF /* implementation-defined */
|
(5) | (depuis C99) |
|
#define FP_FAST_FMAL /* implementation-defined */
|
(6) | (depuis C99) |
|
Défini dans l'en-tête
<tgmath.h>
|
||
|
#define fma( x, y, z )
|
(7) | (depuis C99) |
FP_FAST_FMA
,
FP_FAST_FMAF
, ou
FP_FAST_FMAL
sont définies, la fonction correspondante
fma
,
fmaf
, ou
fmal
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
.
fmal
est appelé. Sinon, si un argument a un type entier ou a le type
double
,
fma
est appelé. Sinon,
fmaf
est appelé.
Table des matières |
Paramètres
| x, y, z | - | valeurs en virgule flottante |
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 forme d'instruction CPU de fused multiply-add . Si elle est supportée 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 spécifie que la situation où la valeur x * y est invalide et z est un NaN constitue une erreur de domaine.
En raison de sa précision intermédiaire infinie,
fma
est un composant commun d'autres opérations mathématiques correctement arrondies, telles que
sqrt
ou même la division (lorsque non fournie par le CPU, par exemple
Itanium
).
Comme pour toutes les expressions en virgule flottante, l'expression ( x * y ) + z peut être compilée comme une opération fusionnée multiply-add, sauf si le #pragma STDC FP_CONTRACT est désactivé.
Exemple
#include <fenv.h> #include <float.h> #include <math.h> #include <stdio.h> // #pragma STDC FENV_ACCESS ON int main(void) { // démontre la différence entre fma et les opérateurs intégrés double in = 0.1; printf("0.1 en double vaut %.23f (%a)\n", in, in); printf("0.1*10 vaut 1.0000000000000000555112 (0x8.0000000000002p-3)," " ou 1.0 si arrondi en double\n"); double expr_result = 0.1 * 10 - 1; printf("0.1 * 10 - 1 = %g : 1 soustrait après " "arrondi intermédiaire à 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); // utilisation de fma en arithmétique double-double printf("\nen arithmétique double-double, 0.1 * 10 est représentable comme "); double high = 0.1 * 10; double low = fma(0.1, 10, -high); printf("%g + %g\n\n", high, low); // gestion des erreurs feclearexcept(FE_ALL_EXCEPT); printf("fma(+Inf, 10, -Inf) = %f\n", fma(INFINITY, 10, -INFINITY)); if (fetestexcept(FE_INVALID)) puts(" FE_INVALID levée"); }
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 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
Références
- Norme C23 (ISO/IEC 9899:2024):
-
- 7.12.13.1 Les fonctions fma (p: TBD)
-
- 7.25 Mathématiques génériques de type <tgmath.h> (p: TBD)
-
- F.10.10.1 Les fonctions fma (p: TBD)
- Norme C17 (ISO/CEI 9899:2018) :
-
- 7.12.13.1 Les fonctions fma (p: 188-189)
-
- 7.25 Mathématiques génériques <tgmath.h> (p: 272-273)
-
- F.10.10.1 Les fonctions fma (p: 386)
- Norme C11 (ISO/IEC 9899:2011) :
-
- 7.12.13.1 Les fonctions fma (p: 258)
-
- 7.25 Mathématiques génériques <tgmath.h> (p: 373-375)
-
- F.10.10.1 Les fonctions fma (p: 530)
- Norme C99 (ISO/CEI 9899:1999) :
-
- 7.12.13.1 Les fonctions fma (p: 239)
-
- 7.22 Mathématiques génériques de type <tgmath.h> (p: 335-337)
-
- F.9.10.1 Les fonctions fma (p: 466)
Voir aussi
|
(C99)
(C99)
(C99)
|
calcule le reste signé de l'opération de division en virgule flottante
(fonction) |
|
(C99)
(C99)
(C99)
|
calcule le reste signé ainsi que les trois derniers bits de l'opération de division
(fonction) |
|
Documentation C++
pour
fma
|
|