В большинстве языков программирования числа с плавающей запятой представлены во многом подобно научной нотации : с показателем степени и мантиссой (также называемой значением). Скажем 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, C ++, Java и C #, двойная точность имеет отдельный тип double
, который часто реализуется как 64-битный.
Когда мы вызываем эту функцию в нашем примере 9.2
, вот что мы получаем:
>>> float_to_bin_parts(9.2)
['0', '10000000010', '0010011001100110011001100110011001100110011001100110']
Интерпретация данных
Вы увидите, что я разделил возвращаемое значение на три компонента. Эти компоненты:
- Подписать
- экспонент
- Мантисса (также называемая значимым, или дробная)
Подписать
Знак сохраняется в первом компоненте как один бит. Это легко объяснить: 0
означает, что число с плавающей точкой является положительным числом; 1
означает, что это отрицательно. Потому что 9.2
это положительно, наша ценность знака 0
.
экспонент
Показатель степени хранится в среднем компоненте как 11 битов. В нашем случае 0b10000000010
. В десятичном виде это представляет значение 1026
. Причудой этого компонента является то, что вы должны вычесть число, равное 2 (число битов) - 1 - 1, чтобы получить истинный показатель степени; в нашем случае это означает вычитание 0b1111111111
(десятичное число 1023
) для получения истинного показателя степени 0b00000000011
(десятичное число 3).
мантисса
Мантисса хранится в третьем компоненте как 52 бита. Тем не менее, есть и странность к этому компоненту. Чтобы понять эту причуду, рассмотрим число в научной нотации, например:
6.0221413x10 23
Мантисса будет 6.0221413
. Напомним, что мантисса в научной нотации всегда начинается с одной ненулевой цифры. То же самое относится и к двоичному, за исключением того, что двоичный имеет только две цифры: 0
и 1
. Таким образом, двоичная мантисса всегда начинается с 1
! При сохранении числа с плавающей точкой, 1
передняя часть двоичной мантиссы опускается для экономии места; мы должны поместить его обратно в начало нашего третьего элемента, чтобы получить истинную мантиссу:
1,0010011001100110011001100110011001100110011001100110
Это включает в себя нечто большее, чем простое сложение, потому что биты, хранящиеся в нашем третьем компоненте, на самом деле представляют дробную часть мантиссы справа от радикальной точки .
Имея дело с десятичными числами, мы «перемещаем десятичную точку» путем умножения или деления на степени 10. В двоичном коде мы можем сделать то же самое, умножив или разделив на степени 2. Поскольку наш третий элемент имеет 52 бита, мы делим это на 2 52, чтобы переместить это 52 места вправо:
0,0010011001100110011001100110011001100110011001100110
В десятичной записи это то же самое, что и деление 675539944105574
на, 4503599627370496
чтобы получить 0.1499999999999999
. (Это один пример соотношения, которое может быть выражено точно в двоичном формате, но только приблизительно в десятичном виде; более подробно см. 675539944105574/4503599627370496 .)
Теперь, когда мы превратили третий компонент в дробное число, добавление 1
дает истинную мантиссу.
Пересмотр компонентов
- Знак (первый компонент):
0
для положительного, 1
для отрицательного
- Экспонента (средний компонент): вычтите 2 (количество бит) - 1 - 1, чтобы получить истинную экспоненту
- Мантисса (последний компонент): разделите на 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 х 10 -1
Двоичные в десятичные:
19 х 2 -1
Отрицательный показатель деления:
19/2 1
Умножьте экспоненту:
19/2
Равно:
9,5
дальнейшее чтение