Некоторые вопросы о точности с плавающей запятой и числовых пределах
Я знаю, что есть множество подобных вопросов, но я не мог найти свои ответы. Пожалуйста, прочитайте перед голосованием, чтобы закрыть (:
- По данным ПК АСМ:
Числовой сопроцессор имеет восемь регистров с плавающей запятой. Каждый регистр содержит 80 бит данных. Числа с плавающей точкой всегда хранятся как 80-битные номера повышенной точности в этих регистрах.
Как это возможно, когда sizeof
показывает разные вещи. Например, в архитектуре x64 размер double
8, и это далеко от 80 бит.
Почему
std::numeric_limits< long double >::max()
дает мне1.18973e+4932
?! Это huuuuuuuuuuge номер. Если это не способ получить максимум чисел с плавающей запятой, то почему это компилируется вообще, и даже больше - почему это возвращает значение.что это значит:
Величины двойной точности могут варьироваться от приблизительно 10^ -308 до 10^308
Это огромные числа, вы не можете хранить их в 8B или даже 16B (что является расширенной точностью и составляет всего 128 бит)?
Очевидно, я что-то упустил. На самом деле, очевидно, много вещей.
4 ответа
1) sizeof
это размер в памяти, а не в регистре. sizeof
в байтах, поэтому 8 байтов = 64 бита. Когда двойники вычисляются в памяти (на этой архитектуре), они получают дополнительные 16 битов для более точных промежуточных вычислений. Когда значение копируется обратно в память, лишние 16 бит теряются.
2) почему вы думаете long double
не поднимается до 1.18973e + 4932?
3) Почему вы не можете хранить 10^308 в 8 байтах? Мне нужно только 13 бит: 4 для хранения 10 и 9 для хранения 308.
double
это не 80-битный процессор Intel с плавающей запятой, это 64-битный IEEE 754 с плавающей запятой. С sizeof(double) вы получите размер последнего.Это правильный способ получить максимальное значение для
long double
так что твой вопрос бессмыслен.Возможно, вам не хватает, что числа с плавающей запятой не являются точными числами. 10^308 не хранит 308 цифр, только около 19 цифр.
Размер пространства, используемого FPU, и объем пространства, используемого в памяти для представления double
это две разные вещи. IEEE 754 (который, вероятно, используется в большинстве архитектур) определяет 32-битные числа с одинарной точностью и 64-битные числа с двойной точностью, поэтому sizeof(double)
дает вам 8 байтов. Intel x86 выполняет математику с плавающей запятой внутри, используя 80 бит.
std::numeric_limits< long double >::max()
дает вам правильный размер для long double
который обычно составляет 80 бит. Если вы хотите максимальный размер для 64-битного двойного, вы должны использовать его в качестве параметра шаблона.
На вопрос о диапазонах, почему вы не можете хранить их в 8 байтах? Они действительно соответствуют друг другу, и вам не хватает того, что в крайних точках диапазона есть число, которое невозможно представить (например, показатель степени приближается к 308, есть много много целых чисел, которые вообще не могут быть представлены).
Смотрите также http://floating-point-gui.de/ для получения информации о плавающей точке.
Числа с плавающей точкой на компьютере представлены в соответствии с IEEE 754-2008.
Он определяет несколько форматов, среди которых
двоичная32 = одинарная точность,
двоичная64 = двойная точность и
binary128 = Четырехкратная точность являются наиболее распространенными.
http://en.wikipedia.org/wiki/IEEE_754-2008
Число с двойной точностью имеет 52 бита для цифры, которая дает точность, и 10 бит для показателя степени, который дает размер числа.
Таким образом, удваиваются 1.xxx(52 двоичных цифры) * 2 ^ экспонента (10 двоичных цифр, поэтому до 2^10=1024)
А 2^1024 = 1,79 * 10^308
Вот почему это самое большое значение, которое вы можете хранить в двойном размере.
При использовании числа с четверной точностью они равны 112 битам и 14 цифрам для показателя степени, поэтому наибольший показатель равен 16384.
Как 2^16384 дает 1,18 * 10^4932, вы видите, что ваш тест на C++ был совершенно корректным и что на x64 ваш double фактически хранится в числе с четверной точностью.