/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:precise
il 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:strict
il 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:fast
di , 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:fast
e altre ottimizzazioni possono essere disponibili tramite l'uso dell'opzione /arch
.
In /fp:fast
il 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 NaN
esempio . 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:except
e /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:strict
opzioni , /fp:fast
e /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_access
e 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 float
i valori , double
e 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
, _clearfp
e _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:fast
il 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:strict
le 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:strict
e /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:strict
e 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:strict
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 typecast possono essere usati per arrotondare in modo esplicito i calcoli intermedi. In /fp:fast
il 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
Aprire la finestra di dialogo Pagine delle proprietà del progetto. Per informazioni dettagliate, vedere Impostare il compilatore e le proprietà di compilazione.
Selezionare la pagina delle proprietà Proprietà>di configurazione C/C++>Generazione codice.
Modificare la proprietà Modello a virgola mobile.
Per impostare l'opzione del compilatore a livello di codice
- Vedere floatingPointModel.
Vedi anche
Opzioni del compilatore MSVC
Sintassi della riga di comando del compilatore MSVC