Разрешено ли сокращение выражений с плавающей точкой в ​​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 используются.

Другие вопросы по тегам