C ++ 32-битный или 64-битный плавающий лимит

Учитывая следующий фрагмент кода, я просто хочу знать

  • почему максимальное значение long double в 64-битной версии меньше, чем в 32-битной?
  • почему 64-разрядная версия не может расширять столько цифр, сколько в 32-разрядной версии, чтобы заполнить вывод с точностью до 40?
  • кажется, что значения LDBL_MIN и LDBL_MAX равны, это ошибка?

Я изучил файлы float.h на своем компьютере, но не могу найти точное определение этих макроконстант.

Тестовый код (платформа = Win7-64bit)

#include <cfloat>
#include <iomanip>
cout<<"FLT_MAX   ="<< setprecision(40) << FLT_MAX  << endl;
cout<<"DBL_MAX   ="<< setprecision(40) << DBL_MAX  << endl;
cout<<"LDBL_MAX  ="<< setprecision(40) << LDBL_MAX << endl;
cout<<"FLT_MIN   ="<< setprecision(40) << FLT_MIN  << endl;
cout<<"DBL_MIN   ="<< setprecision(40) << DBL_MIN  << endl;
cout<<"LDBL_MIN  ="<< setprecision(40) << LDBL_MIN << endl;

32-битный результат (MinGW-20120426)

FLT_MAX  =340282346638528859811704183484516925440
DBL_MAX  =1.797693134862315708145274237317043567981e+308
LDBL_MAX =1.189731495357231765021263853030970205169e+4932
FLT_MIN  =1.175494350822287507968736537222245677819e-038
DBL_MIN  =2.225073858507201383090232717332404064219e-308
LDBL_MIN =3.362103143112093506262677817321752602598e-4932

64-битный результат (MinGW64-TDM 4.6)

FLT_MAX  =340282346638528860000000000000000000000
DBL_MAX  =1.7976931348623157e+308
LDBL_MAX =1.132619801677474e-317
FLT_MIN  =1.1754943508222875e-038
DBL_MIN  =2.2250738585072014e-308
LDBL_MIN =1.132619801677474e-317

Благодарю.

[Редактировать]: Используя последнюю версию MinGW64-TGM 4.7.1, «ошибки» LDBL_MAX, LDBL_MIN, похоже, удалены.

3

Решение

LDBL_MAX =1.132619801677474e-317 звучит как ошибка где-то. Стандарт требует, чтобы каждое значение, представимое как double также может быть представлен в виде long doubleтак что это не допустимо для LDBL_MAX < DBL_MAX, Учитывая, что вы не показали свой реальный код тестирования, я лично проверил бы это, прежде чем обвинять компилятор.

Если действительно есть (не ошибка) разница в long double между этими двумя значениями основание этой разницы будет заключаться в том, что ваш 32-разрядный компилятор использует более старые операции x87 с плавающей запятой, которые имеют точность 80 бит и, следовательно, допускают 80 бит long double,

Ваш 64-битный компилятор использует более новые 64-битные операции с плавающей запятой в x64. Нет 80-битной точности, и это не мешает переключиться на инструкции x87 для реализации большего long double,

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

почему 64-битная версия не может расширять столько цифр, сколько в 32-битной версии
заполнить «40» точность вывода?

Двойной имеет только около 15 десятичных цифр точности. Цифры за пределами этого иногда информативны, но обычно вводят в заблуждение.

Я не могу вспомнить, что говорит стандарт setprecision, но при условии, что реализация позволяет нарисовать линию, где она перестает генерировать цифры, точность double это разумное место для рисования. Что касается того, почему одна реализация решила сделать это, а другая нет — я не знаю. Поскольку это разные дистрибутивы, они могут использовать совершенно разные стандартные библиотеки.

Та же «ложная точность» — вот почему вы видите 340282346638528859811704183484516925440 для FLT_MAX в одном случае, но 340282346638528860000000000000000000000 в другом. Один компилятор (точнее, одна реализация библиотеки) потратил много времени на то, чтобы вычислить много цифр. Другой сдался рано и округлено.

3

Другие решения

Чтобы ответить на этот вопрос, я сделаю только несколько предположений:
1) что вы проверяли это только на 64-битной машине
2) что компиляторы — это разные битовые версии одной и той же подверсии (то есть они практически родственные компиляторы).

Это было сказано:

Из «ИСО / МЭК 14882 МЕЖДУНАРОДНЫЙ СТАНДАРТ Первое издание 1998-09-01»

3.9.1 Основные типы

  1. Существует три типа с плавающей точкой: float, double и long double. Тип double обеспечивает, по крайней мере, такую ​​же точность, как и float, а тип long double обеспечивает, по крайней мере, такую ​​же точность, что и double. Набор значений типа float является подмножеством набора значений типа double; набор значений типа double является подмножеством набора значений типа long double. Представление значений типов с плавающей запятой определяется реализацией. Интегральные и плавающие типы вместе называются арифметическими типами. Специализации стандартного шаблона numeric_limits (18.2) должны определять максимальное и минимальное значения каждого арифметического типа для реализации.

Кроме того, разные процессоры будут иметь разное влияние на конечный результат, насколько точность с более высокими числами уровня. То же самое касается компиляторов. Компилятор VC ++ не будет вести себя так же, как borland, GCC / G ++ и так далее.

0

По вопросам рекламы [email protected]