Разрешено ли сокращение выражений с плавающей точкой в C++?
Выражения с плавающей запятой иногда могут быть сокращены на оборудовании обработки, например, используя объединенное умножение и сложение в качестве одной аппаратной операции.
По-видимому, используя их, это не просто деталь реализации, а регулируется спецификацией языка программирования. В частности, стандарт C89 не допускает таких сокращений, в то время как в C99 они разрешены при условии, что определен некоторый макрос. Подробности смотрите в этом SO ответе.
Но как насчет C++? Разрешены ли сокращения с плавающей точкой? Разрешено в некоторых стандартах? Разрешено универсально?
2 ответа
Резюме
Контракты разрешены, но пользователю предоставляется возможность их отключить. Непонятный язык в стандартных облаках вопрос о том, даст ли их отключение желаемые результаты.
Я исследовал это в официальном стандарте C++ 2003 и в проекте n4659 2017 года. Цитаты C++ взяты с 2003 года, если не указано иное.
Высокая точность и дальность
Текст "контракт" не появляется ни в одном документе. Тем не менее, пункт 5 выражений [expr], параграф 10 (тот же текст в 8 [expr] 13 2017 года) гласит:
Значения плавающих операндов и результаты плавающих выражений могут быть представлены с большей точностью и диапазоном, чем требуется типом; типы не изменяются при этом.
Я бы предпочел, чтобы в этом утверждении было четко указано, может ли эта дополнительная точность и диапазон использоваться свободно (реализация может использовать его в некоторых выражениях, включая подвыражения, но не использовать его в других), или должны были использоваться единообразно (если реализация использует дополнительную точность), он должен использовать его в каждом выражении с плавающей запятой) или в соответствии с некоторыми другими правилами (например, он может использовать одну точность для float
другое для double
).
Если мы интерпретируем это вседозволенно, это означает, что в a*b+c
, a*b
может оцениваться с бесконечной точностью и дальностью, а затем сложение может оцениваться с любой точностью и дальностью, которые являются нормальными для реализации. Это математически эквивалентно сокращению, так как имеет тот же результат, что и оценка a*b+c
с слитой командой умножения-сложения.
Следовательно, с этой интерпретацией реализации могут заключать в себе выражения.
Сокращения, унаследованные от C
17.4.1.2 [lib.headers] 3 (аналогичный текст в 20.5.1.2 [headers] 3 2017 года) гласит:
Средства библиотеки Standard C представлены в 18 дополнительных заголовках, как показано в таблице 12…
Таблица 12 включает в себя <cmath>
и пункт 4 указывает, что это соответствует math.h
, Технически, стандарт C++ 2003 относится к стандарту C 1990, но у меня нет его в электронном виде, и я не знаю, где находится моя бумажная копия, поэтому я буду использовать стандарт C 2011 (но неофициальный проект N1570), который C++ Проект 2017 года относится к.
Стандарт C определяет, в <math.h>
Прагма FP_CONTRACT
:
#pragma STDC FP_CONTRACT on-off-switch
где выключатель on
разрешить сокращение выражений или off
запретить их. Он также говорит, что состояние по умолчанию для прагмы определяется реализацией.
Стандарт C++ не определяет "средство" или "средства". Словарное определение "средства" - это "место, удобство или часть оборудования, предназначенного для определенной цели" (New Oxford American Dictionary, версия приложения Apple Dictionary 2.2.2 (203)). Удобство - это "желательная или полезная функция или средство здания или места". Прагма - это полезная функция, предоставляемая для конкретной цели, поэтому она представляется средством, поэтому она включена в <cmath>
,
Следовательно, использование этой прагмы должно разрешать или запрещать сокращения.
Выводы
Сокращения разрешены, когда
FP_CONTRACT
включен и может быть включен по умолчанию.Текст 8 [expr] 13 может быть интерпретирован, чтобы эффективно разрешать сокращения, даже если
FP_CONTRACT
выключен, но недостаточно ясен для окончательного толкования.
Да, это разрешено.
Например, в компиляторе Visual Studio по умолчанию fp_contract
включен Это говорит компилятору использовать инструкции сжатия с плавающей точкой, где это возможно. Задавать fp_contract
в off
сохранить отдельные инструкции с плавающей точкой.
// pragma_directive_fp_contract.cpp
// on x86 and x64 compile with: /O2 /fp:fast /arch:AVX2
// other platforms compile with: /O2
#include <stdio.h>
// remove the following line to enable FP contractions
#pragma fp_contract (off)
int main() {
double z, b, t;
for (int i = 0; i < 10; i++) {
b = i * 5.5;
t = i * 56.025;
z = t * i + b;
printf("out = %.15e\n", z);
}
}
Подробная информация об Укажите Поведение с плавающей точкой.
Использование коллекции компиляторов GNU (GCC):
Состояние по умолчанию для FP_CONTRACT
прагма (С99 и С11 7.12.2). Эта прагма не реализована. Выражения в настоящее время только сокращены, если -ffp-contract=fast
, -funsafe-math-optimizations
или же -ffast-math
используются.