C++ 32bit vs 64bit плавающий предел


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

  • почему максимальное значение long double меньше в 64 битах, чем в 32 битах?
  • почему 64-разрядная версия не может расширить столько цифр, сколько в 32-разрядной версии, чтобы заполнить выход с точностью "40"?
  • похоже, что значения LDBL_MIN и LDBL_MAX равны, это ошибка?
Я заглянул в поплавок.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

Спасибо.

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

2 3

2 ответа:

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 в другом. Один компилятор (или, скорее, одна реализация библиотеки) взял на себя труд вычислить много цифр. Другой сдался рано и округлился.

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

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

Из "ISO/IEC 14882 INTERNATIONAL STANDARD First edition 1998-09-01"

3.9.1 фундаментальные типы

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

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