Числа №5. Знакомство с float
Переходим к числам с плавающей запятой, которые для краткости будем называть флотами. Они бывают половинной точности (16 бит), единичной (32, float), двойной (64, double) и больше. Для простоты будем работать с обычным 32-битным флотом.
Как мы выяснили, компьютер хранит числа в двоичном виде. Сложение и вычитание устроены по школьному принципу “в столбик”, и каждый разряд должен быть двоичным числом. По-другому компьютер не умеет – так устроены сумматоры (логические схемы): они принимают битовые входы по одному на разряд и выдают битовую маску разрядов результата. И еще бит переноса или переполнения.
Любое число, объявленное в коде, приводится к двоичному виду. Когда вы пишете в программе:
float f = 42.01
нужно понимать, что 42.01 – это еще не число. Это литерал, который задает
число. Литерал может быть другим, например 0.53 или -4.5234e5. Важно, что на
этапе лексера он хранится как строка с метаданными, мол, из этой штуки надо
извлечь флоат.
Дробные числа тоже приводятся к двоичному виду. В примере ниже – двоичная дробь:
1010111.011011
Кого-то она вводит в ступор, но ничего особенного в ней нет. Мы привыкли к десятичным дробям, но аналогично записывается дробь с любым основанием. Например, вот дроби в шестнадцатеричной и восьмеричной системах счисления:
0xfa523.ac591
05627.6232
Так что когда вы пишете f = 42.515625, помните – после компиляции никакого
числа 42.515625 нет. Оно преобразуется к двоичной дроби. Если точнее, это
только первый шаг: после преобразования двоичная дробь нормализуется и
помещается в специальный битовый контейнер. Но пока что мы рассмотрим только
преобразование.
Итак, как привести 42.515625 к двоичному виду? С целой частью все просто: делим на два и выписываем остаток, пока не получим ноль. Ниже – таблица для 42:
expr rem bit
42/2 21 0
21/2 10 1
10/2 5 0
5/2 2 1
2/2 1 0
1/2 0 1
= (101010)2
Для остатка алгоритм, по сути, тот же самый: умножаем его на два (то есть делим на два в отрицательной степени). Если результат меньше единицы, пишем ноль и продолжаем. Если больше единицы, то пишем единицу, вычитаем ее и продолжаем.
Вот что получится для 0.515625:
number *2 bit next
0.515625 1.03125 1 0.03125
0.03125 0.0625 0 0.0625
0.0625 0.125 0 0.125
0.125 0.25 0 0.25
0.25 0.5 0 0.5
0.5 1 1 -
= (0.100001)2
Итого – в двоичном виде 42.515625 становится (101010.100001)2. Это все еще
не конечный набор битов – впереди несколько других операций. Но уже на этом шаге
видны некоторые проблемы. Я оставлю их на следующую заметку, а вы в качестве
упражнения сделайте вот что: приведите к двоичному виду какие-нибудь числа вроде
1.1, 10.135 и так далее. Алгоритмы у вас есть.
Нашли ошибку? Выделите мышкой и нажмите Ctrl/⌘+Enter