В вашем вопросе много неверных предположений
Во-первых, в C ++ нет требований относительно размеров типов. Стандарт только предписывает минимальную точность каждого типа и что ...
... Тип double
обеспечивает, по крайней мере, такую же точность, как float
, а тип long double
обеспечивает, по крайней мере, такую же точность, как double
. Набор значений типа float
является подмножеством набора значений типа double
; набор значений типа double
является подмножеством набора значений типа long double
. Представление значений типов с плавающей запятой определяется реализацией.
http://www.open -std.org / ОТК1 / SC22 / wg21 / документы / документы / 2012 / n3337.pdf
Большинство современных реализаций отображают float
и double
в формат одинарной и двойной точности IEEE-754, поскольку аппаратная поддержка для них является основной. Однако long double
не имеет такой широкой поддержки, потому что немногие люди нуждаются в более высокой точности, чем двойные, а оборудование для них стоит намного дороже. Поэтому некоторые платформы отображают его на IEEE-754 с двойной точностью, то есть так же, как double
. Некоторые другие отображают его в 80-битном формате расширенной точности IEEE 754 , если базовое оборудование поддерживает его. В противном случае long double
будет представлен double-double
арифметическим или IEEE-754 с четверной точностью
Кроме того, точность также не масштабируется линейно до количества бит в типе . Легко видеть, что double
в более чем в два раза точнее, чем float
, и в 8 раз шире, чем float
, несмотря на то, что в два раза больше места для хранения, потому что он имеет 53 бита и по сравнению с 24 в float и еще 3 экспонентных бита. Типы также могут иметь представления ловушек или биты заполнения, поэтому разные типы могут иметь разные диапазоны, даже если они имеют одинаковый размер и принадлежат к одной и той же категории (целочисленная или с плавающей запятой)
Итак, важная вещь здесь std::numeric_limits<long double>::digits
. Если вы напечатаете это, вы увидите, что long double
имеет 64 бита значения, что на 11 бит больше, чем double
. Посмотри вживую . Это означает, что ваш компилятор использует 80-битную расширенную точность для long double
, остальное - просто байтов заполнения , чтобы сохранить выравнивание. На самом деле gcc имеет различные опции , которые изменят ваш вывод:
-malign-double
и -mno-align-double
для управления выравниванием long double
-m96bit-long-double
и -m128bit-long-double
для изменения размера заполнения
-mlong-double-64
, -mlong-double-80
и -mlong-double-128
для управления базовой long double
реализацией
Изменяя параметры, вы получите следующие результаты для long double
Вы получите размер = 10, если отключите заполнение, но это приведет к снижению производительности из-за смещения
В PowerPC вы также можете видеть те же явления при изменении формата с плавающей запятой . С -mabi=ibmlongdouble
(арифметика двойных двойных чисел, которая используется по умолчанию) вы получите (размер, цифры10, цифры2) = (16, 31, 106), но с -mabi=ieeelongdouble
кортеж станет (16, 33, 113)
Для получения дополнительной информации вы должны прочитать https://en.wikipedia.org/wiki/Long_double
И я также хочу знать, как я могу получить более высокую точность, не определяя свой собственный тип данных
Ключевое слово для поиска - арифметика произвольной точности . Существуют различные библиотеки для этого, которые вы можете найти в списке арифметических программ произвольной точности . Вы можете найти больше информации в тегах bigint , biginteger или с произвольной точностью