Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Указывает, как компилятор обрабатывает выражения с плавающей запятой, оптимизации и исключения. Параметры /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-Умножение -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, +бесконечность, -бесконечность, -0,0) обрабатываются в соответствии со спецификациями IEEE-754. Например, вычисляется значение x != x true x NaN. Контракты с плавающей запятой не создаются по умолчанию /fp:precise. Это новое поведение в Visual Studio 2022. Предыдущие версии компилятора могут создавать контракты по умолчанию в /fp:preciseразделе .
Компилятор не выполняет преобразования алгебраических значений для выражений с плавающей запятой, таких как повторное связывание или распределение, если преобразование не гарантирует, что преобразование выдает побитовый результат. Выражения, включающие специальные значения (NaN, +бесконечность, -бесконечность, -0,0) обрабатываются в соответствии со спецификациями IEEE-754. Например, вычисляется значение x != x true x NaN. Контракты с плавающей запятой могут быть созданы в /fp:preciseразделе .
Компилятор создает код, предназначенный для запуска в среде с плавающей запятой по умолчанию. Кроме того, предполагается, что среда с плавающей запятой не обращается к среде выполнения или не изменяется. То есть предполагается, что код: оставляет маскированные исключения с плавающей запятой, не считывает или не записывает регистры состояния с плавающей запятой и не изменяет режимы округления.
Если код с плавающей запятой не зависит от порядка операций и выражений в операторах с плавающей запятой (например, если вы не заботитесь о том, вычисляется ли a * b + a * c как или 2 * a какa + a), рассмотрите /fp:fast вариант, который может создавать более быстрый, более эффективный (b + c) * a код. Если код зависит от порядка операций и выражений, а также обращается к среде с плавающей запятой (например, для изменения режимов округления или перехвата исключений с плавающей запятой), используйте ./fp:strict
/fp:strict
/fp:strict имеет поведение, аналогичное /fp:precise, то есть компилятор сохраняет исходный порядок и округление свойств кода с плавающей запятой при создании и оптимизации кода объекта для целевого компьютера и наблюдает стандарт при обработке специальных значений. Программа также может безопасно получить доступ к среде с плавающей запятой или изменить ее во время выполнения.
В разделе /fp:strictкомпилятор создает код, позволяющий программе безопасно распаковывать исключения с плавающей запятой, считывать или записывать регистры состояния с плавающей запятой или изменять режимы округления. Он округляется до точности исходного кода в четырех определенных точках во время вычисления выражений: при назначении, типах, при передаче аргументов с плавающей запятой в вызов функции и при возврате вызова функции значение с плавающей запятой. Промежуточные вычисления могут выполняться с точностью компьютера. Методы typecasts можно использовать для явного округления промежуточных вычислений. Компилятор не делает никаких алгебраических преобразований в выражениях с плавающей запятой, таких как повторное связывание или распределение, если не гарантируется, что преобразование создает побитовую идентичную результат. Выражения, включающие специальные значения (NaN, +бесконечность, -бесконечность, -0,0) обрабатываются в соответствии со спецификациями IEEE-754. Например, вычисляется значение x != x true x NaN. Контракты с плавающей запятой не создаются в /fp:strictразделе.
/fp:strict вычисляется дороже, чем /fp:precise из-за того, что компилятор должен вставить дополнительные инструкции для перехвата исключений и разрешить программам доступ к среде с плавающей запятой или изменять ее во время выполнения. Если код не использует эту возможность, но требует упорядочения и округления исходного кода или использует специальные значения, используйте /fp:precise. В противном случае рассмотрите возможность использования /fp:fast, который может создавать более быстрый и меньший код.
/fp:fast
Этот /fp:fast параметр позволяет компилятору переупорядочение, объединение или упрощение операций с плавающей запятой для оптимизации кода с плавающей запятой для скорости и пространства. Компилятор может опустить округление при операторах назначения, типах или вызовах функций. Он может изменять порядок операций или создавать алгебраические преобразования, например с помощью ассоциативных и дистрибутивных законов. Он может изменить порядок кода, даже если такие преобразования приводят к заметно другому циклического поведения. Из-за этой расширенной оптимизации результат некоторых вычислений с плавающей запятой может отличаться от тех, которые создаются другими /fp вариантами. Специальные значения (NaN, +бесконечность, -бесконечность, -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 параметрам. В этой таблице показано, как /fp параметры и директивы pragma сопоставляются друг с другом. Дополнительные сведения см. в документации по отдельным параметрам и директивам 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 до Visual Studio 2022 /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 начиная с Visual Studio 2022 /fp:precise поведение по умолчанию fp_contract(off).
Среда с плавающей запятой по умолчанию
При инициализации процесса устанавливается среда с плавающей запятой по умолчанию. Эта среда маскирует все исключения с плавающей запятой, задает режим округления до ближайшего (FE_TONEAREST), сохраняет ненормальные (денормальные) значения, использует точность знака по умолчанию (мантисса) для float, doubleа long double также значения, а также, где поддерживается, задает контроль бесконечности в режиме аффины по умолчанию.
Доступ и изменение среды с плавающей запятой
Среда выполнения Microsoft Visual C++ предоставляет несколько функций для доступа и изменения среды с плавающей запятой. К ним относятся _controlfp, _clearfpи _statusfp их варианты. Чтобы обеспечить правильное поведение программы при доступе к коду или изменении среды с плавающей запятой, fenv_access необходимо включить либо параметром, либо с помощью fenv_access pragma, чтобы эти функции могли иметь какой-либо /fp:strict эффект. Если fenv_access не включено, доступ или изменение среды с плавающей запятой может привести к непредвиденному поведению программы:
Код может не учитывать запрошенные изменения в среде с плавающей запятой.
Регистры состояния с плавающей запятой могут не сообщать о ожидаемых или текущих результатах.
Непредвиденные исключения с плавающей запятой могут возникать или ожидаемые исключения с плавающей запятой могут не возникать.
Когда код обращается к среде с плавающей запятой или изменяет его, необходимо быть осторожным при объединении кода, где fenv_access включен код с включенным кодом, который не fenv_access включен. В коде, где fenv_access не включена, компилятор предполагает, что среда с плавающей запятой по умолчанию по умолчанию действует. Кроме того, предполагается, что состояние с плавающей запятой недоступно или изменено. Рекомендуется сохранить и восстановить локальную среду с плавающей запятой в его состоянии по умолчанию перед передачей элемента управления в функцию, которая не включена fenv_access . В этом примере показано, как float_control можно задать и восстановить прагму:
#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:fast и /fp:preciseне учитывает вызовы _controlfp_s. Например, при компиляции с помощью архитектуры /O2 /fp:precise x86 границы не вычисляются, а выходные данные примера программы:
cLower = -inf
cUpper = -inf
При компиляции с помощью архитектуры /O2 /fp:strict x86 пример программы выводит следующее:
cLower = -inf
cUpper = -3.40282e+38
Специальные значения с плавающей запятой
В /fp:precise и /fp:strict, выражения, которые включают специальные значения (NaN, +бесконечность, -бесконечность, -0,0) ведут себя в соответствии со спецификациями IEEE-754. В соответствии /fp:fastс поведением этих специальных значений может быть несовместимо с IEEE-754.
В этом примере показано другое поведение специальных значений в /fp:preciseразделе , /fp:strictи /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;
}
При компиляции с помощью /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:precise разделе и /fp:strictкомпилятор не выполняет никакого математического преобразования, если преобразование не гарантируется для получения побитового идентичного результата. Компилятор может сделать такие преобразования в /fp:fast. Например, выражение a * b + a * c в примере функции algebraic_transformation может быть скомпилировано в a * (b + c) разделе /fp:fast. Такие преобразования не выполняются или /fp:strictне создаются /fp:precise компиляторомa * b + a * c.
float algebraic_transformation (float a, float b, float c)
{
return a * b + a * c;
}
Явные точки приведения с плавающей запятой
В /fp:precise разделе и /fp:strictкомпилятор округляется до точности исходного кода в четырех конкретных точках во время вычисления выражений: при назначении, типадресации, при передаче аргументов с плавающей запятой в вызов функции и при возврате вызова функции значение с плавающей запятой. Методы typecasts можно использовать для явного округления промежуточных вычислений. В разделе /fp:fastкомпилятор не создает явные приведения в этих точках, чтобы гарантировать точность исходного кода. В этом примере показано поведение в различных /fp вариантах:
float casting(float a, float b)
{
return 5.0*((double)(a+b));
}
При компиляции с помощью /O2 /fp:precise или /O2 /fp:strictможно увидеть, что явные приведения типов вставляются как в рассылку типов, так и в точке возврата функции в созданном коде архитектуры 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
Откройте диалоговое окно Страницы свойств проекта. Подробнее см. в статье Настройка компилятора C++ и свойства сборки в Visual Studio.
Перейдите на страницу свойств Свойства конфигурации>C/C++>Создание кода.
Измените свойство модели с плавающей запятой.
Установка данного параметра компилятора программным способом
- См. раздел floatingPointModel.
См. также
Параметры компилятора MSVC
Синтаксис командной строки компилятора MSVC