Курс Microsoft edX C++: double vs long double — почему нет единого стандарта?

Я решил пройти курс Microsoft C++ на edX. По их словам, double и long double идентичны по размеру и диапазону:

Microsoft C++ на edX

Это противоречит следующим спецификациям: https://en.wikipedia.org/wiki/C_data_types.

Сначала я подумал, что Microsoft делает опечатку, но потом нашел этот пост:

В архитектуре x86 большинство компиляторов реализуют long double как 80-битный тип расширенной точности, поддерживаемый этим оборудованием (иногда сохраняемый как 12 или 16 байтов для поддержания структуры данных).

и

Компиляторы также могут использовать long double для 128-битного формата четверной точности, который в настоящее время реализован в программном обеспечении.

Другими словами, да, long double может хранить больший диапазон значений, чем double. Но это полностью зависит от компилятора.

Итак, я подумал про себя, что в большинстве случаев (то есть в большинстве реализаций компилятора) Microsoft ошибается, но в некоторых случаях они могут быть правы.

Но потом я просмотрел стандарт С++ 11. И вот что там написано:

Существует три типа с плавающей запятой: float, double и long double. Тип double обеспечивает по крайней мере такую ​​же точность, как float, а тип long double обеспечивает по крайней мере такую ​​же точность, как и double. Множество значений типа float является подмножеством множества значений типа double; множество значений типа double является подмножеством множества значений типа long double.

Неясно, да?

Итак, вот вопрос: C++ существует уже давно. Почему до сих пор нет единого стандарта для такого рода вещей? Намеренно ли это ради гибкости — каждый решает сам, какими будут эти типы данных. Или они просто не могут принять всех на борт?

P.S. Я все еще думаю, что Microsoft должна была записать это по-другому: что-то вроде строк long double имеет тот же размер, что и double или больше (до ... байтов).


person InfiniteLoop    schedule 03.05.2018    source источник
comment
Возможно, это не ответ на ваш вопрос, но C++ уже давно существует как обоюдоострый меч. Да, они могли бы определить стандарт, но это нарушило бы обратную совместимость. Это не является жестким контраргументом, поскольку происходит нарушение обратной совместимости, но я предполагаю, что это может быть одной из причин.   -  person Jerome Reinländer    schedule 03.05.2018
comment
Разрешить выполнение соответствующих программ на оборудовании, которое имеет только один размер данных с плавающей запятой. Подумайте о старом оборудовании, встроенных системах, микроконтроллерах и т. д.   -  person Richard Critten    schedule 03.05.2018
comment
Производители чипов не устояли перед искушением снабдить свои процессоры расширенными форматами с плавающей запятой. В прежние времена считалось добавленной стоимостью, но полной катастрофой для разработчиков программного обеспечения, которые не могут заставить свои программы давать стабильные результаты. IEEE-754 — это отраслевой стандарт, и, как и все подобные стандарты, это всего лишь компромисс, который должен сделать всех одинаково недовольными. Microsoft мудро никогда не прыгала на подножку, GCC это сделала. То, что вы получите, зависит от того, какой у вас процессор. x86, power-pc и sparc есть, не совпадают.   -  person Hans Passant    schedule 03.05.2018
comment
Возможно, для вас будет таким же шоком узнать, что все фундаментальные типы C также не имеют заданного размера! Все они определены в терминах at least: en.cppreference.com/w/cpp/language /types Что касается long double - очень старые версии VS (16-битные) использовали x87 80-битный тип float для long double, но с введением SSE он устарел. gcc сохранил 80-битный тип, VS пошел с long double == double.   -  person Dan M.    schedule 03.05.2018
comment
каждая реализация должна указывать точный размер каждого типа, иначе как люди могут узнать, насколько велик long double на этой конкретной платформе? Утверждения типа long double имеют тот же размер, что и double, или больше (до ... байтов), являются расплывчатыми и предназначены только для стандарта.   -  person phuclv    schedule 12.09.2019
comment
Microsoft говорит о собственном компиляторе. Как всегда, они говорят о своих собственных продуктах, а не о стандартах.   -  person user207421    schedule 12.09.2019


Ответы (1)


По их словам, double и long double идентичны по размеру и диапазону (см. скриншот ниже). Это противоречит этим спецификациям:

Здесь нет противоречия. Если вы внимательно прочитали стандарт и статью по ссылке, вы увидите, что стандарт C определяет минимально возможные диапазоны типов, а не какие-то фиксированные размеры для них. Также обратите внимание, что приведенная выше вики-ссылка предназначена для C, а не для C++. Это очень разные языки. К счастью, они оба согласны с размерами типов.

