Указывает ли стандарт С++ на представление чисел с плавающей запятой?
Для типов T
, для которых std::is_floating_point<T>::value
является true
, указывает ли стандарт С++ что-то на пути, которым должен быть реализован T
?
Например, T
может даже следовать представлению sign/mantissa/exponent? Или может быть полностью произвольным?
Ответы
Ответ 1
От N3337:
[basic.fundamental/8]:
Существует три типа с плавающей запятой: float, double и long double. Тип double обеспечивает не менее так же, как float, а double long double обеспечивает как минимум такую же точность, как double. Набор значений типа float является подмножеством набора значений типа double; набор значений типа double является подмножеством набора значений типа long double. Значение представления типы с плавающей запятой определяются реализацией. Интегральные и плавающие типы совместно называются арифметическими типы. Специализации стандартного шаблона std:: numeric_limits (18.3) должны указывать максимальный и минимальные значения для каждого арифметического типа для реализации.
Если вы хотите проверить, использует ли ваша реализация IEEE-754, вы можете использовать std::numeric_limits::is_iec559
:
static_assert(std::numeric_limits<double>::is_iec559,
"This code requires IEEE-754 doubles");
В этой области есть ряд других вспомогательных признаков, таких как has_infinity
, quiet_NaN
и больше.
Ответ 2
Стандарт C имеет "приложение" (в C11 - Приложение F), в котором излагаются, что означает, что реализация C должна соответствовать стандарту IEC 60559, преемнику стандарта IEEE 754. Реализация, соответствующая Приложению F должны иметь номера с плавающей точкой представления IEEE. Однако осуществление этого приложения является необязательным; основной стандарт специально избегает говорить что-либо о представлении чисел с плавающей запятой.
Я не знаю, есть ли эквивалентное приложение для С++. Он не отображается в N3337, но это может означать, что он распространяется отдельно. Существование std::numeric_limits<floating-type>::is_iec559
указывает на то, что комитет С++ по крайней мере думал об этом, но, возможно, не так подробно, как это сделал комитет C. (Это и всегда было чертовски стыдно, что стандарт С++ не выражается как набор изменений для стандарта C.)
Ответ 3
Никакой конкретной реализации не требуется. Стандарт С++ вообще не говорит об этом. Стандарт C довольно подробно описывает концептуальную модель, предполагаемую для чисел с плавающей запятой, со знаком, показателем, значением в некоторой базе b
и т.д. Однако он, в частности, заявляет, что это чисто описательное, а не требование об осуществлении (C11, сноска 21):
Модель с плавающей точкой предназначена для уточнения описания каждой характеристики с плавающей запятой и не требует, чтобы арифметика с плавающей запятой реализации была идентичной.
Тем не менее, хотя детали могут меняться, по крайней мере, из-за меня, мне кажется, что, производя (например) соответствующую реализацию double
, которая не вполне соответствовала обычной модели (т.е. значению и экспоненте ) было бы сложно (или, по крайней мере, трудно сделать с конкурентоспособной производительностью, так или иначе). Было бы особенно сложно, если бы оно менялось другими способами, например, переупорядочиванием порядка или использованием другой базы.
Определение std::numeric_limits<T>::digits
(и std::numeric_limits<T>::digits10
) подразумевает справедливо, что то, что указано как тип с плавающей точкой, должно сохранять (по крайней мере приблизительно) ту же точность для всех чисел в довольно широком диапазоне величин. Самым очевидным способом добиться этого является наличие некоторого количества бит/цифр, посвященных значению, и некоторого другого (отдельного) набора бит, посвященного экспоненте.
Ответ 4
Идея std::is_floating_point
заключается в том, чтобы сделать код пользователя разного происхождения лучше вместе. Технически вы можете указать int
как std::is_floating_point
, не вызывая поведения undefined. Но скажите, что у вас есть некоторая шаблонная библиотека, которая должна многократно делиться на T n
. Для ускорения работы библиотека создает T ni = 1 / n
и заменяет деление на n
умножением на ni
. Это отлично работает для чисел с плавающей запятой, но не для целых чисел. Поэтому библиотека корректно выполняет только оптимизацию, если std::is_floating_point<T>::value == true
. Если вы лжете код, вероятно, все еще работает со стандартной точки зрения, но является неправильным с логической точки зрения. Поэтому, если вы пишете класс, который ведет себя как более крупный float
, отметьте его как std::is_floating_point
, иначе нет. Это должно обеспечить вам оптимальный и правильный код.