/fp (Specificare il comportamento a virgola mobile)

Specifica il modo in cui il compilatore gestisce espressioni a virgola mobile, ottimizzazioni ed eccezioni. Le /fp opzioni specificano se il codice generato consente modifiche all'ambiente a virgola mobile alla modalità di arrotondamento, alle maschere di eccezione e al comportamento subnormali e se i controlli di stato a virgola mobile restituiscono risultati correnti e accurati. Controlla se il compilatore genera codice che gestisce l'operazione di origine e l'ordine delle espressioni e è conforme allo standard per la propagazione NaN. In alternativa, se genera codice più efficiente che può riordinare o combinare operazioni e usare la semplificazione delle trasformazioni algebriche non consentite dallo standard IEEE-754.

Sintassi

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

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

Argomenti

/fp:contract

L'opzione /fp:contract consente al compilatore di generare contrazioni a virgola mobile quando si specificano le /fp:precise opzioni e /fp:except . Una contrazione è un'istruzione di macchina che combina operazioni a virgola mobile, ad esempio Fused-Multiply-Add (FMA). FMA, definito come operazione di base da IEEE-754, non arrotonda il prodotto intermedio prima dell'aggiunta, quindi il risultato può differire dalle operazioni di moltiplicazione e addizione separate. Poiché viene implementato come singola istruzione, può essere più veloce rispetto alle istruzioni separate. La velocità comporta un costo di risultati esatti bit per bit e l'impossibilità di esaminare il valore intermedio.

Per impostazione predefinita, l'opzione /fp:fast abilita /fp:contract. L'opzione /fp:contract non è compatibile con /fp:strict.

L'opzione /fp:contract è una novità di Visual Studio 2022.

/fp:precise

Per impostazione predefinita, il compilatore usa /fp:precise il comportamento.

In /fp:preciseil compilatore mantiene le proprietà di ordinamento e arrotondamento delle espressioni di origine del codice a virgola mobile quando genera e ottimizza il codice oggetto per il computer di destinazione. Il compilatore esegue l'arrotondamento alla precisione del codice sorgente in quattro punti specifici durante la valutazione dell'espressione: in corrispondenza di assegnazioni, typecast, quando gli argomenti a virgola mobile vengono passati a una chiamata di funzione e quando una chiamata di funzione restituisce un valore a virgola mobile. I calcoli intermedi possono essere eseguiti con precisione del computer. I typecast possono essere usati per arrotondare in modo esplicito i calcoli intermedi.

Il compilatore non esegue trasformazioni algebriche su espressioni a virgola mobile, ad esempio la riassociazione o la distribuzione, a meno che non possa garantire che la trasformazione produca un risultato identico bit per bit. Le espressioni che coinvolgono valori speciali (NaN, +infinity, -infinity, -0.0) vengono elaborate in base alle specifiche IEEE-754. Ad esempio, x != x restituisce true se x è NaN. Le contrazioni a virgola mobile non vengono generate per impostazione predefinita in /fp:precise. Questo comportamento è una novità di Visual Studio 2022. Le versioni precedenti del compilatore possono generare contrazioni per impostazione predefinita in /fp:precise.

Il compilatore non esegue trasformazioni algebriche su espressioni a virgola mobile, ad esempio la riassociazione o la distribuzione, a meno che non possa garantire che la trasformazione produca un risultato identico bit per bit. Le espressioni che coinvolgono valori speciali (NaN, +infinity, -infinity, -0.0) vengono elaborate in base alle specifiche IEEE-754. Ad esempio, x != x restituisce true se x è NaN. Le contrazioni a virgola mobile possono essere generate in /fp:precise.

Il compilatore genera il codice da eseguire nell'ambiente a virgola mobile predefinito. Presuppone anche che l'ambiente a virgola mobile non sia accessibile o modificato in fase di esecuzione. Ovvero, presuppone che il codice: lascia mascherate le eccezioni a virgola mobile, non legge o scrive registri di stato a virgola mobile e non modifica le modalità di arrotondamento.

Se il codice a virgola mobile non dipende dall'ordine delle operazioni e delle espressioni nelle istruzioni a virgola mobile, ad esempio se non è importante calcolare a * b + a * c come (b + c) * a o 2 * a come a + a, considerare l'opzione /fp:fast , che può produrre codice più veloce ed efficiente. Se il codice dipende dall'ordine di operazioni ed espressioni e accede o modifica l'ambiente a virgola mobile, ad esempio per modificare le modalità di arrotondamento o per intercettare le eccezioni a virgola mobile, usare /fp:strict.

