Переходим к числам с плавающей запятой, которые для краткости будем называть флотами. Они бывают половинной точности (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 и так далее. Алгоритмы у вас есть.