/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-Умножение -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