Учет режима округления в функции constexpr - PullRequest
0 голосов
/ 02 июня 2018

Я пытаюсь написать constexpr версию функции exp.Я знаю, что

  • Используемый мной алгоритм предназначен для FE_TONEAREST округления
  • Начиная с C ++ 11, можно изменить режим округления с помощью fesetround( int round ) (при условии#pragma STDC FENV_ACCESS поддерживается и имеет значение ON)
  • Мне не разрешено вызывать функцию non-constexpr fesetround(int) в моей собственной функции constexpr

Если мое понимание верно, это означает, что (в компиляторе, который поддерживает #pragma STDC FENV_ACCESS), пользователю будет разрешено установить режим округления до вызова моей функции, но моя функция не сможет отменить это изменение (дажевременно) и, следовательно, может быть оправдан неправильным режимом округления.

Лучший вариант, который я могу придумать для обработки , состоит в том, чтобы иметь две функции:

  • Версия A помечена constexpr и не устанавливает режим округления
  • Версия B имеет значение , а не помечена constexpr и выполняет 3 действия:
    1. Установка округленияРежим до FE_TONEAREST
    2. Вызов версии A
    3. Сбросрежим округления
    4. Возвращает результат версии A

Чтобы установить переменную constexpr, нужно вызвать версию A, но она всегда будетоцениваться так, как если бы режим округления был FE_TONEAREST, поскольку (согласно cppreference ):

Текущий режим округления НЕ влияет на .... результаты арифметики с плавающей точкойоператоры в константных выражениях (всегда до ближайшего)

В non-constexpr contexts версия A и версия B будут согласованы, если режим округления равен FE_TONEAREST, но версия B будет обеспечиватьпревосходный результат для любого другого режима округления.Пользователь должен будет использовать FE_TONEAREST округление или , чтобы вызвать версию B.

Есть ли лучший способ справиться с этим, в стандартном C ++? ... или в стандарте есть что сказать о режимах округления, которые делают этот вопрос спорным?

Редактировать: Моя цель не в том, чтобы уважать режим округления; игнорировать , чтобы обеспечить постоянство точности функции.Я бы предпочел использовать только версию B, но невозможно изменить режим округления в функции constexpr.

1 Ответ

0 голосов
/ 03 июня 2018

Функция FENV_ACCESS, предоставляемая C и C ++, является кладжем и не поддерживает использование, используемое в этом вопросе.Программы, которые изменяют режим округления, редки, и языковая поддержка для них плохая.

В соответствии со стандартом C (и унаследованным C ++ по ссылке), FENV_ACCESS информирует о реализации, которую программа может запускать в нестандартных режимах управления с плавающей запятой.Если вы разрешаете вызывать вашу функцию exp в режиме, отличном от режима по умолчанию, и она не переводится при включенном FENV_ACCESS, стандарты не сообщают нам, как это будет происходить.

Далее, C ++не предоставляет никаких средств для автоматического вызова различных версий подпрограммы в зависимости от режима округления или состояния FENV_ACCESS (хотя реализации C ++ могут сделать это как расширение языка).

утверждение, на которое вы ссылаетесь из cppreference о том, что режим округления не влияет на арифметические операции в константных выражениях, похоже, является выводом, полученным из cppreference, а не чем-то явно выраженным в стандарте C ++.Возможно, это следует из того факта, что константные выражения оцениваются во время перевода, поэтому никакие модификации среды с плавающей запятой не могли быть выполнены.Однако мне не ясно, что это полностью гарантировано стандартом - в примечании в разделе expr.const говорится, что «константные выражения можно оценивать во время перевода». В нем не говорится, что они должны оцениваться во время перевода.

Как правило, не хотелось бы, чтобы exp вел себя так же, когда режим округления ближайший к ближайшему, как когда он приближается к бесконечности или другой настройке.Вместо этого хотелось бы, чтобы exp возвращал результат округления в большую сторону, когда режим находится в направлении к бесконечности, округлен в меньшую сторону, когда режим находится в направлении к отрицательной бесконечности, и округлен до нуля, когда режим приближается к нулю.(Для получения этих результатов требуются разные реализации exp для каждого режима, поскольку простое применение округления к каждой операции не приведет к требуемому результату.) Таким образом, ваш запрос exp возвращает один и тот же результат независимо от режима округлениянемного необычно.С какой целью он возвращает округленный до ближайшего результата, когда программа оценивает операции с плавающей запятой в другом режиме округления?Если программа использует бесконечность, чтобы попытаться вычислить верхнюю границу, ближайший exp нарушит это вычисление.

...