/fp
(Určení chování s plovoucí desetinou čárkou)
Určuje, jak kompilátor zachází s výrazy s plovoucí desetinou čárkou, optimalizacemi a výjimkami. Možnosti /fp
určují, zda vygenerovaný kód umožňuje změny prostředí s plovoucí desetinou čárkou v režimu zaokrouhlování, masky výjimek a chování podnormální hodnoty a zda kontroly stavu s plovoucí desetinou čárkou vrací aktuální a přesné výsledky. Řídí, zda kompilátor generuje kód, který udržuje zdrojové operace a pořadí výrazů a odpovídá standardu šíření NaN. Nebo pokud místo toho generuje efektivnější kód, který může měnit pořadí nebo kombinovat operace a používat zjednodušení algebraických transformací, které nejsou povoleny standardem IEEE-754.
Syntaxe
/fp:contract
/fp:except
[-
]
/fp:fast
/fp:precise
/fp:strict
/fp:except
[-
]
/fp:fast
/fp:precise
/fp:strict
Argumenty
/fp:contract
Tato /fp:contract
možnost umožňuje kompilátoru generovat kontrakty s plovoucí desetinou čárkou při zadávání /fp:precise
a /fp:except
možnosti. Kontrakt je strojová instrukce, která kombinuje operace s plovoucí desetinnou čárkou, jako je například Fused-Multipli-Add (FMA). FMA, definované jako základní operace IEEE-754, nezaokrouhluje meziprodukt před sčítáním, takže výsledek se může lišit od samostatných operací násobení a sčítání. Vzhledem k tomu, že se implementuje jako jedna instrukce, může být rychlejší než samostatné instrukce. Rychlost přichází za cenu bitové přesné výsledky a neschopnost prozkoumat zprostředkující hodnotu.
Ve výchozím nastavení tato /fp:fast
možnost povolí /fp:contract
. Možnost /fp:contract
není kompatibilní s /fp:strict
.
Tato /fp:contract
možnost je nová v sadě Visual Studio 2022.
/fp:precise
Ve výchozím nastavení kompilátor používá /fp:precise
chování.
V části /fp:precise
kompilátor zachová řazení zdrojového výrazu a zaokrouhlování vlastností kódu s plovoucí desetinnou čárkou při generování a optimalizaci kódu objektu pro cílový počítač. Kompilátor během vyhodnocování výrazu zaokrouhlí přesnost zdrojového kódu na čtyři konkrétní body: při přiřazeních, typecasts, když se argumenty s plovoucí desetinnou čárkou předají volání funkce a když volání funkce vrátí hodnotu s plovoucí desetinnou čárkou. Přechodné výpočty se můžou provádět s přesností stroje. Typecasty se dají použít k explicitně zaokrouhlování průběžných výpočtů.
Kompilátor neprovádí algebraické transformace u výrazů s plovoucí desetinou čárkou, jako je například opětovné přidružení nebo distribuce, pokud nemůže zaručit, že transformace vytvoří bitový identický výsledek. Výrazy, které zahrnují speciální hodnoty (NaN, +infinity, -0,0), se zpracovávají podle specifikací IEEE-754. Vyhodnotí se například, x != x
true
jestli x
je NaN. Ve výchozím nastavení nejsou vygenerovány kontrakty s plovoucí desetinou čárkou ./fp:precise
Toto chování je v sadě Visual Studio 2022 nové. Předchozí verze kompilátoru můžou ve výchozím nastavení generovat kontrakty v části /fp:precise
.
Kompilátor neprovádí algebraické transformace u výrazů s plovoucí desetinou čárkou, jako je například opětovné přidružení nebo distribuce, pokud nemůže zaručit, že transformace vytvoří bitový identický výsledek. Výrazy, které zahrnují speciální hodnoty (NaN, +infinity, -0,0), se zpracovávají podle specifikací IEEE-754. Vyhodnotí se například, x != x
true
jestli x
je NaN. Kontrakty s plovoucí desetinou čárkou mohou být generovány v části /fp:precise
.
Kompilátor generuje kód určený ke spuštění ve výchozím prostředí s plovoucí desetinou čárkou. Předpokládá se také, že prostředí s plovoucí desetinou čárkou není za běhu přístupné nebo upravené. To znamená, že předpokládá kód: ponechá výjimky s plovoucí desetinou čárkou maskované, nečte nebo zapisuje stavové registry s plovoucí desetinou čárkou a nemění režim zaokrouhlování.
Pokud kód s plovoucí desetinnou čárkou nezávisí na pořadí operací a výrazů v příkazech s plovoucí desetinnou čárkou (například pokud vám nezáleží na tom, jestli a * b + a * c
je vypočítán jako (b + c) * a
nebo 2 * a
jako a + a
), zvažte /fp:fast
možnost, která může rychleji a efektivněji vytvořit kód. Pokud váš kód závisí na pořadí operací a výrazů a přistupuje nebo mění prostředí s plovoucí desetinnou čárkou (například pro změnu režimů zaokrouhlování nebo výjimku s plovoucí desetinnou čárkou), použijte /fp:strict
.
/fp:strict
/fp:strict
má chování podobné /fp:precise
, to znamená, kompilátor zachovává zdrojové řazení a zaokrouhlování vlastností kódu s plovoucí desetinnou čárkou při generování a optimalizaci kódu objektu pro cílový počítač a sleduje standard při zpracování speciálních hodnot. Program může také bezpečně přistupovat k prostředí s plovoucí desetinou čárkou nebo ho upravovat za běhu.
Kompilátor /fp:strict
vygeneruje kód, který programu umožňuje bezpečně odmaskovat výjimky s plovoucí desetinou čárkou, číst nebo zapisovat do registru stavu s plovoucí desetinou čárkou nebo měnit režim zaokrouhlování. Zaokrouhlí se na přesnost zdrojového kódu ve čtyřech konkrétních bodech během vyhodnocení výrazu: při přiřazení, typecasts, když se argumenty s plovoucí desetinnou čárkou předají volání funkce a když volání funkce vrátí hodnotu s plovoucí desetinnou čárkou. Přechodné výpočty se můžou provádět s přesností stroje. Typecasty se dají použít k explicitně zaokrouhlování průběžných výpočtů. Kompilátor nevytvoří žádné algebraické transformace u výrazů s plovoucí desetinou čárkou, jako je opětovné přidružení nebo distribuce, pokud nemůže zaručit, že transformace vytvoří bitový identický výsledek. Výrazy, které zahrnují speciální hodnoty (NaN, +infinity, -0,0), se zpracovávají podle specifikací IEEE-754. Vyhodnotí se například, x != x
true
jestli x
je NaN. Kontrakty s plovoucí desetinou čárkou se negenerují v části /fp:strict
.
/fp:strict
je výpočetně dražší, než /fp:precise
protože kompilátor musí vkládat další instrukce pro výjimku a umožnit programům přístup k prostředí s plovoucí desetinou čárkou nebo jeho úpravu za běhu. Pokud váš kód tuto funkci nepoužívá, ale vyžaduje řazení a zaokrouhlování zdrojového kódu nebo spoléhá na speciální hodnoty, použijte /fp:precise
. V opačném případě zvažte použití /fp:fast
, které může produkovat rychlejší a menší kód.
/fp:fast
Tato /fp:fast
možnost umožňuje kompilátoru změnit pořadí, kombinovat nebo zjednodušit operace s plovoucí desetinou čárkou, aby optimalizoval kód s plovoucí desetinou čárkou pro rychlost a prostor. Kompilátor může vynechat zaokrouhlování u příkazů přiřazení, typecastů nebo volání funkce. Může měnit pořadí operací nebo provádět algebraické transformace, například pomocí asociativních a distribuativních zákonů. Může změnit pořadí kódu i v případě, že takové transformace mají za následek pozorovatelné odlišné zaokrouhlení chování. Kvůli této vylepšené optimalizaci se výsledek některých výpočtů s plovoucí desetinou čárkou může lišit od výpočtů vytvořených jinými /fp
možnostmi. Speciální hodnoty (NaN, +nekonečno, -nekonečno, -0,0) nelze rozšířit nebo se chovat přísně podle standardu IEEE-754. Kontrakty s plovoucí desetinou čárkou mohou být generovány v části /fp:fast
. Kompilátor je stále vázán základní architekturou v části /fp:fast
, a další optimalizace mohou být k dispozici prostřednictvím této /arch
možnosti.
V části /fp:fast
kompilátor generuje kód určený ke spuštění ve výchozím prostředí s plovoucí desetinou čárkou a předpokládá, že prostředí s plovoucí desetinou čárkou není za běhu přístupné nebo upravené. To znamená, že předpokládá kód: ponechá výjimky s plovoucí desetinou čárkou maskované, nečte nebo zapisuje stavové registry s plovoucí desetinou čárkou a nemění režim zaokrouhlování.
/fp:fast
je určen pro programy, které nevyžadují striktní řazení zdrojového kódu a zaokrouhlování výrazů s plovoucí desetinnou čárkou a nespoléhá na standardní pravidla pro zpracování speciálních hodnot, například NaN
. Pokud kód s plovoucí desetinnou čárkou vyžaduje zachování řazení a zaokrouhlování zdrojového kódu nebo spoléhá na standardní chování speciálních hodnot, použijte /fp:precise
. Pokud váš kód přistupuje k prostředí s plovoucí deseti desetinou čárkou nebo mění režim zaokrouhlování, odmaskuje výjimky s plovoucí desetinou čárkou nebo kontroluje stav s plovoucí desetinou čárkou, použijte /fp:strict
.
/fp:except
Tato /fp:except
možnost vygeneruje kód, který zajistí, že všechny nepřemaskované výjimky s plovoucí desetinnou čárkou jsou vyvolány v přesném bodě, ve kterém k nim dochází, a že nejsou vyvolány žádné jiné výjimky s plovoucí desetinnou čárkou. Ve výchozím nastavení tato /fp:strict
možnost povolí /fp:except
a /fp:precise
ne. Možnost /fp:except
není kompatibilní s /fp:fast
. Možnost může být explicitně zakázána pomocí ./fp:except-
Sama o sobě /fp:except
neumožňuje žádné výjimky s plovoucí desetinou čárkou. Vyžaduje se ale, aby programy povolily výjimky s plovoucí desetinou čárkou. Další informace o povolení výjimek s plovoucí desetinou čárkou naleznete v tématu _controlfp
.
Poznámky
Na stejném příkazovém řádku kompilátoru je možné zadat více /fp
možností. Najednou může platit pouze jeden z /fp:strict
parametrů , /fp:fast
a /fp:precise
možnosti. Pokud zadáte na příkazovém řádku více než jednu z těchto možností, bude mít přednost pozdější možnost a kompilátor vygeneruje upozornění. Možnosti /fp:strict
a /fp:except
možnosti nejsou kompatibilní s /clr
.
Možnost /Za
(kompatibilita ANSI) není kompatibilní s /fp
.
Použití direktiv kompilátoru k řízení chování s plovoucí desetinou čárkou
Kompilátor poskytuje tři direktivy pragma pro přepsání chování s plovoucí desetinou čárkou zadané na příkazovém řádku: float_control
, fenv_access
a fp_contract
. Tyto direktivy můžete použít k řízení chování s plovoucí desetinou čárkou na úrovni funkce, nikoli v rámci funkce. Tyto direktivy přímo neodpovídají možnostem /fp
. Tato tabulka ukazuje, jak se /fp
možnosti a direktivy pragma vzájemně mapují. Další informace najdete v dokumentaci pro jednotlivé možnosti a direktivy pragma.
Možnost | 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 |
* Ve verzích sady Visual Studio před sadou Visual Studio 2022 se /fp:precise
chování ve výchozím nastavení nastaví na fp_contract(on)
.
Možnost | 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 |
* Ve verzích sady Visual Studio počínaje sadou Visual Studio 2022 je /fp:precise
výchozí fp_contract(off)
chování .
Výchozí prostředí s plovoucí desetinou čárkou
Při inicializaci procesu se nastaví výchozí prostředí s plovoucí desetinnou čárkou. Toto prostředí maskuje všechny výjimky s plovoucí desetinnou čárkou, nastaví režim zaokrouhlení na nejbližší (FE_TONEAREST
), zachová subnormální (denormální) hodnoty, použije výchozí přesnost significand (mantissa) pro float
, double
a long double
hodnoty a kde je podporováno, nastaví ovládací prvek nekonečna na výchozí režim affine.
Přístup k prostředí s plovoucí desetinou čárkou a jeho úpravy
Modul runtime Microsoft Visual C++ poskytuje několik funkcí pro přístup k prostředí s plovoucí desetinou čárkou a jeho úpravu. Patří sem _controlfp
, _clearfp
a _statusfp
jejich varianty. Chcete-li zajistit správné chování programu, pokud váš kód přistupuje nebo upravuje prostředí s plovoucí desetinou čárkou, fenv_access
musí být povoleno /fp:strict
buď pomocí možnosti, nebo pomocí direktivy fenv_access
pragma, aby tyto funkce měly jakýkoli účinek. Pokud fenv_access
není povolená, může přístup nebo úprava prostředí s plovoucí desetinou čárkou vést k neočekávanému chování programu:
Kód nemusí respektovat požadované změny prostředí s plovoucí desetinnou čárkou,
Registrace stavu s plovoucí desetinou čárkou nemusí hlásit očekávané nebo aktuální výsledky.
K neočekávaným výjimkám s plovoucí desetinou čárkou může dojít nebo nedochází k očekávaným výjimkám s plovoucí desetinou čárkou.
Když váš kód přistupuje k prostředí s plovoucí desetinou čárkou nebo ho upraví, musíte být opatrní, když zkombinujete kód, kde fenv_access
je povolený s kódem, který nemá fenv_access
povolený. V kódu, kde fenv_access
není povoleno, kompilátor předpokládá, že výchozí prostředí s plovoucí desetinou čárkou platformy je v platnosti. Předpokládá se také, že stav s plovoucí desetinou čárkou není přístupný nebo změněný. Před přenesením ovládacího prvku do funkce, která nemá fenv_access
povolenou funkci, doporučujeme uložit a obnovit místní prostředí s plovoucí desetinou čárkou do výchozího stavu. Tento příklad ukazuje, jak lze nastavit a obnovit direktivu float_control
pragma:
#pragma float_control(precise, on, push)
// Code that uses /fp:strict mode
#pragma float_control(pop)
Režimy zaokrouhlování s plovoucí deseti desetinou čárkou
Kompilátor v obou /fp:precise
a /fp:fast
vygeneruje kód určený ke spuštění ve výchozím prostředí s plovoucí desetinou čárkou. Předpokládá se, že prostředí není za běhu přístupné ani upravené. Kompilátor tedy předpokládá, že kód nikdy neodmaskuje výjimky s plovoucí desetinou čárkou, přečte nebo zapisuje stavové registry s plovoucí desetinou čárkou nebo mění režimy zaokrouhlování. Některé programy ale potřebují změnit prostředí s plovoucí desetinou čárkou. Tato ukázka například vypočítá hranice násobení s plovoucí desetinnou čárkou změnou režimů zaokrouhlení s plovoucí desetinnou čárkou:
// 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;
}
Vzhledem k tomu, že kompilátor předpokládá výchozí prostředí s plovoucí desetinou čárkou pod /fp:fast
a /fp:precise
, je zdarma ignorovat volání _controlfp_s
. Například při kompilaci pomocí architektury /O2
x86 i /fp:precise
pro architekturu x86 se hranice nevypočítá a výstupy ukázkového programu:
cLower = -inf
cUpper = -inf
Při kompilaci pomocí architektury /O2
x86 a /fp:strict
pro architekturu x86 výstup ukázkového programu:
cLower = -inf
cUpper = -3.40282e+38
Speciální hodnoty s plovoucí desetinou čárkou
Výrazy /fp:precise
pod a /fp:strict
, které zahrnují speciální hodnoty (NaN, +nekonečno, -nekonečno, -0,0) se chovají podle specifikací IEEE-754. Chování /fp:fast
těchto speciálních hodnot může být nekonzistentní s IEEE-754.
Tato ukázka demonstruje různé chování speciálních hodnot v části /fp:precise
, /fp:strict
a /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;
}
Při kompilaci pomocí architektury /O2 /fp:precise
x86 nebo /O2 /fp:strict
pro architekturu x86 jsou výstupy konzistentní se specifikací IEEE-754:
INFINITY == INFINITY : 1
NAN == NAN : 0
INFINITY - INFINITY : -nan(ind)
NAN - NAN : nan
std::signbit(-0.0/-INFINITY): 0
Při kompilaci pomocí /O2 /fp:fast
** pro architekturu x86 nejsou výstupy konzistentní s IEEE-754:
INFINITY == INFINITY : 1
NAN == NAN : 1
INFINITY - INFINITY : 0.000000
NAN - NAN : 0.000000
std::signbit(-0.0/-INFINITY): 0
Algebraické transformace s plovoucí desetinou čárkou
Pod /fp:precise
a /fp:strict
, kompilátor nedělá žádnou matematickou transformaci, pokud není zaručeno, že transformace vytvoří bitový identický výsledek. Kompilátor může takové transformace provést v rámci /fp:fast
. Například výraz a * b + a * c
v ukázkové funkci algebraic_transformation
lze zkompilovat do a * (b + c)
pod /fp:fast
. Tyto transformace nejsou provedeny v /fp:precise
rámci nebo /fp:strict
a kompilátor generuje a * b + a * c
.
float algebraic_transformation (float a, float b, float c)
{
return a * b + a * c;
}
Explicitní přetypování s plovoucí desetinou čárkou
Pod /fp:precise
a /fp:strict
, kompilátor zaokrouhluje na přesnost zdrojového kódu na čtyři konkrétní body během vyhodnocení výrazu: při přiřazení, typecasts, když argumenty s plovoucí desetinnou čárkou se předají do volání funkce a když volání funkce vrátí hodnotu s plovoucí desetinnou čárkou. Typecasty se dají použít k explicitně zaokrouhlování průběžných výpočtů. V části /fp:fast
kompilátor nevygeneruje explicitní přetypování v těchto bodech, aby se zaručila přesnost zdrojového kódu. Tato ukázka ukazuje chování v různých /fp
možnostech:
float casting(float a, float b)
{
return 5.0*((double)(a+b));
}
Při kompilaci pomocí /O2 /fp:precise
nebo /O2 /fp:strict
můžete vidět, že explicitní přetypování typů se vloží do typecastu i do návratového bodu funkce ve vygenerovaném kódu pro architekturu x64:
addss xmm0, xmm1
cvtss2sd xmm0, xmm0
mulsd xmm0, QWORD PTR __real@4014000000000000
cvtsd2ss xmm0, xmm0
ret 0
Vygenerovaný /O2 /fp:fast
kód je zjednodušený, protože všechny přetypování typů jsou optimalizované:
addss xmm0, xmm1
mulss xmm0, DWORD PTR __real@40a00000
ret 0
Nastavení tohoto parametru kompilátoru ve vývojovém prostředí Visual Studio
Otevřete dialogové okno Stránky vlastností projektu. Podrobnosti najdete v tématu Nastavení kompilátoru C++ a vlastností sestavení v sadě Visual Studio.
Vyberte stránku vlastností vlastnosti konfigurace>C/C++>Generování kódu.
Upravte vlastnost Model s plovoucí desetinou čárkou.
Programové nastavení tohoto parametru kompilátoru
- Viz třída floatingPointModel.
Viz také
Možnosti kompilátoru MSVC
Syntaxe příkazového řádku kompilátoru MSVC