Namespaces
Variants

std:: fma, std:: fmaf, std:: fmal

From cppreference.net
Common mathematical functions
Nearest integer floating point operations
(C++11)
(C++11)
(C++11) (C++11) (C++11)
Floating point manipulation functions
(C++11) (C++11)
(C++11)
(C++11)
Classification and comparison
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
Types
(C++11)
(C++11)
(C++11)
Macro constants
Definiert im Header <cmath>
(1)
float fma ( float x, float y, float z ) ;

double fma ( double x, double y, double z ) ;

long double fma ( long double x, long double y, long double z ) ;
(seit C++11)
(bis C++23)
constexpr /* floating-point-type */

fma ( /* floating-point-type */ x,
/* floating-point-type */ y,

/* floating-point-type */ z ) ;
(seit C++23)
float fmaf ( float x, float y, float z ) ;
(2) (seit C++11)
(constexpr seit C++23)
long double fmal ( long double x, long double y, long double z ) ;
(3) (seit C++11)
(constexpr seit C++23)
#define FP_FAST_FMA  /* implementation-defined */
(4) (seit C++11)
#define FP_FAST_FMAF /* implementation-defined */
(5) (seit C++11)
#define FP_FAST_FMAL /* implementation-defined */
(6) (seit C++11)
Definiert im Header <cmath>
template < class Arithmetic1, class Arithmetic2, class Arithmetic3 >

/* common-floating-point-type */

fma ( Arithmetic1 x, Arithmetic2 y, Arithmetic3 z ) ;
(A) (seit C++11)
(constexpr seit C++23)
1-3) Berechnet x * y + z als ob mit unendlicher Genauigkeit und nur einmal gerundet, um in den Ergebnistyp zu passen. Die Bibliothek stellt Überladungen von std::fma für alle nicht-cv-qualifizierten Gleitkommatypen als Typ der Parameter x , y und z bereit. (seit C++23)
4-6) Falls die Makrokonstanten FP_FAST_FMA , FP_FAST_FMAF oder FP_FAST_FMAL definiert sind, wertet die Funktion std::fma schneller aus (zusätzlich zur höheren Genauigkeit) als der Ausdruck x * y + z für double -, float - bzw. long double -Argumente. Falls definiert, evaluieren diese Makros zum ganzzahligen Wert 1 .
A) Zusätzliche Überladungen werden für alle anderen Kombinationen arithmetischer Typen bereitgestellt.

Inhaltsverzeichnis

Parameter

x, y, z - Gleitkomma- oder Ganzzahlwerte

Rückgabewert

Bei Erfolg wird der Wert von x * y + z zurückgegeben, als ob er mit unendlicher Genauigkeit berechnet und einmal gerundet wurde, um in den Ergebnistyp zu passen (oder alternativ als einzelner ternärer Gleitkommaoperation berechnet).

Wenn ein Bereichsfehler aufgrund von Überlaufs auftritt, ±HUGE_VAL , ±HUGE_VALF , oder ±HUGE_VALL wird zurückgegeben.

Wenn ein Bereichsfehler aufgrund von Unterlauf auftritt, wird der korrekte Wert (nach Rundung) zurückgegeben.

Fehlerbehandlung

Fehler werden gemeldet, wie in math_errhandling spezifiziert.

Wenn die Implementierung IEEE-Gleitkommaarithmetik (IEC 60559) unterstützt,

  • Wenn x null ist und y unendlich ist oder wenn x unendlich ist und y null ist, und
    • wenn z kein NaN ist, dann wird NaN zurückgegeben und FE_INVALID ausgelöst,
    • wenn z ein NaN ist, dann wird NaN zurückgegeben und FE_INVALID kann ausgelöst werden.
  • Wenn x * y ein exaktes Unendlich ist und z ein Unendlich 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, dann wird NaN zurückgegeben (ohne FE_INVALID ).

Hinweise

Diese Operation wird in der Hardware üblicherweise als fused multiply-add CPU-Befehl implementiert. Falls hardwareunterstützt, sollten die entsprechenden FP_FAST_FMA ? Makros definiert sein, jedoch nutzen viele Implementierungen den CPU-Befehl selbst dann, wenn die Makros nicht definiert sind.

POSIX ( fma , fmaf , fmal ) spezifiziert zusätzlich, dass die Situationen, die zur Rückgabe von FE_INVALID führen, Domänenfehler sind.

Aufgrund seiner unendlich genauen Zwischenpräzision ist std::fma ein häufig verwendeter Baustein für andere korrekt gerundete mathematische Operationen, wie std::sqrt oder sogar die Division (sofern nicht vom Prozessor bereitgestellt, z.B. Itanium ).

Wie bei allen Fließkomma-Ausdrücken kann der Ausdruck x * y + z als fused multiply-add kompiliert werden, es sei denn, das #pragma STDC FP_CONTRACT ist deaktiviert.

Die zusätzlichen Überladungen müssen nicht exakt wie (A) bereitgestellt werden. Sie müssen lediglich sicherstellen, dass für ihr erstes Argument num1 , zweites Argument num2 und drittes Argument num3 :

  • Falls num1 , num2 oder num3 den Typ long double besitzt, dann hat std :: fma ( num1, num2, num3 ) denselben Effekt wie std :: fma ( static_cast < long double > ( num1 ) ,
    static_cast < long double > ( num2 ) ,
    static_cast < long double > ( num3 ) )
    .
  • Andernfalls, falls num1 , num2 und/oder num3 den Typ double oder einen Ganzzahltyp besitzt, dann hat std :: fma ( num1, num2, num3 ) denselben Effekt wie std :: fma ( static_cast < double > ( num1 ) ,
    static_cast < double > ( num2 ) ,
    static_cast < double > ( num3 ) )
    .
  • Andernfalls, falls num1 , num2 oder num3 den Typ float besitzt, dann hat std :: fma ( num1, num2, num3 ) denselben Effekt wie std :: fma ( static_cast < float > ( num1 ) ,
    static_cast < float > ( num2 ) ,
    static_cast < float > ( num3 ) )
    .
(bis C++23)

Wenn num1 , num2 und num3 arithmetische Typen haben, dann hat std :: fma ( num1, num2, num3 ) denselben Effekt wie std :: fma ( static_cast < /*common-floating-point-type*/ > ( num1 ) ,
static_cast < /*common-floating-point-type*/ > ( num2 ) ,
static_cast < /*common-floating-point-type*/ > ( num3 ) )
, wobei /*common-floating-point-type*/ der Gleitkommatyp mit dem höchsten Gleitkomma-Konvertierungsrang und dem höchsten Gleitkomma-Konvertierungsunterrang unter den Typen von num1 , num2 und num3 ist. Argumente vom Integer-Typ werden als mit demselben Gleitkomma-Konvertierungsrang wie double betrachtet.

Wenn kein solcher Gleitkommatyp mit dem höchsten Rang und Unterrang existiert, dann führt die Überlagerungsauflösung nicht zu einem verwendbaren Kandidaten aus den bereitgestellten Überlagerungen.

(seit C++23)

Beispiel

#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";
}

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
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

Siehe auch

(C++11) (C++11) (C++11)
Signierter Rest der Divisionsoperation
(Funktion)
(C++11) (C++11) (C++11)
Signierter Rest sowie die drei letzten Bits der Divisionsoperation
(Funktion)