/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:precisekompilá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 != xtrue 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 != xtrue 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:strictvygeneruje 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 != xtrue 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:fastkompilá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:excepta /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:strictparametrů , /fp:fasta /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_accessa 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, doublea 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, _clearfpa _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:fastvygeneruje 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:fasttě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:stricta /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:stricta 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:fastkompilá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:strictmůž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

  1. Otevřete dialogové okno Stránky vlastností projektu. Podrobnosti najdete v tématu Nastavení kompilátoru C++ a vlastností sestavení v sadě Visual Studio.

  2. Vyberte stránku vlastností vlastnosti konfigurace>C/C++>Generování kódu.

  3. Upravte vlastnost Model s plovoucí desetinou čárkou.

Programové nastavení tohoto parametru kompilátoru

Viz také

Možnosti kompilátoru MSVC
Syntaxe příkazového řádku kompilátoru MSVC