Двоичная система и байты
Предпосылки: нет.
Первая мысль при встрече с компьютером — это умная машина, которая «понимает» числа, буквы, картинки. Внутри её нет никакой такой осведомлённости: есть миллиарды переключателей, каждый в одном из двух состояний — ток идёт или не идёт. Любое число, любая буква, любой пиксель цветной фотографии — это расклад этих переключателей. Вопрос не в том, как компьютер «знает» букву, а в том, как из двух состояний собрать достаточно выразительную запись.
Десятичная система привычна человеку: десять цифр, потому что у нас десять пальцев. Но различать десять уровней напряжения на электронном элементе дорого и ненадёжно, тогда как различить «есть ток — нет тока» — задача для самого дешёвого транзистора. Значит, работать придётся с двумя цифрами — 0 и 1.
Бит
Транзистор — основной элемент процессора — работает как переключатель: открыт или закрыт. Одно из двух состояний. Этого достаточно, чтобы хранить одну двоичную цифру. Такая минимальная единица информации называется бит (bit, сокращение от binary digit — «двоичная цифра»). Бит принимает значение 0 или 1. Меньшее количество информации записать нельзя.
Одного бита хватает, чтобы закодировать «да/нет», «вкл/выкл», «истина/ложь». Но для чисел больше 1, для букв, для координат — нужно больше битов. Как именно — зависит от того, как устроена позиционная система счисления.
Позиционная запись
В десятичной системе запись 349 означает: 3 сотни + 4 десятка + 9 единиц. Каждая позиция имеет вес — степень десятки:
349 = 3 × 10² + 4 × 10¹ + 9 × 10⁰
= 300 + 40 + 9
Двоичная система работает точно так же, только основание — два, а не десять. Вес каждой позиции — степень двойки:
| Позиция (справа) | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| Вес | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
Число 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 | Десятичная |
|---|---|---|
| 0000 | 0 | 0 |
| 0001 | 1 | 1 |
| 0010 | 2 | 2 |
| 0011 | 3 | 3 |
| 0100 | 4 | 4 |
| 0101 | 5 | 5 |
| 0110 | 6 | 6 |
| 0111 | 7 | 7 |
| 1000 | 8 | 8 |
| 1001 | 9 | 9 |
| 1010 | A | 10 |
| 1011 | B | 11 |
| 1100 | C | 12 |
| 1101 | D | 13 |
| 1110 | E | 14 |
| 1111 | F | 15 |
Один байт (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 комбинаций, 00000000–11111111. Для возраста, индекса пикселя, кода символа этого хватает. Но у температуры бывает минус, у баланса — дефицит, у координаты — направление «до» точки отсчёта. Знака у нуля с единицей нет; его приходится кодировать самими битами. Как — в следующей заметке.
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.