/fp (Spécifier le comportement à virgule flottante)

Spécifie la façon dont le compilateur traite les expressions à virgule flottante, les optimisations et les exceptions. Les /fp options spécifient si le code généré autorise les changements d’environnement à virgule flottante en mode arrondi, les masques d’exception et le comportement subnormal, et si les vérifications d'état à virgule flottante retournent les résultats actuels et précis. Il contrôle si le compilateur génère du code qui gère l’opération source et l’ordre d’expression, et est conforme à la norme de propagation NaN. Sinon, s’il génère plutôt du code plus efficace qui peut réorganiser ou combiner des opérations et utiliser la simplification des transformations algébriques qui ne sont pas autorisées par la norme IEEE-754.

Syntaxe

/fp:contract
/fp:except[-]
/fp:fast
/fp:precise
/fp:strict

/fp:except[-]
/fp:fast
/fp:precise
/fp:strict

Arguments

/fp:contract

L’option /fp:contract permet au compilateur de générer des contractions à virgule flottante lorsque vous spécifiez les options et /fp:except les /fp:precise options. Une contraction est une instruction de machine qui combine des opérations à virgule flottante, telles que Fused-Multiply-Add (FMA). FMA, défini comme une opération de base par IEEE-754, n’arrondit pas le produit intermédiaire avant l’ajout, de sorte que le résultat peut différer des opérations de multiplication et d’ajout distinctes. Étant donné qu’elle est implémentée en tant qu’instruction unique, elle peut être plus rapide que des instructions distinctes. La vitesse est un coût de résultats exacts au niveau du bit et une incapacité à examiner la valeur intermédiaire.

Par défaut, l’option /fp:fast active /fp:contract. L’option /fp:contract n’est pas compatible avec /fp:strict.

L’option /fp:contract est nouvelle dans Visual Studio 2022.

/fp:precise

Par défaut, le compilateur utilise /fp:precise le comportement.

Sous /fp:precise, le compilateur conserve le classement et l’arrondi des propriétés d’expression source du code à virgule flottante lorsqu’il génère et optimise le code objet pour l’ordinateur cible. Le compilateur arrondit à la précision du code source à quatre points spécifiques lors de l’évaluation de l’expression : lors des affectations, des typescasts, lorsque les arguments à virgule flottante sont passés à un appel de fonction et lorsqu’un appel de fonction retourne une valeur à virgule flottante. Les calculs intermédiaires peuvent être effectués à la précision de la machine. Les typescast peuvent être utilisés pour arrondir explicitement les calculs intermédiaires.

Le compilateur n’effectue pas de transformations algébriques sur des expressions à virgule flottante, telles que la réassociation ou la distribution, sauf si elle peut garantir que la transformation produit un résultat identique au niveau du bit. Les expressions qui impliquent des valeurs spéciales (NaN, +infinity, -infinity, -0.0) sont traitées conformément aux spécifications IEEE-754. Par exemple, x != x la truex valeur est NaN. Les contractions à virgule flottante ne sont pas générées par défaut sous /fp:precise. Ce comportement est nouveau dans Visual Studio 2022. Les versions précédentes du compilateur peuvent générer des contractions par défaut sous /fp:precise.

Le compilateur n’effectue pas de transformations algébriques sur des expressions à virgule flottante, telles que la réassociation ou la distribution, sauf si elle peut garantir que la transformation produit un résultat identique au niveau du bit. Les expressions qui impliquent des valeurs spéciales (NaN, +infinity, -infinity, -0.0) sont traitées conformément aux spécifications IEEE-754. Par exemple, x != x la truex valeur est NaN. Les contractions à virgule flottante peuvent être générées sous /fp:precise.

Le compilateur génère du code destiné à s’exécuter dans l’environnement à virgule flottante par défaut. Il suppose également que l’environnement à virgule flottante n’est pas accessible ou modifié au moment de l’exécution. Autrement dit, il part du code : laisse des exceptions à virgule flottante masquées, ne lit pas ou n’écrit pas de registres d’état à virgule flottante et ne modifie pas les modes d’arrondi.

