Ответ 1
В большинстве языков программирования числа с плавающей запятой представлены во многом как научная нотация: с показателем и мантиссой (также называемой значимой), Очень простое число, скажем 9.2
, на самом деле является этой дробью:
5179139571476070 * 2 -49
Где показатель степени -49
, а мантисса - 5179139571476070
. Поэтому невозможно представить некоторые десятичные числа таким образом, что и показатель, и мантисса должны быть целыми числами. Другими словами, все поплавки должны быть целыми числами, умноженными на целую степень 2.
9.2
может быть просто 92/10
, но 10 не может быть выражен как 2 n, если n ограничено целыми значениями.
Просмотр данных
Во-первых, несколько функций для просмотра компонентов, которые создают 32- и 64-разрядные float
. Гляните на них, если вы только заботитесь о выходе (пример в Python):
def float_to_bin_parts(number, bits=64):
if bits == 32: # single precision
int_pack = 'I'
float_pack = 'f'
exponent_bits = 8
mantissa_bits = 23
exponent_bias = 127
elif bits == 64: # double precision. all python floats are this
int_pack = 'Q'
float_pack = 'd'
exponent_bits = 11
mantissa_bits = 52
exponent_bias = 1023
else:
raise ValueError, 'bits argument must be 32 or 64'
bin_iter = iter(bin(struct.unpack(int_pack, struct.pack(float_pack, number))[0])[2:].rjust(bits, '0'))
return [''.join(islice(bin_iter, x)) for x in (1, exponent_bits, mantissa_bits)]
У этой функции много сложностей, и это было бы довольно касательной, чтобы объяснить, но если вам интересно, важным ресурсом для наших целей является struct.
Python float
- это 64-битное число с двойной точностью. В других языках, таких как C, С++, Java и С#, двойная точность имеет отдельный тип double
, который часто реализуется как 64 бита.
Когда мы вызываем эту функцию с нашим примером, 9.2
, вот что мы получаем:
>>> float_to_bin_parts(9.2)
['0', '10000000010', '0010011001100110011001100110011001100110011001100110']
Интерпретация данных
Вы увидите, что я разделил возвращаемое значение на три компонента. Этими компонентами являются:
- Вход
- Экспонент
- Мантисса (также называемая значащим или фракцией)
Знак
Знак хранится в первом компоненте как один бит. Легко объяснить: 0
означает, что float является положительным числом; 1
означает, что он отрицательный. Поскольку 9.2
является положительным, наше знаковое значение 0
.
Экспонент
Показатель хранится в среднем компоненте как 11 бит. В нашем случае 0b10000000010
. В десятичной форме, которая представляет значение 1026
. Причуда этого компонента состоит в том, что вы должны вычесть число, равное 2 (# бит) - 1 - 1, чтобы получить истинную экспоненту; в нашем случае это означает вычитание 0b1111111111
(десятичное число 1023
) для получения истинного показателя, 0b00000000011
(десятичное число 3).
Mantissa
Мантисса хранится в третьем компоненте как 52 бит. Однако есть и причуда к этому компоненту. Чтобы понять эту причуду, рассмотрите число в научной нотации, например:
6.0221413x10 23
Мантисса будет 6.0221413
. Напомним, что мантисса в научной нотации всегда начинается с одной ненулевой цифры. То же самое справедливо для двоичного кода, за исключением того, что двоичный код имеет только две цифры: 0
и 1
. Таким образом, двоичная мантисса всегда начинается с 1
! Когда поплавок хранится, 1
в передней части двоичной мантиссы опущен, чтобы сэкономить место; мы должны поместить его обратно в передней части нашего третьего элемента, чтобы получить истинную мантиссу:
1,0010011001100110011001100110011001100110011001100110
Это связано не только с простым добавлением, потому что биты, хранящиеся в нашем третьем компоненте, фактически представляют дробную часть мантиссы, справа от radix точка.
Когда речь идет о десятичных числах, мы "перемещаем десятичную точку" умножая или делим на степени 10. В двоичном случае мы можем сделать то же самое путем умножения или деления на степени 2. Поскольку наш третий элемент имеет 52 бита, мы разделим его на 2 52, чтобы переместить его на 52 места вправо:
0,0010011001100110011001100110011001100110011001100110
В десятичной нотации это то же самое, что делить 675539944105574
на 4503599627370496
, чтобы получить 0.1499999999999999
. (Это один пример отношения, которое может быть выражено точно в двоичном выражении, но только приблизительно в десятичном значении, более подробно см.: 675539944105574/4503599627370496.)
Теперь, когда мы превратили третий компонент в дробное число, добавление 1
дает истинную мантиссу.
Повторное использование компонентов
- Знак (первый компонент):
0
для положительного,1
для отрицательного - Экспонент (средний компонент): вычитает 2 (# бит) - 1 - 1, чтобы получить истинную экспоненту
- Mantissa (последний компонент): разделите на 2 (# бит) и добавьте
1
, чтобы получить истинную мантиссу
Вычисление числа
Соединяя все три части вместе, мы получаем это двоичное число:
1.0010011001100110011001100110011001100110011001100110 x 10 11
Что мы можем затем преобразовать из двоичного в десятичный:
1.1499999999999999 x 2 3 (неточно!)
И умножьте, чтобы показать окончательное представление числа, с которого мы начали (9.2
), после сохранения в виде значения с плавающей запятой:
9,1999999999999993
Представление в виде фракции
9,2
Теперь, когда мы построили номер, можно восстановить его в простую часть:
1.0010011001100110011001100110011001100110011001100110 x 10 11
Сдвиг мантиссы на целое число:
10010011001100110011001100110011001100110011001100110 x 10 11-110100
Преобразование в десятичное число:
5179139571476070 x 2 3-52
Вычесть экспоненту:
5179139571476070 x 2 -49
Поверните отрицательный показатель в деление:
5179139571476070/2 49
Показатель умножения:
5179139571476070/562949953421312
Что равно:
9,1999999999999993
9.5
>>> float_to_bin_parts(9.5)
['0', '10000000010', '0011000000000000000000000000000000000000000000000000']
Уже вы можете видеть, что мантисса - всего 4 цифры, а затем множество нулей. Но пусть проходит через шаги.
Соберите двоичную научную нотацию:
1,0011 x 10 11
Сдвиг десятичной точки:
10011 x 10 11-100
Вычесть экспоненту:
10011 x 10 -1
Двоичный к десятичному:
19 x 2 -1
Отрицательный показатель деления:
19/2 1
Показатель умножения:
19/2
Равно:
9.5
Дальнейшее чтение
- Руководство по плавающей запятой: что каждый программист должен знать о арифметике с плавающей точкой, или, почему мои номера не складываются? (плавающий -point-gui.de)
- Что каждый компьютерный ученый должен знать о арифметике с плавающей точкой (Goldberg 1991).
- Формат с плавающей запятой с двойной точностью IEEE (Википедия)
- Арифметика с плавающей запятой: проблемы и ограничения (docs.python.org)
- Бинарный файл с плавающей запятой