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

long double fma ( long double x, long double y, long double z ) ;
(depuis C++11)
(jusqu'à C++23)
constexpr /* floating-point-type */

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

/* floating-point-type */ z ) ;
(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 */

fma ( Arithmetic1 x, Arithmetic2 y, Arithmetic3 z ) ;
(A) (depuis C++11)
(constexpr depuis C++23)
1-3) Calcule x * y + z comme si avec une précision infinie et arrondi une seule fois pour correspondre au type de résultat. La bibliothèque fournit des surcharges de std::fma pour tous les types à virgule flottante non qualifiés cv comme type des paramètres x , y et z . (depuis C++23)
4-6) Si les constantes de macro FP_FAST_FMA , FP_FAST_FMAF , ou FP_FAST_FMAL sont définies, la fonction 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 .
A) Des surcharges supplémentaires sont fournies pour toutes les autres combinaisons de types arithmétiques.

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 :

  • Si num1 , num2 ou num3 a le type long double , alors std :: fma ( num1, num2, num3 ) a le même effet que std :: fma ( static_cast < long double > ( num1 ) ,
    static_cast < long double > ( num2 ) ,
    static_cast < long double > ( num3 ) )
    .
  • Sinon, si num1 , num2 et/ou num3 a le type double ou un type entier, alors std :: fma ( num1, num2, num3 ) a le même effet que std :: fma ( static_cast < double > ( num1 ) ,
    static_cast < double > ( num2 ) ,
    static_cast < double > ( num3 ) )
    .
  • Sinon, si num1 , num2 ou num3 a le type float , alors std :: fma ( num1, num2, num3 ) a le même effet que std :: fma ( static_cast < float > ( num1 ) ,
    static_cast < float > ( num2 ) ,
    static_cast < float > ( 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 ) ,
static_cast < /*common-floating-point-type*/ > ( num2 ) ,
static_cast < /*common-floating-point-type*/ > ( num3 ) )
, où /*common-floating-point-type*/ est le type à virgule flottante ayant le plus grand rang de conversion en virgule flottante et la plus grande sous-catégorie de conversion en virgule flottante parmi les types de num1 , num2 et num3 , les arguments de type entier sont considérés comme ayant le même rang de conversion en virgule flottante que double .

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)