Si votre code à virgule flottante ne dépend pas de l’ordre des opérations et des expressions dans vos instructions à virgule flottante (par exemple, si vous ne vous souciez pas d’être a * b + a * c calculé en tant que (b + c) * a ou 2 * a comme a + a), envisagez l’option /fp:fast , qui peut produire du code plus rapide et plus efficace. Si votre code dépend tous deux de l’ordre des opérations et des expressions, et accède ou modifie l’environnement à virgule flottante (par exemple, pour modifier les modes d’arrondi ou pour intercepter les exceptions à virgule flottante), utilisez /fp:strict.

/fp:strict

/fp:strict a un comportement similaire à /fp:precise, autrement dit, le compilateur conserve les propriétés d’ordre source et d’arrondi du code à virgule flottante lorsqu’il génère et optimise le code objet pour l’ordinateur cible, et observe la norme lors de la gestion des valeurs spéciales. Le programme peut également accéder ou modifier en toute sécurité l’environnement à virgule flottante au moment de l’exécution.

Sous /fp:strict, le compilateur génère du code qui permet au programme de démasquer en toute sécurité des exceptions à virgule flottante, de lire ou d’écrire des registres d’état à virgule flottante ou de modifier les modes d’arrondi. Il arrondit à la précision du code source à quatre points spécifiques lors de l’évaluation de l’expression : lors des affectations, des typecasts, lorsque des arguments à virgule flottante sont passés à un appel de fonction et lorsqu’un appel de fonction retourne une valeur à virgule flottante. Les calculs intermédiaires peuvent être effectués à la précision de la machine. Les typescast peuvent être utilisés pour arrondir explicitement les calculs intermédiaires. Le compilateur n’effectue aucune transformation algébrique sur des expressions à virgule flottante, telles que la réassociation ou la distribution, sauf si elle peut garantir que la transformation produit un résultat identique au niveau du bit. Les expressions qui impliquent des valeurs spéciales (NaN, +infinity, -infinity, -0.0) sont traitées conformément aux spécifications IEEE-754. Par exemple, x != x la truex valeur est NaN. Les contractions à virgule flottante ne sont pas générées sous /fp:strict.

/fp:strict est plus coûteux que parce que /fp:precise le compilateur doit insérer des instructions supplémentaires pour intercepter les exceptions et autoriser les programmes à accéder ou modifier l’environnement à virgule flottante au moment de l’exécution. Si votre code n’utilise pas cette fonctionnalité, mais nécessite l’ordre et l’arrondi de code source, ou s’appuie sur des valeurs spéciales, utilisez /fp:precise. Sinon, envisagez d’utiliser /fp:fast, ce qui peut produire du code plus rapide et plus petit.

/fp:fast

L’option /fp:fast permet au compilateur de réorganiser, combiner ou simplifier les opérations à virgule flottante afin d’optimiser le code à virgule flottante pour la vitesse et l’espace. Le compilateur peut omettre l’arrondi aux instructions d’affectation, aux typescasts ou aux appels de fonction. Il peut réorganiser des opérations ou faire des transformations algébriques, par exemple, à l’aide de lois associatifs et distribuives. Il peut réorganiser le code même si de telles transformations entraînent un comportement d’arrondi observablement différent. En raison de cette optimisation améliorée, le résultat de certains calculs à virgule flottante peut différer de celui produit par d’autres /fp options. Les valeurs spéciales (NaN, +infinity, -infinity, -0.0) peuvent ne pas être propagées ou se comporter strictement en fonction de la norme IEEE-754. Les contractions à virgule flottante peuvent être générées sous /fp:fast. Le compilateur est toujours lié par l’architecture sous-jacente, /fp:fastet d’autres optimisations peuvent être disponibles via l’utilisation de l’option /arch .

Sous /fp:fast, le compilateur génère du code destiné à s’exécuter dans l’environnement à virgule flottante par défaut et suppose que l’environnement à virgule flottante n’est pas accessible ou modifié au moment de l’exécution. Autrement dit, il part du code : laisse des exceptions à virgule flottante masquées, ne lit pas ou n’écrit pas de registres d’état à virgule flottante et ne modifie pas les modes d’arrondi.