Это обеспечивает гибкость, поскольку C и C++ всегда разрабатывались с учетом переносимости. Основная философия заключается в том, что "вы не платите за то, что не используете", поэтому реализации компилятора должны выбирать то, что лучше и эффективнее для каждой конкретной архитектуры. Они не могут заставить int быть всегда 32-битной. Например, в 18-битной архитектуре int будет иметь 18-битный размер вместо неудобного 32-битного размера, а 16-битным процессорам не придется тратить циклы на поддержку 32-битного int, если int определен как 16-битный тип.

Вот почему C и C++ допускают дополнение до 1 и величину знака для целочисленных типов со знаком, а не только дополнение до 2. Типы с плавающей запятой также не обязаны иметь фиксированный размер или быть двоичными, поэтому реализации могут использовать десятичные типы с плавающей запятой. На самом деле IEEE-754 даже не требуется, потому что были компьютеры, использующие другие форматы с плавающей запятой. См. раздел Есть ли какие-либо реальные процессоры, не использующие IEEE 754?

Итак, читаем стандарт ISO/IEC 9899:201x C++, раздел 5.2.4.2.1 (Размеры целочисленных типов <limits.h>), мы знаем, что:

Приведенные ниже значения должны быть заменены постоянными выражениями, подходящими для использования в #if директивах предварительной обработки. […] Их значения, определенные реализацией, должны быть равны или больше по величине (абсолютное значение) показанным, с тем же знаком

Значение, соответствующее INT_MAX, равно 32767, что означает, что INT_MAX >= 32767 во всех соответствующих реализациях. То же самое относится к типам с плавающей запятой в разделе 5.2.4.2.2 (Характеристики типов с плавающей запятой <float.h>)

То, что вы читаете в стандарте, означает

  • точностьOf(плавающая) ⩽ точностьOf(двойная) ⩽ точностьOf(длинная двойная) и
  • setOfValues(float) ⊂ setOfValues(double) ⊂ setOfValues(long double)

Все очень четко и совсем не туманно. На самом деле вам гарантировано только

  • СИМВОЛ_БИТ ⩾ 8
  • sizeof(char) ⩽ sizeof(short) ⩽ sizeof(int) ⩽ sizeof(long) ⩽ sizeof(long long)
  • sizeof(float) ⩽ sizeof(double) ⩽ sizeof(long double)
  • FLT_DECIMAL_DIG ⩾ 6
  • LDBL_DECIMAL_DIG ⩾ DBL_DECIMAL_DIG ⩾ 10

Таким образом, double может иметь тот же размер и точность, что и long double. На самом деле они обычно имеют один и тот же тип на платформах, отличных от x86, потому что у них нет тип с расширенной точностью, например x86. В последнее время многие реализации перешли на программный формат IEEE-754 четырехкратной точности. для long double, но, конечно, это будет намного медленнее

Поскольку существует множество возможных форматов для long double, существуют также различные варианты выбора размера long double, например, когда людям не нужна дополнительная точность или не нужна низкая производительность программной реализации. Например

  • GCC для x86 имеет -mlong-double-64/80/128 в зависимости от того, хотите ли вы 64-разрядную (т. е. то же, что и double), 80-битный (увеличенная точность) или 128-битный (четверная точность) long double. Точно так же есть варианты -m96/128bit-long-double, если вы хотите обменять скорость на 25% использования памяти.
  • GCC для PowerPC имеет -mabi=ibmlongdouble/ieeelongdouble для реализация двойной двойной точности или стандартный формат четверной точности который имеет более широкий диапазон и немного лучшую точность, но намного медленнее

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

Именно так, как я сказал выше, это намеренно ради гибкости. Вы не платите за потерю производительности и использования памяти, когда вам не нужна точность выше double. Комитет по стандартизации заботится обо всех возможных архитектурах, в том числе о некоторых, возможно, мертвых1.

На самом деле разрешение более высоких long double иногда приводит к неожиданным результатам, когда FLT_EVAL_METHOD = 2, потому что операции float и double также выполняются с более высокой точностью, поэтому одно и то же выражение в разных точках может давать разные результаты. Кроме того, невозможно векторизовать нечетную расширенную точность long double math2, что еще больше снижает производительность. Поэтому даже в x86 MS компилятор cl.exe полностью отключает использование 80-битных длинных двойных

Смотрите также


1 См.


2 См.

person phuclv    schedule 11.09.2019
comment
Но установка точности x87 на 53 бита не помогает с FLT_EVAL_METHOD для float, если мы не используем SSE, не так ли? - person Ruslan; 11.09.2019
comment
@Руслан, да, ты прав. Это может произойти, если FLT_EVAL_METHOD > 0 - person phuclv; 11.09.2019