/fp:strict

/fp:strict ha un comportamento simile a /fp:precise, ovvero il compilatore mantiene le proprietà di ordinamento e arrotondamento di origine di codice a virgola mobile quando genera e ottimizza il codice oggetto per il computer di destinazione e osserva lo standard quando gestisce valori speciali. Il programma può anche accedere in modo sicuro o modificare l'ambiente a virgola mobile in fase di esecuzione.

In /fp:strictil compilatore genera codice che consente al programma di annullare il mascheramento delle eccezioni a virgola mobile, di lettura o scrittura di registri di stato a virgola mobile o di modificare le modalità di arrotondamento. Esegue l'arrotondamento alla precisione del codice sorgente in quattro punti specifici durante la valutazione dell'espressione: in corrispondenza di assegnazioni, typecast, quando gli argomenti a virgola mobile vengono passati a una chiamata di funzione e quando una chiamata di funzione restituisce un valore a virgola mobile. I calcoli intermedi possono essere eseguiti con precisione del computer. I typecast possono essere usati per arrotondare in modo esplicito i calcoli intermedi. Il compilatore non esegue alcuna trasformazione algebrica su espressioni a virgola mobile, ad esempio la riassociazione o la distribuzione, a meno che non possa garantire che la trasformazione produca un risultato identico bit per bit. Le espressioni che coinvolgono valori speciali (NaN, +infinity, -infinity, -0.0) vengono elaborate in base alle specifiche IEEE-754. Ad esempio, x != x restituisce true se x è NaN. Le contrazioni a virgola mobile non vengono generate in /fp:strict.

/fp:strict è computazionale più costoso rispetto /fp:precise al fatto che il compilatore deve inserire istruzioni aggiuntive per intercettare le eccezioni e consentire ai programmi di accedere o modificare l'ambiente a virgola mobile in fase di esecuzione. Se il codice non usa questa funzionalità, ma richiede l'ordinamento e l'arrotondamento del codice sorgente oppure si basa su valori speciali, usare /fp:precise. In caso contrario, prendere in considerazione l'uso /fp:fastdi , che può produrre codice più veloce e più piccolo.

/fp:fast

L'opzione /fp:fast consente al compilatore di riordinare, combinare o semplificare le operazioni a virgola mobile per ottimizzare il codice a virgola mobile per velocità e spazio. Il compilatore può omettere l'arrotondamento in corrispondenza di istruzioni di assegnazione, typecast o chiamate di funzione. Può riordinare le operazioni o apportare trasformazioni algebriche, ad esempio, usando leggi associative e di distribuzione. Può riordinare il codice anche se tali trasformazioni comportano un comportamento di arrotondamento osservabile diverso. A causa di questa ottimizzazione avanzata, il risultato di alcuni calcoli a virgola mobile può differire da quelli prodotti da altre /fp opzioni. I valori speciali (NaN, +infinity, -infinity, -0.0) non possono essere propagati o si comportano rigorosamente in base allo standard IEEE-754. Le contrazioni a virgola mobile possono essere generate in /fp:fast. Il compilatore è ancora associato dall'architettura sottostante in /fp:faste altre ottimizzazioni possono essere disponibili tramite l'uso dell'opzione /arch .

In /fp:fastil compilatore genera codice destinato all'esecuzione nell'ambiente a virgola mobile predefinito e presuppone che l'ambiente a virgola mobile non sia accessibile o modificato in fase di esecuzione. Ovvero, presuppone che il codice: lascia mascherate le eccezioni a virgola mobile, non legge o scrive registri di stato a virgola mobile e non modifica le modalità di arrotondamento.

/fp:fast è destinato a programmi che non richiedono l'ordinamento rigoroso del codice sorgente e l'arrotondamento delle espressioni a virgola mobile e non si basano sulle regole standard per la gestione di valori speciali, ad NaNesempio . Se il codice a virgola mobile richiede la conservazione dell'ordinamento e dell'arrotondamento del codice sorgente o si basa sul comportamento standard dei valori speciali, usare /fp:precise. Se il codice accede o modifica l'ambiente a virgola mobile per modificare le modalità di arrotondamento, annullare il mascheramento delle eccezioni a virgola mobile o controllare lo stato a virgola mobile, usare /fp:strict.

