/fp
(Określ zachowanie zmiennoprzecinkowe)
Określa sposób traktowania przez kompilator wyrażeń zmiennoprzecinkowych, optymalizacji i wyjątków. Opcje /fp
określają, czy wygenerowany kod umożliwia zmianę środowiska zmiennoprzecinkowego w trybie zaokrąglania, maskach wyjątków i zachowaniu podnormalnych oraz czy testy stanu zmiennoprzecinkowe zwracają bieżące, dokładne wyniki. Określa, czy kompilator generuje kod, który obsługuje operację źródłową i kolejność wyrażeń, i jest zgodny ze standardem propagacji NaN. Lub, jeśli zamiast tego generuje bardziej wydajny kod, który może zmienić kolejność lub połączyć operacje i używać upraszczających transformacji algebraicznych, które nie są dozwolone przez standard IEEE-754.
Składnia
/fp:contract
/fp:except
[-
]
/fp:fast
/fp:precise
/fp:strict
/fp:except
[-
]
/fp:fast
/fp:precise
/fp:strict
Argumenty
/fp:contract
Opcja /fp:contract
umożliwia kompilatorowi generowanie skurczów zmiennoprzecinkowych podczas określania /fp:precise
opcji i /fp:except
. Skurcz to instrukcja maszynowa, która łączy operacje zmiennoprzecinkowe, takie jak Fused-Multiply-Add (FMA). FMA, zdefiniowane jako podstawowa operacja ieee-754, nie zaokrągla produktu pośredniego przed dodatkami, więc wynik może różnić się od oddzielnych operacji mnożenia i dodawania. Ponieważ jest on implementowany jako pojedyncza instrukcja, może być szybszy niż oddzielne instrukcje. Szybkość jest kosztem bitowych dokładnych wyników i niezdolnością do zbadania wartości pośredniej.
Domyślnie /fp:fast
opcja włącza wartość /fp:contract
. Opcja nie jest zgodna /fp:contract
z /fp:strict
programem .
Opcja /fp:contract
jest nowa w programie Visual Studio 2022.
/fp:precise
Domyślnie kompilator używa /fp:precise
zachowania.
W obszarze /fp:precise
kompilator zachowuje kolejność wyrażeń źródłowych i zaokrąglanie właściwości kodu zmiennoprzecinkowego podczas generowania i optymalizowania kodu obiektu dla maszyny docelowej. Kompilator zaokrągla precyzję kodu źródłowego do czterech konkretnych punktów podczas oceny wyrażeń: przy przydziałach, emisjach typów, gdy argumenty zmiennoprzecinkowe są przekazywane do wywołania funkcji, a gdy wywołanie funkcji zwraca wartość zmiennoprzecinkową. Obliczenia pośrednie mogą być wykonywane z dokładnością maszyny. Emisje typów mogą służyć do jawnego zaokrąglania obliczeń pośrednich.
Kompilator nie wykonuje przekształceń algebraicznych w wyrażeniach zmiennoprzecinkowych, takich jak ponowne skojarzenie lub rozkład, chyba że może zagwarantować, że transformacja generuje bitowo identyczny wynik. Wyrażenia obejmujące wartości specjalne (NaN, +nieskończoność, -nieskończoność, -0,0) są przetwarzane zgodnie ze specyfikacjami IEEE-754. Na przykład oblicza wartość true
, x != x
jeśli x
jest to NaN. Kontrakty zmiennoprzecinkowe nie są domyślnie generowane w obszarze /fp:precise
. To zachowanie jest nowe w programie Visual Studio 2022. Poprzednie wersje kompilatora mogą domyślnie generować skurcze w obszarze /fp:precise
.
Kompilator nie wykonuje przekształceń algebraicznych w wyrażeniach zmiennoprzecinkowych, takich jak ponowne skojarzenie lub rozkład, chyba że może zagwarantować, że transformacja generuje bitowo identyczny wynik. Wyrażenia obejmujące wartości specjalne (NaN, +nieskończoność, -nieskończoność, -0,0) są przetwarzane zgodnie ze specyfikacjami IEEE-754. Na przykład oblicza wartość true
, x != x
jeśli x
jest to NaN. Kontrakty zmiennoprzecinkowe mogą być generowane w obszarze /fp:precise
.
Kompilator generuje kod przeznaczony do uruchomienia w domyślnym środowisku zmiennoprzecinkowa. Przyjęto również założenie, że środowisko zmiennoprzecinkowe nie jest dostępne ani modyfikowane w czasie wykonywania. Oznacza to, że przyjęto założenie, że kod: pozostawia zamaskowane wyjątki zmiennoprzecinkowe, nie odczytuje ani nie zapisuje rejestrów stanu zmiennoprzecinkowych i nie zmienia trybów zaokrąglania.
Jeśli kod zmiennoprzecinkowy nie zależy od kolejności operacji i wyrażeń w instrukcjach zmiennoprzecinkowych (na przykład jeśli nie obchodzi się, czy a * b + a * c
jest obliczany jako (b + c) * a
lub 2 * a
jako a + a
), rozważ /fp:fast
opcję, która może szybciej wygenerować, wydajniejszy kod. Jeśli kod zależy od kolejności operacji i wyrażeń oraz uzyskuje dostęp do środowiska zmiennoprzecinkowego lub zmienia je (na przykład w celu zmiany trybów zaokrąglania lub wychwytowania wyjątków zmiennoprzecinkowych), użyj polecenia /fp:strict
.
/fp:strict
/fp:strict
ma zachowanie podobne do /fp:precise
, czyli kompilator zachowuje właściwości kolejności źródłowej i zaokrąglania kodu zmiennoprzecinkowego podczas generowania i optymalizowania kodu obiektu dla maszyny docelowej i obserwuje standard podczas obsługi wartości specjalnych. Program może również bezpiecznie uzyskiwać dostęp do środowiska zmiennoprzecinkowego lub modyfikować je w czasie wykonywania.
W obszarze /fp:strict
kompilator generuje kod, który umożliwia programowi bezpieczne odmaskowanie wyjątków zmiennoprzecinkowych, odczytywanie lub zapisywanie rejestrów stanu zmiennoprzecinkowych lub zmienianie trybów zaokrąglania. Jest zaokrąglany do dokładności kodu źródłowego w czterech konkretnych punktach podczas oceny wyrażeń: przy przypisań, emisjach typów, gdy argumenty zmiennoprzecinkowe są przekazywane do wywołania funkcji, a gdy wywołanie funkcji zwraca wartość zmiennoprzecinkowa. Obliczenia pośrednie mogą być wykonywane z dokładnością maszyny. Emisje typów mogą służyć do jawnego zaokrąglania obliczeń pośrednich. Kompilator nie tworzy żadnych przekształceń algebraicznych w wyrażeniach zmiennoprzecinkowych, takich jak ponowne skojarzenie lub rozkład, chyba że może zagwarantować, że transformacja generuje bitowo identyczny wynik. Wyrażenia obejmujące wartości specjalne (NaN, +nieskończoność, -nieskończoność, -0,0) są przetwarzane zgodnie ze specyfikacjami IEEE-754. Na przykład oblicza wartość true
, x != x
jeśli x
jest to NaN. Kontrakty zmiennoprzecinkowe nie są generowane w obszarze /fp:strict
.
/fp:strict
jest obliczanie droższe niż /fp:precise
dlatego, że kompilator musi wstawić dodatkowe instrukcje, aby wychwytować wyjątki i zezwolić programom na dostęp do środowiska zmiennoprzecinkowego lub zmodyfikować je w czasie wykonywania. Jeśli kod nie używa tej funkcji, ale wymaga porządkowania i zaokrąglania kodu źródłowego lub opiera się na specjalnych wartościach, użyj polecenia /fp:precise
. W przeciwnym razie rozważ użycie metody /fp:fast
, która może generować szybszy i mniejszy kod.
/fp:fast
Opcja /fp:fast
umożliwia kompilatorowi zmienianie kolejności, łączenie lub upraszczanie operacji zmiennoprzecinkowych w celu zoptymalizowania kodu zmiennoprzecinkowego pod kątem szybkości i miejsca. Kompilator może pominąć zaokrąglanie instrukcji przypisania, emisji typów lub wywołań funkcji. Może zmieniać kolejność operacji lub przekształcać algebraiczne, na przykład przy użyciu przepisów asocjacyjnych i dystrybucyjnych. Może zmienić kolejność kodu, nawet jeśli takie przekształcenia powodują zauważalne różne zachowanie zaokrąglania. Ze względu na tę ulepszoną optymalizację wynik niektórych obliczeń zmiennoprzecinkowych może się różnić od tych generowanych przez inne /fp
opcje. Wartości specjalne (NaN, +nieskończoność, -nieskończoność, -0,0) mogą nie być propagowane ani zachowywać się ściśle zgodnie ze standardem IEEE-754. Kontrakty zmiennoprzecinkowe mogą być generowane w obszarze /fp:fast
. Kompilator jest nadal powiązany z podstawową architekturą w obszarze /fp:fast
, a więcej optymalizacji może być dostępnych za pomocą /arch
opcji .
W obszarze /fp:fast
kompilator generuje kod przeznaczony do uruchomienia w domyślnym środowisku zmiennoprzecinkowa i zakłada, że środowisko zmiennoprzecinkowe nie jest dostępne ani modyfikowane w czasie wykonywania. Oznacza to, że przyjęto założenie, że kod: pozostawia zamaskowane wyjątki zmiennoprzecinkowe, nie odczytuje ani nie zapisuje rejestrów stanu zmiennoprzecinkowych i nie zmienia trybów zaokrąglania.
/fp:fast
jest przeznaczony dla programów, które nie wymagają ścisłego porządkowania kodu źródłowego i zaokrąglania wyrażeń zmiennoprzecinkowych, i nie polegają na standardowych regułach obsługi wartości specjalnych, takich jak NaN
. Jeśli kod zmiennoprzecinkowa wymaga zachowania kolejności kodu źródłowego i zaokrąglania lub opiera się na standardowym zachowaniu wartości specjalnych, użyj polecenia /fp:precise
. Jeśli kod uzyskuje dostęp do środowiska zmiennoprzecinkowego lub modyfikuje je w celu zmiany trybów zaokrąglania, zdemaskuj wyjątki zmiennoprzecinkowe lub sprawdź stan zmiennoprzecinkowa, użyj polecenia /fp:strict
.
/fp:except
Opcja /fp:except
generuje kod w celu zapewnienia, że wszystkie niemaskowane wyjątki zmiennoprzecinkowe są zgłaszane w dokładnym punkcie, w którym występują, i że żadne inne wyjątki zmiennoprzecinkowe nie są zgłaszane. Domyślnie /fp:strict
opcja włącza /fp:except
element i /fp:precise
nie. Opcja nie jest zgodna /fp:except
z /fp:fast
programem . Opcja może być jawnie wyłączona przy użyciu polecenia /fp:except-
.
Samodzielnie /fp:except
nie włącza żadnych wyjątków zmiennoprzecinkowych. Jednak jest to wymagane, aby programy włączały wyjątki zmiennoprzecinkowe. Aby uzyskać więcej informacji na temat włączania wyjątków zmiennoprzecinkowych, zobacz _controlfp
.
Uwagi
Wiele /fp
opcji można określić w tym samym wierszu polecenia kompilatora. W danym momencie może obowiązywać tylko jedna z /fp:strict
opcji , /fp:fast
i /fp:precise
. Jeśli określisz więcej niż jedną z tych opcji w wierszu polecenia, późniejsza opcja ma pierwszeństwo, a kompilator generuje ostrzeżenie. Opcje /fp:strict
i /fp:except
nie są zgodne z /clr
.
Opcja /Za
(zgodność ze standardem ANSI) nie jest zgodna z /fp
programem .
Używanie dyrektyw kompilatora do kontrolowania zachowania zmiennoprzecinkowego
Kompilator udostępnia trzy dyrektywy pragma, aby zastąpić zachowanie zmiennoprzecinkowe określone w wierszu polecenia: float_control
, fenv_access
i fp_contract
. Za pomocą tych dyrektyw można kontrolować zachowanie zmiennoprzecinkowe na poziomie funkcji, a nie w funkcji. Te dyrektywy nie odpowiadają bezpośrednio opcjom /fp
. W tej tabeli przedstawiono sposób /fp
mapowania między sobą opcji i dyrektyw pragma. Aby uzyskać więcej informacji, zobacz dokumentację dotyczącą poszczególnych opcji i dyrektyw pragma.
Opcja | 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 |
* W wersjach programu Visual Studio przed programem Visual Studio 2022 /fp:precise
zachowanie jest domyślnie ustawione na fp_contract(on)
.
Opcja | 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 |
* W wersjach programu Visual Studio począwszy od programu Visual Studio 2022 /fp:precise
zachowanie jest domyślnie ustawione na fp_contract(off)
.
Domyślne środowisko zmiennoprzecinkowe
Po zainicjowaniu procesu zostanie ustawione domyślne środowisko zmiennoprzecinkowe . To środowisko maskuje wszystkie wyjątki zmiennoprzecinkowe, ustawia tryb zaokrąglania w celu zaokrąglenia do najbliższego (FE_TONEAREST
), zachowuje wartości podrzędne (denormal), używa domyślnej precyzji znakowej (mantissa) dla float
wartości , double
i long double
, gdzie jest obsługiwana, ustawia kontrolkę nieskończoności na domyślny tryb affine.
Dostęp i modyfikacja środowiska zmiennoprzecinkowego
Środowisko uruchomieniowe Microsoft Visual C++ udostępnia kilka funkcji umożliwiających dostęp do środowiska zmiennoprzecinkowego i modyfikowanie go. Obejmują one _controlfp
warianty , _clearfp
i _statusfp
. Aby zapewnić prawidłowe zachowanie programu w przypadku uzyskiwania dostępu do kodu lub modyfikowania środowiska zmiennoprzecinkowego, fenv_access
należy włączyć /fp:strict
opcję lub użyć fenv_access
pragma, aby te funkcje miały jakikolwiek wpływ. Jeśli fenv_access
nie jest włączona, dostęp lub modyfikacja środowiska zmiennoprzecinkowego może spowodować nieoczekiwane zachowanie programu:
Kod może nie honorować żądanych zmian w środowisku zmiennoprzecinkowa,
Rejestry stanu zmiennoprzecinkowego mogą nie zgłaszać oczekiwanych lub bieżących wyników.
Mogą wystąpić nieoczekiwane wyjątki zmiennoprzecinkowe lub oczekiwane wyjątki zmiennoprzecinkowe.
Gdy kod uzyskuje dostęp do środowiska zmiennoprzecinkowego lub go modyfikuje, należy zachować ostrożność podczas łączenia kodu, w którym fenv_access
jest włączony kod, który nie został fenv_access
włączony. W kodzie, w którym fenv_access
nie włączono, kompilator zakłada, że domyślne środowisko zmiennoprzecinkowe platformy działa. Przyjęto również założenie, że stan zmiennoprzecinkowa nie jest uzyskiwany ani modyfikowany. Zalecamy zapisanie i przywrócenie lokalnego środowiska zmiennoprzecinkowego do domyślnego stanu przed przeniesieniem kontrolki do funkcji, która nie została fenv_access
włączona. W tym przykładzie pokazano, jak float_control
można ustawić i przywrócić pragma:
#pragma float_control(precise, on, push)
// Code that uses /fp:strict mode
#pragma float_control(pop)
Tryby zaokrąglania zmiennoprzecinkowego
/fp:precise
Zarówno w systemach , jak i /fp:fast
kompilator generuje kod przeznaczony do uruchomienia w domyślnym środowisku zmiennoprzecinkowych. Przyjęto założenie, że środowisko nie jest dostępne ani modyfikowane w czasie wykonywania. Oznacza to, że kompilator zakłada, że kod nigdy nie maskuje wyjątków zmiennoprzecinkowych, odczytuje lub zapisuje rejestry stanu zmiennoprzecinkowe lub zmienia tryby zaokrąglania. Jednak niektóre programy muszą zmienić środowisko zmiennoprzecinkowe. Na przykład ten przykład oblicza granice błędów mnożenia zmiennoprzecinkowego przez zmianę trybów zaokrąglania zmiennoprzecinkowego:
// 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;
}
Ponieważ kompilator zakłada domyślne środowisko zmiennoprzecinkowe w obszarze /fp:fast
i /fp:precise
, można zignorować wywołania metody _controlfp_s
. Na przykład podczas kompilowania przy użyciu architektury /O2
i /fp:precise
dla architektury x86 granice nie są obliczane, a przykładowe dane wyjściowe programu:
cLower = -inf
cUpper = -inf
Podczas kompilowania przy użyciu architektury /O2
i /fp:strict
dla architektury x86 przykładowy program generuje następujące dane wyjściowe:
cLower = -inf
cUpper = -3.40282e+38
Wartości specjalne zmiennoprzecinkowe
W obszarze /fp:precise
i /fp:strict
wyrażenia, które obejmują wartości specjalne (NaN, +infinity, -infinity, -0.0) zachowują się zgodnie ze specyfikacjami IEEE-754. W obszarze /fp:fast
zachowanie tych wartości specjalnych może być niezgodne ze standardem IEEE-754.
W tym przykładzie pokazano różne zachowanie specjalnych wartości w elementach /fp:precise
, /fp:strict
i /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;
}
Podczas kompilowania przy użyciu /O2 /fp:precise
architektury x86 lub /O2 /fp:strict
dla architektury x86 dane wyjściowe są zgodne ze specyfikacją IEEE-754:
INFINITY == INFINITY : 1
NAN == NAN : 0
INFINITY - INFINITY : -nan(ind)
NAN - NAN : nan
std::signbit(-0.0/-INFINITY): 0
Podczas kompilowania przy użyciu polecenia /O2 /fp:fast
** dla architektury x86 dane wyjściowe nie są zgodne ze standardem IEEE-754:
INFINITY == INFINITY : 1
NAN == NAN : 1
INFINITY - INFINITY : 0.000000
NAN - NAN : 0.000000
std::signbit(-0.0/-INFINITY): 0
Przekształcenia algebraiczne zmiennoprzecinkowe
W systemach /fp:precise
i /fp:strict
kompilator nie wykonuje żadnych przekształceń matematycznych, chyba że ma gwarancję uzyskania nieco identycznego wyniku. Kompilator może wykonać takie przekształcenia w obszarze /fp:fast
. Na przykład wyrażenie a * b + a * c
w przykładowej funkcji algebraic_transformation
może zostać skompilowane w a * (b + c)
obszarze /fp:fast
. Takie przekształcenia nie są wykonywane w obszarze /fp:precise
lub /fp:strict
, a kompilator generuje a * b + a * c
element .
float algebraic_transformation (float a, float b, float c)
{
return a * b + a * c;
}
Punkty rzutujące jawne zmiennoprzecinkowe
W obszarze /fp:precise
i /fp:strict
kompilator zaokrągla do dokładności kodu źródłowego w czterech określonych punktach podczas obliczania wyrażenia: przy przypisaniach, emisjach typów, gdy argumenty zmiennoprzecinkowe są przekazywane do wywołania funkcji, a gdy wywołanie funkcji zwraca wartość zmiennoprzecinkową. Emisje typu mogą służyć do jawnego zaokrąglania obliczeń pośrednich. W obszarze /fp:fast
kompilator nie generuje jawnych rzutów w tych punktach, aby zagwarantować precyzję kodu źródłowego. W tym przykładzie pokazano zachowanie w różnych /fp
opcjach:
float casting(float a, float b)
{
return 5.0*((double)(a+b));
}
Podczas kompilowania przy użyciu funkcji /O2 /fp:precise
lub /O2 /fp:strict
można zobaczyć, że jawne rzutowania typów są wstawiane zarówno w rzutach typu, jak i w punkcie zwrotnym funkcji w wygenerowanym kodzie architektury x64:
addss xmm0, xmm1
cvtss2sd xmm0, xmm0
mulsd xmm0, QWORD PTR __real@4014000000000000
cvtsd2ss xmm0, xmm0
ret 0
W obszarze /O2 /fp:fast
wygenerowanego kodu jest uproszczony, ponieważ wszystkie rzuty typów są optymalizowane:
addss xmm0, xmm1
mulss xmm0, DWORD PTR __real@40a00000
ret 0
Aby ustawić tę opcję kompilatora w środowisku programowania Visual Studio
Otwórz okno dialogowe Strony właściwości projektu. Aby uzyskać szczegółowe informacje, zobacz Set C++ compiler and build properties in Visual Studio (Ustawianie właściwości kompilatora języka C++ i kompilowania w programie Visual Studio).
Wybierz stronę właściwości Właściwości> konfiguracjiC/C++>Code Generation.
Zmodyfikuj właściwość Model zmiennoprzecinkowa .
Aby programowo ustawić tę opcję kompilatora
- Zobacz: .
Zobacz też
Opcje kompilatora MSVC
Składnia wiersza polecenia kompilatora MSVC