/fp
(指定浮點行為)
指定編譯程式如何處理浮點表達式、優化和例外狀況。 /fp
選項會指定產生的程式代碼是否允許浮點環境變更為四捨五入模式、例外狀況遮罩和次正規行為,以及浮點狀態檢查是否傳回目前、精確的結果。 它會控制編譯程式是否會產生維護來源作業和表達式順序的程序代碼,並符合 NaN 傳播的標準。 或者,如果它會產生更有效率的程式代碼,可能會重新排序或合併作業,並使用簡化 IEEE-754 標準不允許的代數轉換。
語法
/fp:contract
/fp:except
[-
]
/fp:fast
/fp:precise
/fp:strict
/fp:except
[-
]
/fp:fast
/fp:precise
/fp:strict
引數
/fp:contract
選項 /fp:contract
可讓編譯程式在指定 /fp:precise
和 /fp:except
選項時產生浮點合約。 收縮是結合浮點運算的計算機指令,例如 Fused-Multiply-Add (FMA)。 FMA 定義為 IEEE-754 的基本運算,不會在加法之前四捨五入中繼乘積,因此結果可能與不同的乘法和加法運算不同。 由於它是實作為單一指令,所以其速度可能會比個別的指令更快。 速度代價是位確切的結果,而且無法檢查中繼值。
根據預設, /fp:fast
選項會啟用 /fp:contract
。 選項 /fp:contract
與不相容 /fp:strict
。
此選項 /fp:contract
是 Visual Studio 2022 的新功能。
/fp:precise
根據預設,編譯程式會使用 /fp:precise
行為。
在下 /fp:precise
,編譯程式會在產生並優化目標機器的物件程序代碼時,保留浮點程式代碼的來源表達式排序和四捨五入屬性。 編譯程式會在表達式評估期間四個特定點四捨五入原始碼精確度:在指派、類型廣播、浮點自變數傳遞至函式呼叫,以及當函式呼叫傳回浮點值時。 中繼計算可能以機器精確度執行。 Typecasts 可用來明確四捨五入中繼計算。
編譯程式不會在浮點表達式上執行代數轉換,例如重新關聯或分佈,除非它可以保證轉換會產生位相同的結果。 涉及特殊值的表達式(NaN、+infinity、-infinity、-infinity、-0.0)會根據 IEEE-754 規格進行處理。 例如, x != x
評估為 true
如果 x
是 NaN。 浮點收縮預設不會在下 /fp:precise
產生。 此行為是Visual Studio 2022的新功能。 舊版編譯程序預設可能會在下 /fp:precise
產生合約。
編譯程式不會在浮點表達式上執行代數轉換,例如重新關聯或分佈,除非它可以保證轉換會產生位相同的結果。 涉及特殊值的表達式(NaN、+infinity、-infinity、-infinity、-0.0)會根據 IEEE-754 規格進行處理。 例如, x != x
評估為 true
如果 x
是 NaN。 浮點收縮可能會在下 /fp:precise
產生。
編譯程式會產生程序代碼,以在預設浮點環境中執行。 它也假設在運行時間不會存取或修改浮點環境。 也就是說,它會假設程序代碼:將浮點例外狀況保留遮罩、不會讀取或寫入浮點狀態緩存器,也不會變更四捨五入模式。
如果您的浮點程式代碼不相依於浮點語句中的作業和表達式順序(例如,如果您不在乎是否 a * b + a * c
計算為 (b + c) * a
或 2 * a
作為 a + a
),請考慮 /fp:fast
選項,這可以產生更快、更有效率的程序代碼。 如果您的程式代碼都相依於作業和表達式的順序,並存取或改變浮點環境(例如,若要變更四捨五入模式或設陷浮點例外狀況),請使用 /fp:strict
。
/fp:strict
/fp:strict
具有類似 /fp:precise
的行為,也就是說,編譯程式會在產生並優化目標機器的物件程序代碼時,保留浮點程式代碼的來源排序和四捨五入屬性,並在處理特殊值時觀察標準。 程式也可以在運行時間安全地存取或修改浮點環境。
在下 /fp:strict
,編譯程式會產生程序代碼,讓程式安全地解除遮罩浮點例外狀況、讀取或寫入浮點狀態緩存器,或變更四捨五入模式。 它會在表達式評估期間四個特定點四捨五入原始碼精確度:在指派、類型廣播、浮點自變數傳遞至函式呼叫時,以及當函式呼叫傳回浮點值時。 中繼計算可能以機器精確度執行。 Typecasts 可用來明確四捨五入中繼計算。 編譯程式不會在浮點表達式上進行任何代數轉換,例如重新關聯或分佈,除非它可以保證轉換會產生位相同的結果。 涉及特殊值的表達式(NaN、+infinity、-infinity、-infinity、-0.0)會根據 IEEE-754 規格進行處理。 例如, x != x
評估為 true
如果 x
是 NaN。 浮點收縮不會在下 /fp:strict
產生。
/fp:strict
比計算成本更高 /fp:precise
,因為編譯程式必須插入額外的指令來攔截例外狀況,並允許程式在運行時間存取或修改浮點環境。 如果您的程式代碼未使用這項功能,但需要原始程式碼排序和四捨五入,或依賴特殊值,請使用 /fp:precise
。 否則,請考慮使用 /fp:fast
,這會產生更快且較小的程序代碼。
/fp:fast
選項 /fp:fast
可讓編譯程式重新排序、合併或簡化浮點運算,以優化速度與空間的浮點程序代碼。 編譯程式可能會省略指派語句、typecasts 或函式呼叫的四捨五入。 例如,它可以使用關聯和散發法來重新排序作業或進行代數轉換。 即使這類轉換會導致明顯不同的四捨五入行為,它也可能會重新排序程序代碼。 由於這項增強的優化,某些浮點運算的結果可能會與其他選項所產生的 /fp
不同。 特殊值(NaN、+infinity、-infinity、-0.0)可能不會根據 IEEE-754 標準傳播或行為嚴格。 浮點收縮可能會在下 /fp:fast
產生。 編譯程式仍然受到 底下 /fp:fast
的基礎架構所系結,而且可以使用 選項來取得 /arch
更多優化。
在下 /fp:fast
,編譯程式會產生要在預設浮點環境中執行的程序代碼,並假設在運行時間不會存取或修改浮點環境。 也就是說,它會假設程序代碼:將浮點例外狀況保留遮罩、不會讀取或寫入浮點狀態緩存器,也不會變更四捨五入模式。
/fp:fast
適用於不需要嚴格原始程式碼排序和四捨五入浮點表達式的程式,而且不依賴標準規則來處理特殊值,例如 NaN
。 如果您的浮點程式代碼需要保留原始程式碼排序和四捨五入,或依賴特殊值的標準行為,請使用 /fp:precise
。 如果您的程式代碼存取或修改浮點環境以變更四捨五入模式、取消遮罩浮點例外狀況,或檢查浮點狀態,請使用 /fp:strict
。
/fp:except
選項 /fp:except
會產生程序代碼,以確保任何未遮罩的浮點例外狀況都會在發生的確切點引發,而且不會引發任何其他浮點例外狀況。 根據預設, /fp:strict
選項會啟用 /fp:except
,而且 /fp:precise
不會。 選項 /fp:except
與不相容 /fp:fast
。 選項可以使用 來明確停用 /fp:except-
。
本身不會 /fp:except
啟用任何浮點例外狀況。 不過,程式必須啟用浮點例外狀況。 如需如何啟用浮點例外狀況的詳細資訊,請參閱 _controlfp
。
備註
您可以在相同的編譯程式命令列中指定多個 /fp
選項。 一次只能有一個 /fp:strict
、 /fp:fast
和 /fp:precise
選項生效。 如果您在命令行上指定其中一個以上的選項,則較新的選項會優先使用,編譯程式會產生警告。 /fp:strict
和 /fp:except
選項與不相容/clr
。
/Za
[ANSI 兼容性] 選項與 不相容/fp
。
使用編譯程式指示詞來控制浮點行為
編譯程式提供三個 pragma 指示詞來覆寫命令行上指定的浮點行為: float_control
、 fenv_access
和 fp_contract
。 您可以使用這些指示詞來控制函式層級的浮點行為,而不是在函式內。 這些指示詞不會直接對應至 /fp
選項。 下表顯示選項和 pragma 指示詞如何 /fp
彼此對應。 如需詳細資訊,請參閱個別選項和 pragma 指示詞的檔。
選項 | 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 |
* 在 Visual Studio 2022 之前的 Visual Studio 版本中, /fp:precise
行為預設為 fp_contract(on)
。
選項 | 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 |
* 從 Visual Studio 2022 開始的 Visual Studio 版本中, /fp:precise
行為預設為 fp_contract(off)
。
默認浮點環境
初始化進程時,會 設定預設浮點環境 。 此環境會遮罩所有浮點例外狀況、將四捨五入模式設定為四捨五入至最接近(FE_TONEAREST
)、保留次正規值(反正規值)float
double
值、使用、、 和 long double
值的預設精確度,以及支援的位置,將無限控件設定為預設的仿射模式。
浮點環境存取和修改
Microsoft Visual C++ 執行時間提供數個函式來存取和修改浮點環境。 這些包括 _controlfp
、 _clearfp
和 _statusfp
及其變體。 若要在程式代碼存取或修改浮點環境時確保正確的程式行為, fenv_access
必須透過 /fp:strict
選項或使用 fenv_access
pragma 來啟用,這些函式才能有任何作用。 未啟用時 fenv_access
,浮點環境的存取或修改可能會導致非預期的程序行為:
程序代碼可能不接受對浮點環境的要求變更,
浮點狀態緩存器可能不會報告預期或目前的結果,
可能發生非預期的浮點例外狀況,或可能發生預期的浮點例外狀況。
當您的程式代碼存取或修改浮點環境時,當您結合已啟用的程式代碼與未fenv_access
啟用的程式代碼fenv_access
時,必須小心。 在未啟用的程式代碼 fenv_access
中,編譯程式會假設平台默認浮點環境有效。 它也會假設不會存取或修改浮點狀態。 建議您先將本機浮點環境儲存並還原為其默認狀態,再將控件傳送至未 fenv_access
啟用的函式。 此範例示範如何 float_control
設定和還原 pragma:
#pragma float_control(precise, on, push)
// Code that uses /fp:strict mode
#pragma float_control(pop)
浮點四捨五入模式
/fp:precise
在和/fp:fast
下,編譯程式會產生程序代碼,以在預設浮點環境中執行。 它假設環境不會在運行時間存取或修改。 也就是說,編譯程式會假設程式代碼永遠不會解除遮罩浮點例外狀況、讀取或寫入浮點狀態緩存器,或變更四捨五入模式。 不過,有些程式需要改變浮點環境。 例如,此範例會藉由改變浮點四捨五入模式來計算浮點乘法的錯誤界限:
// 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;
}
由於編譯程式假設 和/fp:precise
下/fp:fast
的預設浮點環境,因此可以忽略 對_controlfp_s
的呼叫。 例如,使用和 /fp:precise
來編譯 /O2
x86 架構時,不會計算界限,而且範例程式會輸出:
cLower = -inf
cUpper = -inf
/O2
使用和 /fp:strict
編譯 x86 架構時,範例程式會輸出:
cLower = -inf
cUpper = -3.40282e+38
浮點特殊值
在 和 /fp:strict
下/fp:precise
,涉及特殊值的表達式 (NaN, +infinity, -infinity, -0.0) 會根據 IEEE-754 規格運作。 在下 /fp:fast
,這些特殊值的行為可能與 IEEE-754 不一致。
此範例示範 、 /fp:strict
和 /fp:fast
底下/fp:precise
特殊值的不同行為:
// 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;
}
使用 /O2 /fp:precise
或 /O2 /fp:strict
進行 x86 架構編譯時,輸出會與 IEEE-754 規格一致:
INFINITY == INFINITY : 1
NAN == NAN : 0
INFINITY - INFINITY : -nan(ind)
NAN - NAN : nan
std::signbit(-0.0/-INFINITY): 0
使用 /O2 /fp:fast
** 進行 x86 架構編譯時,輸出與 IEEE-754 不一致:
INFINITY == INFINITY : 1
NAN == NAN : 1
INFINITY - INFINITY : 0.000000
NAN - NAN : 0.000000
std::signbit(-0.0/-INFINITY): 0
浮點代數轉換
在 和/fp:strict
下/fp:precise
,除非保證轉換會產生位相同的結果,否則編譯程式不會執行任何數學轉換。 編譯程式可能會在下 /fp:fast
進行這類轉換。 例如,範例algebraic_transformation
函式中的運算式a * b + a * c
可能會在下/fp:fast
編譯成 a * (b + c)
。 這類轉換不會在 或/fp:strict
下/fp:precise
完成,編譯程式會產生 a * b + a * c
。
float algebraic_transformation (float a, float b, float c)
{
return a * b + a * c;
}
浮點明確轉換點
在和 /fp:strict
下/fp:precise
,編譯程式會在表達式評估期間四個特定點四捨五入原始碼精確度:在指派、類型廣播、浮點自變數傳遞至函式呼叫,以及當函式呼叫傳回浮點值時。 Typecasts 可用來明確四捨五入中繼計算。 在下 /fp:fast
,編譯程式不會在這些點產生明確的轉換,以確保原始碼精確度。 此範例示範不同 /fp
選項下的行為:
float casting(float a, float b)
{
return 5.0*((double)(a+b));
}
使用 /O2 /fp:precise
或 /O2 /fp:strict
編譯時,您可以看到在 typecast 和函式傳回點插入明確型別轉換,並插入 x64 架構產生的程式代碼:
addss xmm0, xmm1
cvtss2sd xmm0, xmm0
mulsd xmm0, QWORD PTR __real@4014000000000000
cvtsd2ss xmm0, xmm0
ret 0
在產生的程式代碼下 /O2 /fp:fast
會簡化,因為所有類型轉換都會優化:
addss xmm0, xmm1
mulss xmm0, DWORD PTR __real@40a00000
ret 0
在 Visual Studio 開發環境中設定這個編譯器選項
開啟專案的 [屬性頁] 對話方塊。 如需詳細資料,請參閱在 Visual Studio 中設定 C ++ 編譯器和組建屬性。
選取 [組態屬性>C/C++>Code 產生] 屬性頁。
修改浮點模型屬性。
若要以程式方式設定這個編譯器選項
- 請參閱 floatingPointModel。