Если прагма STD C FENV_ACCESS отсутствует, означает ли это режим округления по умолчанию? - PullRequest
2 голосов
/ 17 марта 2020

У меня проблема с интерпретацией стандарта C, последний черновик взят из http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2454.pdf.

Стандартная оценка

Стандарт определяет pragma STD FENV_ACCESS и состояния (7.6.1p2):

The FENV_ACCESS pragma provides a means to inform the implementation when a program might
access the floating-point environment to test floating-point status flags or run under non-default
floating-point control modes.

Не ясно, почему эта прагма необходима для работы в нестандартных режимах управления с плавающей точкой. Это потому что

  • установка этих режимов не по умолчанию требует записи в регистр режима управления, или
  • прагма необходима всегда, даже если текущий режим не по умолчанию уже установлен?

Далее в этом абзаце стандарта мы находим:

If part of a program tests floating-point status flags or establishes non-default floating-point
mode settings using any means other than the FENV_ROUND pragmas, but was translated with the
state for the FENV_ACCESS pragma "off", the behavior is undefined.

Похоже, тестирование текущего режима без изменения не является неопределенным поведением. Но сноска в том же абзаце гласит:

In general, if the state of FENV_ACCESS is "off", the translator can assume that the flags are
not tested, and that default modes are in effect, except where specified otherwise by an
FENV_ROUND pragma.

Вопрос

Итак, если прагма FENV_ACCESS не указана, означает ли это, что действует режим округления по умолчанию?

Предположим, что прагма FENV_ROUND также отсутствует, и компилятор предполагает, что FENV_ACCESS выключен по умолчанию, это необходимо для обратной совместимости.

Пример

Рассмотрим следующий исходный код:

#include <math.h>
float func_01(float x) {
    return nearbyint(x);
}

Функция nearbyint описана (7.12.9.3) как выполнение округления с использованием текущего режима округления. Но код не имеет pragma FENV_ACCESS. Означает ли это, что текущий режим округления может игнорироваться и nearbyint совпадает с roundeven?

1 Ответ

1 голос
/ 17 марта 2020

C Черновик n2454

Я написал этот ответ, основываясь на текущем стандарте C, 2018, но вопрос касается черновика для готовящегося стандарта. После просмотра черновика произошли существенные изменения, и этот ответ не применим.

Примечательно, что черновой вариант n2454 в 7.6.1: 2:

… Если часть программы тестируется Состояния с плавающей запятой отмечают или устанавливают нестандартные настройки режима с плавающей запятой, используя любые средства, кроме прагм FENV_ROUND, но были переведены с состоянием для прагмы FENV_ACCESS «выкл», поведение не определено…

Примечательно, что здесь отсутствует текст из C 2018, который появился сразу после «нестандартных настроек режима с плавающей запятой»:

… или работает в режиме не по умолчанию settings,…

Текст C 2018 означает, что если код, скомпилированный с FENV_ACCESS, устанавливает режим не по умолчанию и отключает код, скомпилированный с FENV_ACCESS, то поведение не определено только потому, что код, скомпилированный с FENV_ACCESS off, работает в режиме не по умолчанию. Черновой текст не содержит этого, что, по-видимому, означает, что вызывающий абонент может изменить режим и код вызова, скомпилированный с выключенным FENV_ACCESS, и поведение должно быть определено. Это означает, что код, скомпилированный с FENV_ACCESS off, должен быть подготовлен к запуску в любом режиме с плавающей запятой.

Этот же абзац в черновике также содержит новый текст:

(Когда выполнение переходит из части программы, переведенной с FENV_ACCESS «выкл.», в часть, переведенную с FENV_ACCESS «вкл», состояние флагов состояния с плавающей запятой не определено, а режимы управления с плавающей запятой имеют настройки по умолчанию .)

Рассмотрим, что происходит, когда подпрограмма A с FENV_ACCESS вызывает подпрограмму B с FENV_ACCESS выключенной. Когда B возвращается, управление переходит от части доступа к программе к части программы доступа. В приведенном выше предложении говорится, что режимы управления с плавающей точкой находятся в своих настройках по умолчанию. Другими словами, возвращение из процедуры отключения доступа должно изменить режим с плавающей запятой на режим по умолчанию. Это кажется странным. Поэтому я не готов обновлять этот ответ, чтобы охватить черновик проекта.

Ответ за C 2018

Не ясно, почему эта прагма необходима для работы под стандартные режимы управления с плавающей точкой.

Это может быть связано с тем, что (в зависимости от реализации C) код, сгенерированный компилятором, должен быть другим, если неизвестно, что операции с плавающей точкой в режиме по умолчанию. Например, при компиляции кода с FENV_ACCESS, установленным на off, компилятор может скомпилировать вызов на sin как вызов быстрой версии, которая предполагает округление по умолчанию. Но если для FENV_ACCESS установлено значение on, он скомпилирует вызов более медленной версии, которая тестирует режим округления и использует соответствующую реализацию функции синуса.

Поскольку код, который должен быть сгенерирован, отличается для on и off версий, компилятор должен знать, является ли FENV_ACCESS on или off.

Так что, если не была указана прагма FENV_ACCESS, означает ли это значение по умолчанию действует режим округления?

Нет. Если прагма FENV_ACCESS отсутствует, компилятор находится в состоянии по умолчанию, которое может быть on или off, и это определяется реализацией.

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

Функция nearbyint описана (7.12.9.3) как выполнение округления с использованием текущего режима округления. Но код не имеет pragma FENV_ACCESS. Означает ли это, что текущий режим округления может игнорироваться и nearbyint совпадает с roundeven?

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

Обратите внимание, что округление до ближайших связей с чётными значениями превосходит режим округления по умолчанию, но это не определяется стандартом C, если только Приложение F не эффект.

...