/fp:except

L'opzione /fp:except genera codice per garantire che tutte le eccezioni a virgola mobile non mascherate vengano generate nel punto esatto in cui si verificano e che non vengano generate altre eccezioni a virgola mobile. Per impostazione predefinita, l'opzione /fp:strict abilita /fp:excepte /fp:precise non. L'opzione /fp:except non è compatibile con /fp:fast. L'opzione può essere disabilitata in modo esplicito tramite /fp:except-.

Da solo, /fp:except non abilita eccezioni a virgola mobile. Tuttavia, è necessario per i programmi abilitare le eccezioni a virgola mobile. Per altre informazioni su come abilitare le eccezioni a virgola mobile, vedere _controlfp.

Osservazioni:

È possibile specificare più /fp opzioni nella stessa riga di comando del compilatore. Solo una delle /fp:strictopzioni , /fp:faste /fp:precise può essere applicata alla volta. Se si specificano più di una di queste opzioni nella riga di comando, l'opzione successiva ha la precedenza e il compilatore genera un avviso. Le /fp:strict opzioni e /fp:except non sono compatibili con /clr.

L'opzione /Za (compatibilità ANSI) non è compatibile con /fp.

Uso delle direttive del compilatore per controllare il comportamento a virgola mobile

Il compilatore fornisce tre direttive pragma per eseguire l'override del comportamento a virgola mobile specificato nella riga di comando: float_control, fenv_accesse fp_contract. È possibile usare queste direttive per controllare il comportamento a virgola mobile a livello di funzione, non all'interno di una funzione. Queste direttive non corrispondono direttamente alle /fp opzioni. Questa tabella illustra il mapping tra le opzioni e le /fp direttive pragma. Per altre informazioni, vedere la documentazione relativa alle singole opzioni e direttive pragma.

Opzione 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

* Nelle versioni di Visual Studio precedenti a Visual Studio 2022, il /fp:precise comportamento predefinito è fp_contract(on).

Opzione 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

* Nelle versioni di Visual Studio a partire da Visual Studio 2022, il /fp:precise comportamento predefinito è fp_contract(off).

Ambiente a virgola mobile predefinito

Quando un processo viene inizializzato, viene impostato l'ambiente a virgola mobile predefinito. Questo ambiente maschera tutte le eccezioni a virgola mobile, imposta la modalità di arrotondamento su più vicino (FE_TONEAREST), mantiene i valori sottonormali (denormali), usa la precisione predefinita di significand (mantissa) per floati valori , doublee long double e, se supportato, imposta il controllo infinity sulla modalità affine predefinita.

Accesso e modifica all'ambiente a virgola mobile

Il runtime di Microsoft Visual C++ fornisce diverse funzioni per accedere e modificare l'ambiente a virgola mobile. Tra cui _controlfp, _clearfpe _statusfp le relative varianti. Per garantire un comportamento corretto del programma quando il codice accede o modifica l'ambiente a virgola mobile, fenv_access deve essere abilitato, tramite l'opzione /fp:strict o tramite il fenv_access pragma, affinché queste funzioni abbiano alcun effetto. Quando fenv_access non è abilitato, l'accesso o la modifica dell'ambiente a virgola mobile possono comportare un comportamento imprevisto del programma:

  • Il codice potrebbe non rispettare le modifiche richieste all'ambiente a virgola mobile,

  • I registri di stato a virgola mobile potrebbero non segnalare i risultati previsti o correnti,

  • È possibile che si verifichino eccezioni a virgola mobile impreviste o che non si verifichino eccezioni a virgola mobile previste.

Quando il codice accede o modifica l'ambiente a virgola mobile, è necessario prestare attenzione quando si combina il codice in cui fenv_access è abilitato con il codice che non è fenv_access abilitato. Nel codice in cui fenv_access non è abilitato, il compilatore presuppone che l'ambiente a virgola mobile predefinito della piattaforma sia attivo. Presuppone inoltre che lo stato a virgola mobile non sia accessibile o modificato. È consigliabile salvare e ripristinare lo stato predefinito dell'ambiente a virgola mobile locale prima che il controllo venga trasferito a una funzione che non è fenv_access abilitata. In questo esempio viene illustrato come impostare e ripristinare il float_control pragma:

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

