Выражения с плавающей точкой иногда могут быть сокращены на оборудовании обработки, например использование объединенного умножения-и-сложения в качестве одной аппаратной операции.
По-видимому, используя их, это не просто деталь реализации, а регулируется спецификацией языка программирования. В частности, стандарт C89 не допускает таких сокращений, в то время как в C99 они разрешены при условии, что определен некоторый макрос. Смотрите подробности в этот так ответ.
Но как насчет C ++? Разрешены ли сокращения с плавающей точкой? Разрешено в некоторых стандартах? Разрешено универсально?
Контракты разрешены, но пользователю предоставляется возможность их отключить. Непонятный язык в стандартных облаках вопрос о том, даст ли их отключение желаемые результаты.
Я исследовал это в официальном стандарте C ++ 2003 и в проекте n4659 2017 года. Цитаты C ++ взяты с 2003 года, если не указано иное.
Текст «контракт» не появляется ни в одном документе. Тем не менее, пункт 5 выражений [expr], параграф 10 (тот же текст в 8 [expr] 13 2017 года) гласит:
Значения плавающих операндов и результаты плавающих выражений могут быть представлены с большей точностью и диапазоном, чем требуется типом; типы не изменяются при этом.
Я бы предпочел, чтобы в этом утверждении было четко указано, может ли эта дополнительная точность и диапазон использоваться свободно (реализация может использовать его в некоторых выражениях, включая подвыражения, но не использовать его в других), или должны были использоваться единообразно (если реализация использует дополнительную точность) , он должен использовать его в каждом выражении с плавающей запятой) или в соответствии с некоторыми другими правилами (например, он может использовать одну точность для float
другое для double
).
Если мы интерпретируем это вседозволенно, это означает, что в a*b+c
, a*b
может оцениваться с бесконечной точностью и дальностью, а затем сложение может оцениваться с любой точностью и дальностью, которые являются нормальными для реализации. Это математически эквивалентно сокращению, так как имеет тот же результат, что и оценка a*b+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 ++ не определяет «средство» или «средства». Словарное определение «средства» означает «место, удобство или часть оборудования, предоставленные для определенной цели» (Новый Оксфордский Американский Словарь, Приложение 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
используются.