Некоторые вопросы о точности с плавающей запятой и числовых пределах

Я знаю, что есть множество подобных вопросов, но я не мог найти свои ответы. Пожалуйста, прочитайте перед голосованием, чтобы закрыть (:

Числовой сопроцессор имеет восемь регистров с плавающей запятой. 
Каждый регистр содержит 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.

  1. double это не 80-битный процессор Intel с плавающей запятой, это 64-битный IEEE 754 с плавающей запятой. С sizeof(double) вы получите размер последнего.

  2. Это правильный способ получить максимальное значение для long doubleтак что твой вопрос бессмыслен.

  3. Возможно, вам не хватает, что числа с плавающей запятой не являются точными числами. 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 фактически хранится в числе с четверной точностью.

Другие вопросы по тегам