/fp:fast est destiné aux programmes qui ne nécessitent pas d’ordre de code source strict et d’arrondi d’expressions à virgule flottante, et qui ne s’appuient pas sur les règles standard pour gérer des valeurs spéciales telles que NaN. Si votre code à virgule flottante nécessite la conservation de l’ordre et de l’arrondi du code source, ou s’appuie sur le comportement standard des valeurs spéciales, utilisez /fp:precise. Si votre code accède ou modifie l’environnement à virgule flottante pour modifier les modes d’arrondi, dissocier les exceptions à virgule flottante ou case activée’état à virgule flottante, utilisez /fp:strict.

/fp:except

L’option /fp:except génère du code pour s’assurer que toutes les exceptions à virgule flottante non masquées sont levées au point exact auquel elles se produisent et qu’aucune autre exception à virgule flottante n’est levée. Par défaut, l’option /fp:strict active /fp:exceptet /fp:precise ne le fait pas. L’option /fp:except n’est pas compatible avec /fp:fast. L’option peut être explicitement désactivée à l’aide de /fp:except-.

Par lui-même, /fp:except n’active aucune exception à virgule flottante. Toutefois, il est nécessaire pour les programmes d’activer des exceptions à virgule flottante. Pour plus d’informations sur l’activation des exceptions à virgule flottante, consultez _controlfp.

Notes

Plusieurs /fp options peuvent être spécifiées dans la même ligne de commande du compilateur. Une seule option /fp:strict/fp:fast/fp:precise peut être appliquée à la fois. Si vous spécifiez plusieurs de ces options sur la ligne de commande, l’option ultérieure est prioritaire et le compilateur génère un avertissement. Les /fp:strict options et /fp:except les options ne sont pas compatibles avec /clr.

L’option /Za (compatibilité ANSI) n’est pas compatible avec /fp.

Utilisation des directives du compilateur pour contrôler le comportement à virgule flottante

Le compilateur fournit trois directives pragma pour remplacer le comportement à virgule flottante spécifié sur la ligne de commande : float_control, fenv_accesset fp_contract. Vous pouvez utiliser ces directives pour contrôler le comportement à virgule flottante au niveau de la fonction, et non au sein d’une fonction. Ces directives ne correspondent pas directement aux /fp options. Ce tableau montre comment les /fp options et les directives pragma sont mappées les unes aux autres. Pour plus d’informations, consultez la documentation relative aux options individuelles et aux directives pragma.

Option float_control(precise, *) float_control(except, *) fenv_access(*) fp_contract(*)
/fp:fast off off off on
/fp:precise on off off off*
/fp:strict on on on off

* Dans les versions de Visual Studio avant Visual Studio 2022, le /fp:precise comportement par défaut est défini fp_contract(on)sur .

Option float_control(precise, *) float_control(except, *) fenv_access(*) fp_contract(*)
/fp:fast off off off on
/fp:precise on off off on*
/fp:strict on on on off

* Dans les versions de Visual Studio commençant par Visual Studio 2022, le /fp:precise comportement par défaut est fp_contract(off).

Environnement à virgule flottante par défaut

Lorsqu’un processus est initialisé, l’environnement à virgule flottante par défaut est défini. Cet environnement masque toutes les exceptions à virgule flottante, définit le mode arrondi pour arrondir à la valeur la plus proche (FE_TONEAREST), conserve les valeurs sous-normales (dénormales), utilise la précision par défaut de significand (mantissa) pour float, doubleet long double les valeurs, et où elle est prise en charge, définit le contrôle infini sur le mode affine par défaut.

Accès et modification de l’environnement à virgule flottante

Le runtime Microsoft Visual C++ fournit plusieurs fonctions permettant d’accéder à et de modifier l’environnement à virgule flottante. Ceux-ci incluent _controlfp, _clearfpet _statusfp leurs variantes. Pour garantir un comportement de programme correct lorsque votre code accède ou modifie l’environnement à virgule flottante, fenv_access doit être activé, soit par l’option, soit par l’utilisation /fp:strict du fenv_access pragma, pour que ces fonctions aient un effet quelconque. Lorsqu’il fenv_access n’est pas activé, l’accès ou la modification de l’environnement à virgule flottante peut entraîner un comportement inattendu du programme :

  • Le code peut ne pas respecter les modifications demandées dans l’environnement à virgule flottante,

  • Les registres d’état à virgule flottante peuvent ne pas signaler les résultats attendus ou actuels,

  • Des exceptions à virgule flottante inattendues peuvent se produire ou des exceptions à virgule flottante attendues peuvent ne pas se produire.

