Двоичная система и байты

Предпосылки: нет.

Целые числа

Первая мысль при встрече с компьютером — это умная машина, которая «понимает» числа, буквы, картинки. Внутри её нет никакой такой осведомлённости: есть миллиарды переключателей, каждый в одном из двух состояний — ток идёт или не идёт. Любое число, любая буква, любой пиксель цветной фотографии — это расклад этих переключателей. Вопрос не в том, как компьютер «знает» букву, а в том, как из двух состояний собрать достаточно выразительную запись.

Десятичная система привычна человеку: десять цифр, потому что у нас десять пальцев. Но различать десять уровней напряжения на электронном элементе дорого и ненадёжно, тогда как различить «есть ток — нет тока» — задача для самого дешёвого транзистора. Значит, работать придётся с двумя цифрами — 0 и 1.

Бит

Транзистор — основной элемент процессора — работает как переключатель: открыт или закрыт. Одно из двух состояний. Этого достаточно, чтобы хранить одну двоичную цифру. Такая минимальная единица информации называется бит (bit, сокращение от binary digit — «двоичная цифра»). Бит принимает значение 0 или 1. Меньшее количество информации записать нельзя.

Одного бита хватает, чтобы закодировать «да/нет», «вкл/выкл», «истина/ложь». Но для чисел больше 1, для букв, для координат — нужно больше битов. Как именно — зависит от того, как устроена позиционная система счисления.

Позиционная запись

В десятичной системе запись 349 означает: 3 сотни + 4 десятка + 9 единиц. Каждая позиция имеет вес — степень десятки:

349 = 3 × 10² + 4 × 10¹ + 9 × 10⁰
    = 300     + 40      + 9

Двоичная система работает точно так же, только основание — два, а не десять. Вес каждой позиции — степень двойки:

Позиция (справа)76543210
Вес1286432168421

Число 42 в двоичной записи: нужно разложить 42 на сумму степеней двойки.

42 = 32 + 8 + 2
   = 1×32 + 0×16 + 1×8 + 0×4 + 1×2 + 0×1

Запись: 00101010. Единицы стоят в позициях с весом 32, 8 и 2 — их сумма даёт 42. Нули — в остальных позициях. Проверка:

0×128 + 0×64 + 1×32 + 0×16 + 1×8 + 0×4 + 1×2 + 0×1
= 32 + 8 + 2
= 42

Обратное преобразование (из двоичной в десятичную) — просто подставляем единицы в таблицу весов и складываем.

Чтобы перевести число из десятичной в двоичную систему, есть способ, не требующий знания степеней двойки наизусть — последовательное деление на 2:

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. Дополняем нулями слева до 8 позиций: 00101010. Тот же результат.

Двоичная арифметика

Сложение в двоичной системе подчиняется тем же правилам, что и в десятичной. В десятичной: 7 + 8 = 15, записываем 5, переносим 1 в следующий разряд. В двоичной: 1 + 1 = 10 (два), записываем 0, переносим 1.

Правила для одного разряда:

0 + 0 = 0
0 + 1 = 1
1 + 0 = 1
1 + 1 = 10  (0, перенос 1)

Складываем 3 + 5. Три — 0011, пять — 0101:

    перенос:  1 1 1 0
              0 0 1 1   (3)
            + 0 1 0 1   (5)
            ---------
              1 0 0 0   (8)

Разряд за разрядом, справа налево: 1+1 = 10 (пишем 0, перенос 1). 1+0+перенос 1 = 10 (пишем 0, перенос 1). 0+1+перенос 1 = 10 (пишем 0, перенос 1). 0+0+перенос 1 = 1. Результат: 1000 = 8.

Процессор складывает числа именно так — разряд за разрядом с переносом. Чтобы сложить два десятичных разряда, нужно учесть 100 комбинаций (10×10 цифр), а два двоичных — всего 4 (2×2). Схему на 4 комбинации легко выразить в транзисторах; схема на 100 комбинаций — уже сложная таблица. Экспериментальные троичные ЭВМ (например, советская «Сетунь», 1958) показали, что третье состояние технически возможно, но каждый логический элемент становится резко сложнее, и выигрыш в плотности записи не компенсирует потерь.

От бита к байту

Один бит — 0 или 1 — слишком мал, чтобы представить что-то полезное. Буква алфавита — это минимум 5 бит (2⁵ = 32 варианта), но при этом нет места для цифр и знаков препинания. Нужна стандартная группа.

В 1950-х и начале 1960-х единого стандарта не было. CDC 6600 (1964) использовал 6-битные символы — 64 варианта, но строчные буквы уже не помещались. PDP-8 (1965) работал с 12-битными словами, удобными для вычислений, но избыточными для одного символа. В ходе проектирования IBM 7030 Stretch термин «байт» ввёл Вернер Бухгольц в 1956 году — слово byte намеренно написано с буквой y вместо bite («кусок»), чтобы не путать с bit. В той ранней записи байт ещё не был фиксированной восьмёркой: Бухгольц допускал длину от 1 до 6 бит, а компьютер поставили только в 1961. Стандартом 8 бит стали позже, с выходом IBM System/360 в 1964 году.

System/360 зафиксировал 8 бит как универсальную единицу. Почему именно 8? Два практических соображения:

Достаточный диапазон. 8 бит дают 2⁸ = 256 вариантов. Хватает для всех латинских букв (заглавных и строчных), цифр, знаков препинания и служебных кодов. 6 бит (64 варианта) — не хватало даже для строчных букв. 7 бит (128 вариантов) — достаточно для латиницы, но 8 бит дают ещё одно преимущество.

