Позиционные системы счисления и перевод между основаниями
Откуда берётся «вес» цифры и почему двоичная система — родной язык компьютера.
Позиционная система счисления — система записи чисел, в которой вклад цифры в значение числа зависит не только от самой цифры, но и от её позиции (разряда).
Зачем это нужно
Вы каждый день пишете числа и не задумываетесь, что 25 и 52 — это одни и те же цифры, но разные числа. Разница в позиции. В старшей школе и на ЕГЭ системы счисления — это фундамент: без них не понять, как компьютер хранит числа, как работают цвета в вебе (#FF8800), маски подсети и логические схемы. Хорошая новость: за внешней «магией» стоит одна простая идея, которую вы освоите за этот урок раз и навсегда.
Интуиция: число как сумма «весов»
В привычной десятичной системе основание равно 10, а цифры — от 0 до 9. Число — это сумма цифр, умноженных на степени основания. Возьмём 2025:
2025 = 2·10³ + 0·10² + 2·10¹ + 5·10⁰
= 2000 + 0 + 20 + 5
Самая правая цифра стоит в разряде единиц (10⁰ = 1), левее — десятки (10¹), сотни (10²) и так далее. Поменяйте систему — поменяется только основание. В двоичной системе основание 2, цифры лишь 0 и 1, а веса разрядов — степени двойки: 1, 2, 4, 8, 16, 32…
Почему компьютеру удобна именно двойка? Потому что внутри он оперирует двумя состояниями: есть напряжение или нет, ток течёт или не течёт. Два устойчивых состояния надёжнее, чем десять «оттенков», которые легко спутать из-за помех. Поэтому вся электроника считает в двоичной системе, а человеку показывает результат в десятичной.
Почему выбор основания — это выбор компромисса
Стоит на секунду задуматься: десятичная система не «естественнее» других, мы привыкли к ней лишь потому, что у человека десять пальцев. Существовали и другие системы: вавилоняне считали в шестидесятеричной (её следы — в 60 минутах и 360 градусах), у некоторых народов была двенадцатеричная (отсюда дюжина). С точки зрения математики все позиционные системы равноправны — любое число записывается в любой из них, и арифметика подчиняется одним и тем же законам. Меняется лишь основание, то есть «шаг», с которым мы переходим к следующему разряду.
У основания есть содержательный смысл-компромисс. Чем оно меньше, тем проще «алфавит» цифр (в двоичной их всего две), но тем длиннее запись числа. Чем оно больше, тем короче запись, но тем больше разных символов нужно различать. Двоичная система — крайность в сторону простоты алфавита: всего два знака, идеально ложащихся на «включено/выключено». Шестнадцатеричная — разумная середина для человека: запись вчетверо короче двоичной, а перевод в неё тривиален. Понимая этот компромисс, вы перестаёте воспринимать системы счисления как набор разрозненных правил и видите за ними единую идею.
Перевод из любой системы в десятичную
Это самый простой переход: распишите число как сумму «цифра × основание в степени разряда». Переведём двоичное 101101 в десятичное. Нумеруем разряды справа налево с нуля:
1·2⁵ + 0·2⁴ + 1·2³ + 1·2² + 0·2¹ + 1·2⁰
= 32 + 0 + 8 + 4 + 0 + 1 = 45
Python умеет это «из коробки» — функция int(строка, основание) читает запись числа в заданной системе и возвращает обычное целое:
# int(строка, основание) переводит запись в десятичное число
print(int("101101", 2)) # двоичное
print(int("755", 8)) # восьмеричное
print(int("1F", 16)) # шестнадцатеричное
print(int("2025", 10)) # десятичное (для проверки)
Вывод:
45 493 31 2025
Перевод из десятичной в любую систему: деление с остатком
Обратный переход — алгоритм «деления с остатком». Делим число на основание, записываем остаток, частное снова делим — и так пока частное не станет нулём. Остатки, прочитанные снизу вверх, и есть искомая запись. Переведём 45 в двоичную:
45 : 2 = 22, остаток 1 ←
22 : 2 = 11, остаток 0
11 : 2 = 5, остаток 1
5 : 2 = 2, остаток 1
2 : 2 = 1, остаток 0
1 : 2 = 0, остаток 1 → читаем снизу вверх: 101101
Реализуем алгоритм сами, без встроенных функций — так понятнее, что внутри. Заодно проверим себя через стандартные bin, oct, hex (они добавляют префиксы 0b, 0o, 0x):
def to_base(n, base):
if n == 0:
return "0"
digits = "0123456789ABCDEF"
res = ""
while n > 0:
res = digits[n % base] + res # приписываем остаток слева
n //= base # целочисленное деление
return res
print(to_base(45, 2)) # вручную
print(bin(45)) # встроенная проверка
print(to_base(493, 8))
print(to_base(255, 16))
Вывод:
101101 0b101101 755 FF
Магия троек и четвёрок: 8 и 16 системы
Почему программисты так любят восьмеричную и шестнадцатеричную системы? Потому что 8 = 2³, а 16 = 2⁴ — это степени двойки. Значит, перевод между двоичной и ними не требует деления вообще: достаточно резать двоичную запись на группы. Для восьмеричной — по 3 бита справа, для шестнадцатеричной — по 4 бита, и каждую группу заменить одной цифрой.
Двоичное: 1010 1111
По 4 бита: 1010=A 1111=F → AF (шестнадцатеричное)
По 3 бита: 010 101 111 → 2 5 7 → 257 (восьмеричное)
Поэтому один байт (8 бит) — это ровно две шестнадцатеричные цифры. Цвет #FF8800 — это три байта: красный 255, зелёный 136, синий 0. Проверим эту «нарезку» на Python:
b = "10101111"
hex_val = format(int(b, 2), "X") # X — заглавные hex-цифры
print("Двоичное", b, "= шестнадцатеричное", hex_val)
# Разбор цвета #FF8800 на компоненты R, G, B
color = "FF8800"
r = int(color[0:2], 16)
g = int(color[2:4], 16)
b2 = int(color[4:6], 16)
print("R =", r, " G =", g, " B =", b2)
Вывод:
Двоичное 10101111 = шестнадцатеричное AF R = 255 G = 136 B = 0
Попробуй сам
Запустите код и поэкспериментируйте: поменяйте число и основания, проверьте, что прямой и обратный перевод дают исходное значение. Это лучший способ убедиться, что вы всё поняли.
def to_base(n, base):
if n == 0:
return "0"
digits = "0123456789ABCDEF"
res = ""
while n > 0:
res = digits[n % base] + res
n //= base
return res
x = 100
for base in (2, 8, 16):
s = to_base(x, base)
back = int(s, base) # переводим обратно
print(f"{x} в системе {base:>2} = {s:>8}, обратно = {back}")
Вывод:
100 в системе 2 = 1100100, обратно = 100 100 в системе 8 = 144, обратно = 100 100 в системе 16 = 64, обратно = 100
Частые ошибки
- Путают направление чтения остатков. При делении остатки читаются снизу вверх (от последнего к первому), а не в порядке получения.
- Забывают про разряд 0. Самый правый разряд — это основание в степени 0, то есть всегда «×1», а не «×основание».
- Считают, что A, B, C — это переменные. В шестнадцатеричной системе это цифры: A=10, B=11, …, F=15.
- Группируют биты не с того конца. Резать на тройки/четвёрки нужно строго справа; недостающие биты слева дополняют нулями.
Итоги
- В позиционной системе значение цифры = цифра × (основание)^(номер разряда), нумерация разрядов с нуля справа.
- В десятичную переводят суммированием весов; из десятичной — делением с остатком (читать снизу вверх).
- 8 и 16 системы — это «упакованная» двоичная: группы по 3 и по 4 бита соответственно.
- Python:
int(s, base)читает,bin/oct/hex/formatзаписывают в нужной системе.