Lorsque votre code accède ou modifie l’environnement à virgule flottante, vous devez être prudent lorsque vous combinez du code activé fenv_access avec du code qui n’a fenv_access pas été activé. Dans le code où fenv_access l’option n’est pas activée, le compilateur suppose que l’environnement à virgule flottante par défaut de la plateforme est en vigueur. Il suppose également que l’état à virgule flottante n’est pas accessible ou modifié. Nous vous recommandons d’enregistrer et de restaurer l’environnement à virgule flottante locale à son état par défaut avant le transfert du contrôle vers une fonction qui n’a fenv_access pas été activée. Cet exemple montre comment définir et restaurer le float_control pragma :

#pragma float_control(precise, on, push)
// Code that uses /fp:strict mode
#pragma float_control(pop)

Modes d’arrondi à virgule flottante

Sous les deux /fp:precise et /fp:fast, le compilateur génère du code destiné à s’exécuter dans l’environnement à virgule flottante par défaut. Il part du principe que l’environnement n’est pas accessible ou modifié au moment de l’exécution. Autrement dit, le compilateur suppose que le code ne masque jamais les exceptions à virgule flottante, lit ou écrit des registres d’état à virgule flottante ou modifie les modes d’arrondi. Toutefois, certains programmes doivent modifier l’environnement à virgule flottante. Par exemple, cet exemple calcule les limites d’erreur d’une multiplication à virgule flottante en modifiant les modes d’arrondi à virgule flottante :

// fp_error_bounds.cpp
#include <iostream>
#include <limits>
using namespace std;

int main(void)
{
    float a = std::<float>::max();
    float b = -1.1;
    float cLower = 0.0;
    float cUpper = 0.0;
    unsigned int control_word = 0;
    int err = 0;

    // compute lower error bound.
    // set rounding mode to -infinity.
    err = _controlfp_s(&control_word, _RC_DOWN, _MCW_RC);
    if (err)
    {
        cout << "_controlfp_s(&control_word, _RC_DOWN, _MCW_RC) failed with error:" << err << endl;
    }  
    cLower = a * b;

    // compute upper error bound.
    // set rounding mode to +infinity.
    err = _controlfp_s(&control_word, _RC_UP, _MCW_RC);
    if (err)
    {
        cout << "_controlfp_s(&control_word, _RC_UP, _MCW_RC) failed with error:" << err << endl;
    }
    cUpper = a * b;

    // restore default rounding mode.
    err = _controlfp_s(&control_word, _CW_DEFAULT, _MCW_RC);
    if (err)
    {
        cout << "_controlfp_s(&control_word, _CW_DEFAULT, _MCW_RC) failed with error:" << err << endl;
    }
    // display error bounds.
    cout << "cLower = " << cLower << endl;
    cout << "cUpper = " << cUpper << endl;
    return 0;
}

Étant donné que le compilateur part du principe que l’environnement à virgule flottante par défaut est sous /fp:fast et /fp:precisequ’il est libre d’ignorer les appels à _controlfp_s. Par exemple, lorsqu’elles sont compilées à l’aide de l’architecture /O2 x86 et /fp:precise pour l’architecture x86, les limites ne sont pas calculées et les exemples de sorties de programme :

cLower = -inf
cUpper = -inf

Lors de la compilation à l’aide de l’architecture /O2 x86 et /fp:strict de l’architecture x86, l’exemple de programme génère :

cLower = -inf
cUpper = -3.40282e+38

Valeurs spéciales à virgule flottante

Sous /fp:precise et /fp:strict, les expressions qui impliquent des valeurs spéciales (NaN, +infinity, -infinity, -0.0) se comportent en fonction des spécifications IEEE-754. Sous /fp:fast, le comportement de ces valeurs spéciales peut être incohérent avec IEEE-754.

