Двоичный код — это способ записи информации с помощью всего двух символов, 0 и 1. Одна такая позиция называется битом, а сам процесс представления чисел, текста, картинок и звука цепочками из нулей и единиц — двоичным кодированием. Синоним — бинарный код (от латинского binarius, «двойной»). В статье разберем, почему компьютеры устроены именно так, что такое байт и разряды, как перевести число из десятичной системы в двоичную и обратно, как кодируются буквы (ASCII, UTF-8), как с двоичным кодом работают в Python и какие ошибки встречаются чаще всего.
Содержание
Почему компьютеры используют два состояния
Причина в физике, а не в математике. Внутри процессора и памяти информация хранится уровнями напряжения, зарядом ячейки, намагниченностью участка диска. Различить два состояния («выше порога» / «ниже порога») просто и надежно: небольшая помеха не превратит 0 в 1. Если бы уровней было десять, как в десятичной записи, границы между ними были бы узкими, а ошибки чтения — частыми.
Второй аргумент — простота схем. Транзистор работает как ключ: открыт или закрыт. Из ключей собирают логические элементы (И, ИЛИ, НЕ), из них — сумматоры, регистры и весь процессор, а математика для двух состояний уже готова: булева алгебра.
Это не единственно возможный путь: в 1958 году в МГУ построили рабочий троичный компьютер «Сетунь». Но двоичная схема оказалась дешевле в массовом производстве, и сегодня вся серийная вычислительная техника — двоичная.
Бит, байт и разряды
Бит — минимальная единица информации: одна позиция, в которой стоит либо 0, либо 1. Один бит различает два значения. Каждый добавленный бит удваивает число комбинаций, поэтому n битов дают 2^n различных значений, а не n и не 2n.
Байт — группа из 8 битов, минимальная адресуемая единица памяти в подавляющем большинстве архитектур: процессор читает и пишет память байтами, а не отдельными битами. Один байт принимает 2^8 = 256 значений — от 00000000 до 11111111, то есть от 0 до 255.
| Разрядов (бит) | Комбинаций | Диапазон без знака | Где встречается |
|---|---|---|---|
| 1 | 2 | 0..1 | флаг, логическое значение |
| 4 | 16 | 0..15 | одна шестнадцатеричная цифра |
| 8 | 256 | 0..255 | байт, канал цвета, символ ASCII |
| 16 | 65 536 | 0..65 535 | короткое целое, отсчет звука на CD |
| 32 | 4 294 967 296 | 0..4 294 967 295 | целое int во многих языках, адрес IPv4 |
| 64 | около 1.8·10^19 | 0..2^64 — 1 | целое long, адрес памяти в 64-битной системе |
Разряд — позиция в записи числа. В двоичной записи каждый разряд имеет вес, равный степени двойки: справа налево 1, 2, 4, 8, 16 и так далее. Самый правый разряд — младший, самый левый — старший. На весах разрядов и строится перевод между системами счисления.
Перевод из десятичной системы в двоичную и обратно
Десятичное число в двоичное: деление на 2
Число делят на 2 нацело и записывают остаток (0 или 1). Частное снова делят на 2, пока оно не станет нулем. Двоичная запись — остатки, прочитанные снизу вверх (от последнего к первому).
Переведем 13:
| Шаг | Делим | Частное | Остаток |
|---|---|---|---|
| 1 | 13 : 2 | 6 | 1 |
| 2 | 6 : 2 | 3 | 0 |
| 3 | 3 : 2 | 1 | 1 |
| 4 | 1 : 2 | 0 | 1 |
Читаем остатки снизу вверх: 1101. Итак, 13 = 1101 в двоичной записи. Частая ошибка — прочитать остатки сверху вниз и получить 1011 (это 11, а не 13).
Для маленьких чисел быстрее не делить, а раскладывать по степеням двойки: 13 = 8 + 4 + 1, значит единицы стоят в разрядах с весами 8, 4 и 1, а в разряде с весом 2 — ноль: 1101. Деление на 2 удобнее, когда число большое и на глаз не раскладывается.
Двоичное число в десятичное: сумма весов
Каждую единицу умножают на вес ее разряда и складывают. Для 1101 (веса справа налево 1, 2, 4, 8):
1·8 + 1·4 + 0·2 + 1·1 = 8 + 4 + 0 + 1 = 13.
Еще пример: 10110 = 1·16 + 0·8 + 1·4 + 1·2 + 0·1 = 22.
Восьмеричная и шестнадцатеричная запись
Длинные цепочки нулей и единиц неудобно читать, поэтому используют компактные формы. В шестнадцатеричной системе одна цифра (0-9, A-F) ровно соответствует четырем битам, в восьмеричной (0-7) — трем. Это не другой код, а сокращенная запись того же двоичного: 1101 = D (hex) = 15 (oct), байт 11111111 = FF = 255. Поэтому цвета в CSS пишут как #FF0000, а адреса памяти — как 0x7FFE: двоичные данные видны «сжато», без перевода в десятичную систему.
Двоичный алфавит и кодирование символов
Двоичный алфавит — алфавит из двух символов, 0 и 1; его мощность (число символов) равна двум. Чтобы записать таким алфавитом буквы, каждой букве назначают номер и хранят его в двоичном виде. Договоренность «символ — номер» называется кодировкой.
ASCII — историческая 7-битная кодировка: 128 символов с номерами от 0 до 127 (латиница, цифры, знаки препинания, управляющие символы). Заглавная латинская A имеет номер 65, в двоичной записи 01000001 (старший, восьмой бит байта остается нулем). Кириллицы в ASCII нет: для нее использовали 8-битные кодировки (CP1251, KOI8-R), которые заполняли верхнюю половину байта, 128-255, каждая по-своему. Отсюда «кракозябры», когда текст открывали не в той кодировке.
Unicode решает проблему единым списком номеров для всех письменностей — в нем более 150 тысяч символов. UTF-8 — самый распространенный способ записать эти номера в байты, кодировка переменной длины: символ занимает от 1 до 4 байтов в зависимости от номера.
| Символ | Номер в Unicode | Байты в UTF-8 | Двоичный вид |
|---|---|---|---|
| A | U+0041 (65) | 1 байт: 41 | 01000001 |
| а (кириллица) | U+0430 (1072) | 2 байта: D0 B0 | 11010000 10110000 |
| € | U+20AC | 3 байта: E2 82 AC | 11100010 10000010 10101100 |
| 😀 | U+1F600 | 4 байта: F0 9F 98 80 | 11110000 10011111 10011000 10000000 |
Первые 128 символов UTF-8 совпадают с ASCII байт в байт, поэтому английский текст читается без изменений. А одна кириллическая буква в UTF-8 занимает 2 байта: слово «привет» из 6 букв весит 12 байтов.
Как кодируют числа, текст, изображения и звук
Один и тот же байт 01000001 — это число 65, буква A или яркость канала цвета. Смысл битам придает не запись, а формат, в котором программа их читает.
| Тип данных | Что кодируется | Как | Типичный размер |
|---|---|---|---|
| Целые числа | значение | позиционная двоичная запись; отрицательные — в дополнительном коде | 8, 16, 32, 64 бит |
| Дробные числа | знак, мантисса, порядок | стандарт IEEE 754 | 32 бит (float), 64 бит (double) |
| Текст | номер каждого символа | кодировка: ASCII, UTF-8, UTF-16 | 1-4 байта на символ в UTF-8 |
| Изображение (растр) | цвет каждого пикселя | три канала R, G, B по 8 бит; красный = 11111111 00000000 00000000 | 24 бит на пиксель, около 16.7 млн цветов |
| Звук | амплитуда сигнала через равные промежутки времени | дискретизация: на CD 44 100 отсчетов в секунду по 16 бит на каждый канал | 1411 кбит/с для стерео без сжатия |
Общий принцип: объект сначала измеряют или нумеруют (пиксель — цветом, звук — амплитудой, букву — номером), а полученные числа записывают в двоичном виде. Сжатие (JPEG, MP3, ZIP) добавляется поверх и меняет объем, а не идею.
Двоичный код в программировании
В повседневном коде двоичная запись нужна нечасто, но встречается в задачах про флаги, маски, сетевые адреса, права доступа и «сырые» байты. В Python для этого есть встроенные средства:
bin(13) # '0b1101' - число в двоичную строку
int('1101', 2) # 13 - двоичная строка в число
0b1101 # 13 - двоичный литерал прямо в коде
format(13, '08b') # '00001101' - с ведущими нулями до байта
hex(13), oct(13) # ('0xd', '0o15')
ord('A') # 65
format(ord('A'), '08b') # '01000001'
'а'.encode('utf-8') # b'\xd0\xb0' - кириллическая буква = 2 байта
len('привет'), len('привет'.encode('utf-8')) # (6, 12)
Побитовые операции работают с каждым разрядом отдельно. Возьмем 13 = 1101 и 6 = 0110:
13 & 6 # 4 - И: 1101 & 0110 = 0100 (единица там, где она в обоих)
13 | 6 # 15 - ИЛИ: 1101 | 0110 = 1111 (единица там, где хотя бы в одном)
13 ^ 6 # 11 - исключающее ИЛИ: 1101 ^ 0110 = 1011 (где биты различаются)
13 << 2 # 52 - сдвиг влево на 2 = умножение на 4
13 >> 1 # 6 - сдвиг вправо на 1 = целочисленное деление на 2
~13 # -14 - инверсия; в Python дает -(x + 1), так как int не ограничен байтом
Признак, когда побитовые операции уместны: у объекта есть набор независимых «да/нет» свойств. Их удобно хранить в одном числе, где каждый бит — отдельный флаг: проверка — value & FLAG, установка — value | FLAG. Так устроены права доступа к файлам в Unix (rwx = три бита) и многие системные API.
Типовые ошибки
Путать 2^n и n. Из «байт — 8 бит» делают вывод, что байт хранит 8 значений, или что для 256 значений нужно 256 бит. Правильно: n бит дают 2^n значений, 8 бит — 256. Родственная ошибка в коде — считать длину двоичной записи через len(bin(x)):
len(bin(255)) # 10 - неверно: посчитан и префикс '0b'
(255).bit_length() # 8 - верно: 255 помещается в 8 бит
(256).bit_length() # 9 - а 256 уже нет: это 257-е значение
Считать, что байт равен символу. Это верно только для ASCII. В UTF-8 кириллица занимает 2 байта, поэтому резать байтовую строку «по символам» нельзя:
s = 'привет'
s.encode('utf-8')[:3].decode('utf-8')
# UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd1 in position 2: unexpected end of data
s[:2].encode('utf-8') # b'\xd0\xbf\xd1\x80' - верно: сначала режем строку, потом кодируем
Забыть основание при переводе строки в число.
int('1101') # 1101 - строка прочитана как десятичное число
int('1101', 2) # 13 - верно: указано основание 2
Путать двоичный код и «код программы». Двоичный код — форма записи любых данных нулями и единицами. Код программы — текст на языке программирования, который пишет и читает человек. Между ними компилятор или интерпретатор: он превращает исходный код в машинный — двоичные команды процессора. Фраза «программист пишет на двоичном коде» неверна: вручную такие команды не набирают, разве что в учебных целях.
Выводы
- Двоичный код — это способ записи информации с помощью двух символов, 0 и 1; синоним — бинарный код, а представление чисел, текста, картинок и звука такими цепочками называется двоичным кодированием.
- Компьютеры используют два состояния из-за физики: различить два уровня напряжения просто и надежно, транзистор работает как ключ, а математика для двух состояний — булева алгебра.
- Бит — одна позиция со значением 0 или 1, байт — группа из 8 битов и минимальная адресуемая единица памяти; n битов дают 2^n значений, байт — 256 значений от 0 до 255.
- Перевод из десятичной системы в двоичную — деление на 2 с чтением остатков снизу вверх (13 = 1101), обратный перевод — сумма весов разрядов (1·8 + 1·4 + 0·2 + 1·1 = 13).
- Текст кодируется через номера символов: ASCII — 7-битная кодировка на 128 символов, UTF-8 записывает номера Unicode переменной длиной от 1 до 4 байтов, одна кириллическая буква занимает 2 байта.
- В Python двоичную запись дают
bin(),int(s, 2)иformat(x, '08b'), а побитовые операции&,|,^,<<,>>работают с каждым разрядом отдельно и удобны для флагов и масок.
Где применяется / связь с практикой
Понимание двоичного кода нужно не для чтения нулей и единиц глазами, а чтобы объяснять поведение программ: почему 0.1 + 0.2 не равно 0.3, почему строка из 6 букв весит 12 байтов, почему 32-битный int переполняется на 2 147 483 647, как читать маску подсети 255.255.255.0 и права доступа 755. На этот слой опираются алгоритмы, сети, базы данных и системное программирование.
Если хотите двигаться от основ к разработке, посмотрите каталог курсов по программированию Otus: там есть программы по Python, C, Go и другим языкам, где представление данных и побитовые операции разбираются на практических задачах. Познакомиться с форматом заранее можно на открытых уроках Otus — они бесплатные и проходят регулярно.
Смежные темы: Двоичная система счисления и бинарный код — что нужно знать новичку, Кодирование символов и UTF, Введение в кодирование информации.
FAQ
Как записывают отрицательные числа? В дополнительном коде: старший бит отводят под знак, отрицательное число получают инверсией битов положительного и прибавлением 1. В 8 битах помещается диапазон от -128 до 127, а сложение работает одной схемой для чисел любого знака.
Почему дробные числа «не сходятся»? Дробь 0.1 в двоичной записи бесконечна (как 1/3 в десятичной), а под мантиссу отведено конечное число бит, поэтому 0.1 + 0.2 в Python дает 0.30000000000000004. Для денег используют Decimal или целые в копейках.
Килобайт — это 1000 или 1024 байта? По стандарту 1 КБ = 1000 байт, а 1024 байта — кибибайт (КиБ). Производители дисков считают тысячами, операционные системы часто степенями двойки, поэтому диск «на 500 ГБ» показывает около 465 ГБ.