Степень двойки. 8 = 2³. Память компьютера — пронумерованный ряд ячеек; номер ячейки называется адресом. Когда размер ячейки — степень двойки, процессору проще вычислять адреса: вместо умножения достаточно сдвига битов (что это за операция — будет в побитовых операциях).

С 1964 года байт (byte) — группа из 8 бит — стал стандартной единицей хранения и адресации. Один байт хранит число от 0 (00000000) до 255 (11111111).

Шестнадцатеричная система

Байт удобно хранить, но неудобно читать глазами. Адрес памяти — 32 или 64 бита: строка 11011110101011011011111011101111 на экране отладчика превращает любую ошибку в поиск иголки в стоге. Десятичная запись не помогает — по 3 735 928 559 невозможно сказать, какие биты установлены. Нужна компактная запись, которая сохраняет прямую связь с битами.

Шестнадцатеричная система (hexadecimal, hex) использует 16 цифр: 0–9, далее A = 10, B = 11, C = 12, D = 13, E = 14, F = 15. Одна hex-цифра кодирует ровно 4 бита (2⁴ = 16 вариантов). Это значит, что любую группу из 4 бит можно записать одним символом:

ДвоичнаяHexДесятичная
000000
000111
001022
001133
010044
010155
011066
011177
100088
100199
1010A10
1011B11
1100C12
1101D13
1110E14
1111F15

Один байт (8 бит) записывается ровно двумя hex-цифрами. Число 42 (двоичное 00101010) — hex 2A: первая тетрада 0010 = 2, вторая 1010 = A. Четыре байта — 8 hex-цифр вместо 32 двоичных.

Запись 0xDEADBEEF — 32-битное число, часто используемое в отладке как маркер неинициализированной памяти. Префикс 0x — общепринятый способ отличить hex от десятичной записи.

0xDEADBEEF:

  D    E    A    D    B    E    E    F
 1101 1110 1010 1101 1011 1110 1110 1111

32 бита, но записаны 8 читаемыми символами. Перевод мгновенный: каждая hex-цифра — независимая группа из 4 бит.

Hex повсеместен: адреса памяти, коды цветов в вебе (#FF5733), MAC-адреса сетевых карт (см. Ethernet и коммутация), содержимое файлов в hex-редакторе. Везде, где важно видеть структуру на уровне байтов и полубайтов (полубайт из 4 бит называют ниббл, nibble — «маленький кусочек»).

Единицы объёма: KB vs KiB

Байт мал — реальные данные исчисляются миллиардами байтов. Для удобства используют приставки, но их две разных, и их путают.

ОбозначениеЗначениеТочное количество байт
1 kB (SI)10³1 000
1 KiB (IEC)2¹⁰1 024
1 MB (SI)10⁶1 000 000
1 MiB (IEC)2²⁰1 048 576
1 GB (SI)10⁹1 000 000 000
1 GiB (IEC)2³⁰1 073 741 824

Приставки SI (k, M, G) — степени десятки, так их определила метрическая система. Приставки IEC (Ki, Mi, Gi) — степени двойки, введены в 1998 году именно чтобы развести два значения. Производитель диска маркирует его как 500 GB (500 × 10⁹ байт) — ОС делит на 2³⁰ и показывает 465 GiB. Те же байты, две шкалы.

Одни и те же биты — разный смысл

Существует соблазн думать, что в памяти «лежат числа», «лежат буквы», «лежат картинки» — у каждого значения свой тип, видимый изнутри. Это иллюзия. В памяти лежат только биты, и ничего больше. Наивная модель «буквы хранятся буквами, а числа — числами» ломается уже на одном конкретном примере.

Возьмём восемь бит 01000001. В памяти они — просто восемь переключателей в определённых состояниях.

     Биты в памяти: 01000001

     Программа-калькулятор видит:  целое число 65
     Текстовый редактор видит:    букву 'A'
     Графический редактор видит:  оттенок серого (яркость 65 из 255)

Целое число 65 получается разложением по степеням двойки: 0×128 + 1×64 + 0×32 + 0×16 + 0×8 + 0×4 + 0×2 + 1×1 = 65.

Буква ‘A’ получается, если 65 — не значение, а номер в таблице символов. А оттенок серого — если 65 интерпретируется как яркость пикселя. Одни биты, три разных смысла.

Сами биты не несут информации о своём типе. Число, символ, цвет или инструкция процессора — решает программа, которая эти биты читает. Если программа ошибётся и прочитает текст как числа — результат будет бессмысленным, но компьютер не возразит. Для него всё — цепочки нулей и единиц.

Из этого следует практический вопрос: если соответствие «биты → символ» задаёт программа, то где оно записано и кто его гарантирует? Стандартные таблицы такого соответствия называются кодировками, и им посвящена отдельная заметка.


Восемь бит — это 256 комбинаций, 0000000011111111. Для возраста, индекса пикселя, кода символа этого хватает. Но у температуры бывает минус, у баланса — дефицит, у координаты — направление «до» точки отсчёта. Знака у нуля с единицей нет; его приходится кодировать самими битами. Как — в следующей заметке.

Sources

  • Petzold, C., 2000, Code: The Hidden Language of Computer Hardware and Software. Microsoft Press.
  • Patterson, D., Hennessy, J., 2013, Computer Organization and Design. 5th ed. Morgan Kaufmann.
  • Buchholz, W., 1962, Planning a Computer System: Project Stretch. McGraw-Hill.

Целые числа