Cet exemple illustre le comportement différent des valeurs spéciales sous /fp:precise, /fp:strictet /fp:fast:

// fp_special_values.cpp
#include <stdio.h>
#include <cmath>

float gf0 = -0.0;

int main()
{
    float f1 = INFINITY;
    float f2 = NAN;
    float f3 = -INFINITY;
    bool a, b;
    float c, d, e;
    a = (f1 == f1);
    b = (f2 == f2);
    c = (f1 - f1);
    d = (f2 - f2);
    e = (gf0 / f3);
    printf("INFINITY == INFINITY : %d\n", a);
    printf("NAN == NAN           : %d\n", b);
    printf("INFINITY - INFINITY  : %f\n", c);
    printf("NAN - NAN            : %f\n", d);
    printf("std::signbit(-0.0/-INFINITY): %d\n", std::signbit(e));
    return 0;
}

Lorsqu’elles sont compilées à l’aide /O2 /fp:precise ou /O2 /fp:strict pour l’architecture x86, les sorties sont cohérentes avec la spécification IEEE-754 :

INFINITY == INFINITY : 1
NAN == NAN           : 0
INFINITY - INFINITY  : -nan(ind)
NAN - NAN            : nan
std::signbit(-0.0/-INFINITY): 0

Lorsqu’elles sont compilées à l’aide /O2 /fp:fastde ** pour l’architecture x86, les sorties ne sont pas cohérentes avec IEEE-754 :

INFINITY == INFINITY : 1
NAN == NAN           : 1
INFINITY - INFINITY  : 0.000000
NAN - NAN            : 0.000000
std::signbit(-0.0/-INFINITY): 0

Transformations algébriques à virgule flottante

Sous /fp:precise et /fp:strict, le compilateur ne fait aucune transformation mathématique, sauf si la transformation est garantie pour produire un résultat identique au niveau du bit. Le compilateur peut effectuer de telles transformations sous /fp:fast. Par exemple, l’expression a * b + a * c de l’exemple de fonction algebraic_transformation peut être compilée sous a * (b + c)/fp:fast. Ces transformations ne sont pas effectuées sous /fp:precise ou /fp:strict, et le compilateur génère a * b + a * c.

float algebraic_transformation (float a, float b, float c)
{
    return a * b + a * c;
}

Points de cast explicites à virgule flottante

Sous /fp:precise et /fp:strict, le compilateur arrondit à la précision du code source à quatre points spécifiques lors de l’évaluation de l’expression : lors des affectations, des typecasts, lorsque les arguments à virgule flottante sont passés à un appel de fonction et lorsqu’un appel de fonction retourne une valeur à virgule flottante. Les typescast peuvent être utilisés pour arrondir explicitement les calculs intermédiaires. Sous /fp:fast, le compilateur ne génère pas de casts explicites à ces points pour garantir la précision du code source. Cet exemple illustre le comportement sous différentes /fp options :

float casting(float a, float b)
{
    return 5.0*((double)(a+b));
}

Lors de la compilation à l’aide /O2 /fp:precise ou /O2 /fp:strict, vous pouvez voir que les casts de types explicites sont insérés à la fois dans lacast de type et au point de retour de la fonction dans le code généré pour l’architecture x64 :

        addss    xmm0, xmm1
        cvtss2sd xmm0, xmm0
        mulsd    xmm0, QWORD PTR __real@4014000000000000
        cvtsd2ss xmm0, xmm0
        ret      0

Sous /O2 /fp:fast le code généré est simplifié, car tous les casts de type sont optimisés :

        addss    xmm0, xmm1
        mulss    xmm0, DWORD PTR __real@40a00000
        ret      0

Pour définir cette option du compilateur dans l'environnement de développement Visual Studio

  1. Ouvrez la boîte de dialogue Pages de propriété du projet. Pour plus d’informations, consultez Définir le compilateur C++ et les propriétés de build dans Visual Studio.

  2. Sélectionnez la page de propriétés De configuration>C/C++>Génération de code.

  3. Modifiez la propriété Model à virgule flottante.

Pour définir cette option du compilateur par programmation

Voir aussi

Options du compilateur MSVC
Syntaxe de ligne de commande du compilateur MSVC