Modalità di arrotondamento a virgola mobile

/fp:precise In e /fp:fastil compilatore genera codice destinato all'esecuzione nell'ambiente a virgola mobile predefinito. Si presuppone che l'ambiente non sia accessibile o modificato in fase di esecuzione. Ovvero, il compilatore presuppone che il codice non smascheri mai le eccezioni a virgola mobile, le letture o le scritture dei registri di stato a virgola mobile o cambi le modalità di arrotondamento. Tuttavia, alcuni programmi devono modificare l'ambiente a virgola mobile. Ad esempio, questo esempio calcola i limiti di errore di una moltiplicazione a virgola mobile modificando le modalità di arrotondamento a virgola mobile:

// 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;
}

Poiché il compilatore presuppone l'ambiente a virgola mobile predefinito in /fp:fast e /fp:precise, è possibile ignorare le chiamate a _controlfp_s. Ad esempio, quando viene compilato usando e /O2 /fp:precise per l'architettura x86, i limiti non vengono calcolati e l'output del programma di esempio:

cLower = -inf
cUpper = -inf

Quando viene compilato usando sia /O2 che /fp:strict per l'architettura x86, il programma di esempio restituisce:

cLower = -inf
cUpper = -3.40282e+38

Valori speciali a virgola mobile

In /fp:precise e /fp:strictle espressioni che coinvolgono valori speciali (NaN, +infinity, -infinity, -0.0) si comportano in base alle specifiche IEEE-754. In /fp:fast, il comportamento di questi valori speciali può essere incoerente con IEEE-754.

Questo esempio illustra il diverso comportamento dei valori speciali in /fp:precise, /fp:stricte /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;
}

Quando viene compilato usando /O2 /fp:precise o /O2 /fp:strict per l'architettura x86, gli output sono coerenti con la specifica IEEE-754:

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

Quando viene compilato usando /O2 /fp:fast** per l'architettura x86, gli output non sono coerenti con IEEE-754:

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

Trasformazioni algebriche a virgola mobile

In /fp:precise e /fp:strict, il compilatore non esegue alcuna trasformazione matematica, a meno che la trasformazione non generi un risultato bit per bit identico. Il compilatore può eseguire tali trasformazioni in /fp:fast. Ad esempio, l'espressione a * b + a * c nella funzione algebraic_transformation di esempio può essere compilata in in a * (b + c) /fp:fast. Tali trasformazioni non vengono eseguite in /fp:precise o /fp:stricte il compilatore genera a * b + a * c.

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

Punti di cast espliciti a virgola mobile

In /fp:precise e /fp:strictil compilatore esegue l'arrotondamento alla precisione del codice sorgente in quattro punti specifici durante la valutazione dell'espressione: in corrispondenza di assegnazioni, typecast, quando gli argomenti a virgola mobile vengono passati a una chiamata di funzione e quando una chiamata di funzione restituisce un valore a virgola mobile. I typecast possono essere usati per arrotondare in modo esplicito i calcoli intermedi. In /fp:fastil compilatore non genera cast espliciti in questi punti per garantire la precisione del codice sorgente. Questo esempio illustra il comportamento in diverse /fp opzioni:

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

Quando viene compilato usando /O2 /fp:precise o /O2 /fp:strict, è possibile notare che i cast di tipi espliciti vengono inseriti sia nel typecast che nel punto restituito della funzione nel codice generato per l'architettura x64:

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

Nel /O2 /fp:fast codice generato viene semplificato, perché tutti i cast di tipo sono ottimizzati:

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

Per impostare l'opzione del compilatore nell'ambiente di sviluppo di Visual Studio

  1. Aprire la finestra di dialogo Pagine delle proprietà del progetto. Per informazioni dettagliate, vedere Impostare il compilatore e le proprietà di compilazione.

  2. Selezionare la pagina delle proprietà Proprietà>di configurazione C/C++>Generazione codice.

  3. Modificare la proprietà Modello a virgola mobile.

Per impostare l'opzione del compilatore a livello di codice

Vedi anche

Opzioni del compilatore MSVC
Sintassi della riga di comando del compilatore MSVC