Как представить 0,1 в арифметике с плавающей запятой и десятичной - PullRequest
11 голосов
/ 10 августа 2010

Я пытаюсь лучше понять арифметику с плавающей запятой и видел несколько ссылок на «Что должен знать каждый компьютерный специалист об арифметике с плавающей запятой».

Я до сих пор не понимаю, как такое число, как 0.1 или 0.5 хранится в числах с плавающей запятой и в виде десятичных дробей.

Может кто-нибудь объяснить, как устроена память?

Я знаю, что число с плавающей точкой состоит из двух частей (то есть числак власти чего-либо).

Ответы [ 2 ]

39 голосов
/ 10 августа 2010

Я всегда указывал людям на онлайн-конвертер Харальда Шмидта вместе со статьей Википедии IEEE754-1985 с ее красивыми картинками.

Для этих двух конкретных значений вы получите (для 0,1):

s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm    1/n
0 01111011 10011001100110011001101
           |  ||  ||  ||  ||  || +- 8388608
           |  ||  ||  ||  ||  |+--- 2097152
           |  ||  ||  ||  ||  +---- 1048576
           |  ||  ||  ||  |+-------  131072
           |  ||  ||  ||  +--------   65536
           |  ||  ||  |+-----------    8192
           |  ||  ||  +------------    4096
           |  ||  |+---------------     512
           |  ||  +----------------     256
           |  |+-------------------      32
           |  +--------------------      16
           +-----------------------       2

Знак положительный, это довольно просто.

Показатель степени равен 64+32+16+8+2+1 = 123 - 127 bias = -4, поэтому множитель равен 2<sup>-4</sup> или 1/16.

Мантисса короткая. Он состоит из 1 (неявное основание) плюс (для всех этих битов, каждый из которых стоит 1/(2<sup>n</sup>), поскольку n начинается с 1 и увеличивается вправо), {1/2, 1/16, 1/32, 1/256, 1/512, 1/4096, 1/8192, 1/65536, 1/131072, 1/1048576, 1/2097152, 1/8388608}.

Когда вы складываете все это, вы получаете 1.60000002384185791015625.

Когда вы умножаете это значение на множитель, вы получаете 0.100000001490116119384765625, поэтому они говорят, что вы не можете представлять 0.1 точно в виде числа с плавающей запятой IEEE754, и предоставляют так много возможностей для SO для людей, отвечающих на вопросы типа "why doesn't 0.1 + 0.1 + 0.1 == 0.3?" : -)


Пример 0.5 значительно проще. Он представлен как:

s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm
0 01111110 00000000000000000000000

, что означает, что это неявное основание, 1, плюс никаких других добавок (все биты мантиссы равны нулю).

Знак снова положительный. Показатель степени 64+32+16+8+4+2 = 126 - 127 bias = -1. Следовательно, множитель равен 2<sup>-1</sup>, что составляет 1/2 или 0.5.

Таким образом, окончательное значение равно 1, умноженному на 0.5 или 0.5. Voila!


Мне иногда было проще думать об этом с точки зрения десятичной дроби.

Число 1.345 эквивалентно

1 + 3/10   + 4/100 + 5/1000

или

        -1       -2      -3
1 + 3*10   + 4*10  + 5*10

Аналогично, представление IEEE754 для десятичного числа 0.8125:

s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm
0 01111110 10100000000000000000000

С неявным основанием 1, это эквивалентно двоичному файлу:

         01111110-01111111
1.101 * 2

или

                     -1
(1   + 1/2 + 1/8) * 2     (no 1/4 since that bit is 0)

, который становится:

(8/8 + 4/8 + 1/8) * 1/2

и , тогда становится:

13/8 * 1/2 = 0.8125
2 голосов
/ 10 августа 2010

См. запись в Википедии и группа IEEE , первая.

По сути, есть знак, число и показатель степени. Число в одной базе не может быть окончательно представлено в другой базе, если исходная база имеет факторы, которых нет в базе назначения. Например, 1/3 нельзя представить как конечное десятичное число, но тривиально представить в виде троичного (base-3) числа: (0.1) 3 .

Итак, 0.5 имеет конечное двоичное представление, (0.1) 2 , то есть 2 -1 , но 0.1 имеет повторение представление, потому что 2 и 10 имеют множитель (5), который не является общим.

...