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