fma, fmaf, fmal
| Definiert in Header <math.h> |
||
| float fmaf( float x, float y, float z ); |
(1) | (seit C99) |
| double fma( double x, double y, double z ); |
(2) | (seit C99) |
| long double fmal( long double x, long double y, long double z ); |
(3) | (seit C99) |
| #define FP_FAST_FMA /* implementierungsabhängig */ |
(4) | (seit C99) |
| #define FP_FAST_FMAF /* implementierungsabhängig */ |
(5) | (seit C99) |
| #define FP_FAST_FMAL /* implementierungsabhängig */ |
(6) | (seit C99) |
| Definiert in Header <tgmath.h> |
||
| #define fma( x, y, z ) |
(7) | (seit C99) |
FP_FAST_FMA, FP_FAST_FMAF oder FP_FAST_FMAL definiert sind, wertet die entsprechende Funktion fma, fmaf oder fmal schneller aus (zusätzlich zur höheren Präzision) als der Ausdruck x * y + z für Argumente vom Typ double, float bzw. long double. Wenn sie definiert sind, werden diese Makros zu einer Ganzzahl 1 ausgewertet.fmal aufgerufen. Andernfalls, wenn ein beliebiges Argument einen Ganzzahltyp oder den Typ double hat, wird fma aufgerufen. Andernfalls wird fmaf aufgerufen.Inhalt |
[bearbeiten] Parameter
| x, y, z | - | Gleitkommazahlen |
[bearbeiten] Rückgabewert
Bei Erfolg gibt den Wert von (x * y) + z zurück, als ob dieser mit unendlicher Präzision berechnet und nur einmal gerundet worden wäre, um den Ergebnistyp anzupassen (oder alternativ als einzelne ternäre Gleitkommaoperation berechnet).
Wenn ein Bereichsfehler aufgrund von Überlauf auftritt, wird ±HUGE_VAL, ±HUGE_VALF oder ±HUGE_VALL zurückgegeben.
Wenn ein Bereichsfehler aufgrund von Unterlauf auftritt, wird der korrekte Wert (nach Rundung) zurückgegeben.
[bearbeiten] Fehlerbehandlung
Fehler werden wie in math_errhandling angegeben gemeldet.
Wenn die Implementierung IEEE-Gleitkomma-Arithmetik (IEC 60559) unterstützt,
- Wenn x Null ist und y unendlich ist, oder wenn x unendlich ist und y Null ist, und
- wenn z keine NaN ist, dann wird NaN zurückgegeben und FE_INVALID ausgelöst,
- wenn z eine NaN ist, dann wird NaN zurückgegeben und FE_INVALID kann ausgelöst werden.
- Wenn x * y eine exakte Unendlichkeit ist und z eine Unendlichkeit mit entgegengesetztem Vorzeichen ist, wird NaN zurückgegeben und FE_INVALID ausgelöst.
- Wenn x oder y NaN sind, wird NaN zurückgegeben.
- Wenn z NaN ist und x * y nicht 0 * Inf oder Inf * 0 ist, wird NaN zurückgegeben (ohne FE_INVALID).
[bearbeiten] Hinweise
Diese Operation wird häufig in der Hardware als Fused Multiply-Add-CPU-Instruktion implementiert. Wenn dies von der Hardware unterstützt wird, werden die entsprechenden Makros FP_FAST_FMA* voraussichtlich definiert sein, aber viele Implementierungen nutzen die CPU-Instruktion auch dann, wenn die Makros nicht definiert sind.
POSIX spezifiziert, dass die Situation, in der der Wert x * y ungültig ist und z eine NaN ist, ein Domänenfehler ist.
Aufgrund ihrer unendlichen Zwischenpräzision ist fma ein gängiger Baustein für andere korrekt gerundete mathematische Operationen wie sqrt oder sogar die Division (wenn nicht von der CPU bereitgestellt, z. B. Itanium).
Wie bei allen Gleitkommaausdrücken kann der Ausdruck (x * y) + z als Fused Multiply-Add kompiliert werden, es sei denn, die #pragma STDC FP_CONTRACT ist ausgeschaltet.
[bearbeiten] Beispiel
#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"); }
Mögliche Ausgabe
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[bearbeiten] Referenzen
- C23-Standard (ISO/IEC 9899:2024)
- 7.12.13.1 The fma functions (S. TBD)
- 7.25 Typ-generische Mathematik <tgmath.h> (S. TBD)
- F.10.10.1 The fma functions (S. TBD)
- C17-Standard (ISO/IEC 9899:2018)
- 7.12.13.1 The fma functions (S. 188-189)
- 7.25 Typ-generische Mathematik <tgmath.h> (S. 272-273)
- F.10.10.1 The fma functions (S. 386)
- C11-Standard (ISO/IEC 9899:2011)
- 7.12.13.1 The fma functions (S. 258)
- 7.25 Typ-generische Mathematik <tgmath.h> (S. 373-375)
- F.10.10.1 The fma functions (S. 530)
- C99-Standard (ISO/IEC 9899:1999)
- 7.12.13.1 The fma functions (S. 239)
- 7.22 Typ-generische Mathematik <tgmath.h> (S. 335-337)
- F.9.10.1 The fma functions (S. 466)
[bearbeiten] Siehe auch
| (C99)(C99)(C99) |
berechnet den vorzeichenbehafteten Rest der Gleitkommadivision (Funktion) |
| (C99)(C99)(C99) |
berechnet den vorzeichenbehafteten Rest sowie die drei letzten Bits der Division (Funktion) |
| C++ Dokumentation für fma
| |