Что такое система счисления
Способ записи чисел — это набор цифр и правило, как по ним вычислить значение. Количество разных цифр называется основанием: у десятичной записи 10 цифр, у двоичной 2, у шестнадцатеричной 16.
Мы так привыкли к десятичной системе счисления, что не замечаем её правил. Но число 222 состоит из трёх одинаковых цифр, и каждая значит своё: двести, двадцать и два. Это и есть главная идея позиционной записи — цифра «весит» столько, сколько позволяет её место. Если основание другое, меняются только веса позиций, а правило остаётся тем же. Поэтому, разобравшись с одной системой счисления, легко понять все остальные. Исключение — непозиционные записи: к ним это правило не подходит.
В школьной программе 8 класса по федеральной образовательной программе основного общего образования (ФОП ООО) обязательна двоичная запись с переводом целых чисел от 0 до 1024[1]. Другие системы счисления — восьмеричная и шестнадцатеричная — встречаются в учебниках как продолжение темы: они нужны, чтобы коротко записывать длинные двоичные числа.
Позиционные и непозиционные системы счисления
В позиционной записи значение цифры зависит от её места в числе, в непозиционной — нет. Пример непозиционной — римские цифры: знак X всегда означает десять, где бы он ни стоял.
| Признак | Позиционная (десятичная) | Непозиционная (римская) |
| Значение знака | Зависит от места: 5 в 50 и в 500 весит по-разному | Постоянное: V всегда пять |
| Ноль | Есть, нужен для пустых позиций | Нет |
| Пример | 14 = 1 · 10 + 4 | XIV = 10 + (5 − 1) |
| Сложение столбиком | Удобно | Почти невозможно |
| Где встречается | Везде в расчётах | Номера веков, глав, циферблаты |
В римской записи есть своё правило: меньший знак перед большим вычитается (IV = 4), после большего — прибавляется (VI = 6). Но это не позиционность в строгом смысле: знаки не умножаются на вес позиции. Поэтому римскими цифрами трудно считать, и в компьютерах такую систему счисления не используют. Зато удобно пробовать программы: перевести римское число в обычное — хорошая задача на строки и словари.
Основание и развёрнутая запись числа
Развёрнутая запись — это число, расписанное как сумма «цифра × основание в степени номера позиции». Номера позиций считают справа, начиная с 0, поэтому самая правая цифра всегда умножается на 1.
Для десятичного 345: 3 · 10² + 4 · 10¹ + 5 · 10⁰ = 300 + 40 + 5. Для восьмеричного 3458: 3 · 8² + 4 · 8¹ + 5 · 8⁰ = 192 + 32 + 5 = 229. Цифры одни и те же, а значения разные — всё решает основание. Отсюда два важных правила. Первое: цифра всегда меньше основания, поэтому в восьмеричной нет цифр 8 и 9. Второе: запись «10» в любом основании равна самому основанию — 102 = 2, 108 = 8, 1016 = 16.
Развёрнутая запись — универсальный способ перевести число из любой позиционной системы счисления в десятичную. Без неё не получится проверить ни один перевод, поэтому пропускать эту тему не стоит. Достаточно знать степени основания и уметь умножать.
Восьмеричная и шестнадцатеричная записи
Восьмеричная запись использует 8 цифр от 0 до 7, шестнадцатеричная — 16 знаков: цифры от 0 до 9 и буквы A, B, C, D, E, F для значений от 10 до 15.
| Десятичное | Двоичное | Восьмеричное | Шестнадцатеричное |
| 0 | 0 | 0 | 0 |
| 5 | 101 | 5 | 5 |
| 8 | 1000 | 10 | 8 |
| 10 | 1010 | 12 | A |
| 15 | 1111 | 17 | F |
| 16 | 10000 | 20 | 10 |
| 64 | 1000000 | 100 | 40 |
| 255 | 11111111 | 377 | FF |
Почему именно 8 и 16? Документация Python не случайно даёт для них отдельные приставки, а не только для двоичной. Потому что это степени двойки: 8 = 2³, 16 = 2⁴. Благодаря этому одна восьмеричная цифра заменяет ровно 3 двоичные, а одна шестнадцатеричная — ровно 4. Длинная строка нулей и единиц превращается в короткую и удобную запись без вычислений. Например, байт 11111111 в шестнадцатеричном виде — всего две буквы FF.
Перевод через двоичную: триады и тетрады
Чтобы перевести двоичное число в восьмеричное, разбейте его справа налево на группы по 3 цифры (триады), а для шестнадцатеричного — по 4 цифры (тетрады). Каждая группа заменяется одной цифрой.
Переведём 1011102 в восьмеричную. Делим справа: 101 | 110. Группа 101 — это 5, группа 110 — это 6. Ответ: 568. Проверка через развёрнутую запись: 5 · 8 + 6 = 46, и 1011102 тоже равно 32 + 8 + 4 + 2 = 46.
Теперь 101011112 в шестнадцатеричную. Тетрады: 1010 | 1111. 1010 = 10 = A, 1111 = 15 = F. Ответ: AF16, то есть 175. Если в левой группе не хватает цифр, допишите нули слева: 11 0101 → 0011 0101 → 3516.
Обратный перевод работает так же: каждую восьмеричную цифру заменяют тремя двоичными, каждую шестнадцатеричную — четырьмя. Так можно перевести восьмеричное число в шестнадцатеричное без деления: через двоичную запись как промежуточный шаг. Поупражняться с двоичными разрядами можно в тренажёре вверху страницы, а подробный разбор перевода целых чисел — в статье о двоичной записи чисел.
Перевод в любое основание и обратно
Чтобы перевести десятичное число в основание k, делите его на k с остатком, пока частное не станет 0, и запишите остатки снизу вверх. Для обратного перевода используйте развёрнутую запись.
Переведём 200 в восьмеричную: 200 : 8 = 25, остаток 0; 25 : 8 = 3, остаток 1; 3 : 8 = 0, остаток 3. Снизу вверх: 3108. Проверка: 3 · 64 + 1 · 8 + 0 = 200. Для шестнадцатеричной остатки от 10 до 15 записывают буквами.
n = int(input())
k = int(input())
cifry = "0123456789ABCDEF"
otvet = ""
while n > 0:
otvet = cifry[n % k] + otvet
n = n // k
print(otvet if otvet else "0")
Программа переводит число в любое основание от 2 до 16. Программа не проверяет ввод, поэтому основание больше 16 или отрицательное число давать ей нельзя. Строка cifry служит таблицей: остаток 11 превращается в букву B, потому что на 11-й позиции этой строки стоит B. Имена otvet и cifry выбраны по совету руководства PEP 8: переменная должна говорить, что в ней лежит. Это тот же алгоритм деления, что и на бумаге, только без ошибок при списывании остатков. Как устроены такие циклы, объясняет урок о цикле while в Python.
Функции bin, oct, hex и int в Python
В Python есть 4 встроенные функции для перевода: bin(), oct() и hex() переводят целое число в строку с двоичной, восьмеричной и шестнадцатеричной записью, а int(строка, основание) — обратно.
print(bin(46), oct(46), hex(175))
print(int("56", 8), int("af", 16), int("101110", 2))
print(0o56 + 0xAF)
0b101110 0o56 0xaf
46 175 46
221
Приставки 0b, 0o и 0x подсказывают основание. Их же можно писать прямо в коде: 0xAF — обычное целое число 175. Функция int принимает основание от 2 до 36 и не различает регистр букв. Все эти функции описаны в официальной документации Python[2], там же перечислены допустимые основания. Удобный приём для самопроверки: переведите число вручную, а потом сверьтесь с Python. Исследования Roediger и Karpicke показывают, что такая самостоятельная проверка запоминается лучше, чем чтение готового ответа.
Где встречаются разные основания
Шестнадцатеричную запись чаще всего видят в цветах веб-страниц: код вида #FF8800 — это 3 байта, по одному на красный, зелёный и синий. FF = 255 означает максимум яркости.
Восьмеричная запись встречается реже, например в правах доступа к файлам в Linux. Двоичная лежит в основе всего, что хранит компьютер. А основание 60 мы используем каждый день, не задумываясь. По ФОП ООО эти примеры не обязательны, но они помогают понять, что основание выбирают по удобству: в часе 60 минут, в минуте 60 секунд. Это след древней шестидесятеричной записи. Разобраться, как буквы, картинки и звуки превращаются в биты, поможет статья о кодировании информации.
Когда перевод через двоичную не подходит
Если основания не являются степенями двойки, группировка по 3 или 4 цифры не подходит: нужен перевод через десятичную. Вот 4 таких ситуации. Третью из них подробно разбирает официальная документация Python в главе о дробных числах.
- Перевод между основаниями 3 и 5. Ни одно из них не степень двойки, триады не помогут.
- Число в основании 10 нужно записать в основании 16. Сначала делите на 16 или переводите в двоичную делением на 2.
- Дроби вроде 0,1. Многие из них в двоичной записи бесконечны, поэтому
0.1 + 0.2в Python не даёт ровно 0.3. - Римские числа больше 3999. Стандартная запись без черт над знаками до них не дотягивает, и алгоритм деления к ней неприменим.
«Компьютер считает в шестнадцатеричной». Это миф: внутри машина хранит биты, а шестнадцатеричная запись нужна людям, чтобы короче читать двоичные данные.
«Буквы в числе — это ошибка». Это не подтверждается: в шестнадцатеричной записи A–F — обычные цифры со значениями от 10 до 15.
Чего делать нельзя
Нельзя разбивать двоичное число на группы слева направо: группы отсчитывают от правого края, иначе ответ изменится. Вот 6 правил.
- Нельзя использовать цифру, равную основанию или большую: в восьмеричной записи нет 8 и 9.
- Не следует опускать основание у записи: 100 может означать 4, 64, 100 или 256.
- Не стоит забывать нули внутри групп — тетрада 1001 равна 9, а без нулей получится 11, то есть 3.
- Нельзя передавать в
intстроку с недопустимой цифрой:int("19", 8)даст ValueError. - Не следует сравнивать строки из
bin()как числа — сравнивайте сами целые значения. - Не стоит учить таблицу до 255 наизусть: достаточно 16 строк для тетрад.
Источники
[1] Приказ Минпросвещения России от 18.05.2023 № 370 «Об утверждении федеральной образовательной программы основного общего образования».
[2] The Python Tutorial (официальная документация Python 3). Python Software Foundation.
[3] Roediger H. L., Karpicke J. D. Test-enhanced learning: Taking memory tests improves long-term retention // Psychological Science. 2006. Vol. 17, № 3. P. 249–255.
Вопросы и ответы
Почему в шестнадцатеричной записи буквы, а не цифры 10–15?
Каждая позиция должна занимать ровно один знак. Запись «10» уже означает «одна шестнадцатка и ноль», поэтому для значений от 10 до 15 взяли буквы A–F.
Какое основание самое маленькое?
Для позиционной записи — 2: нужны хотя бы две цифры, 0 и 1. С одной цифрой можно только ставить палочки, как при счёте на пальцах.
Как проверить перевод без компьютера?
Переведите ответ обратно через развёрнутую запись и сравните с исходным числом. Самопроверка таким способом закрепляет навык лучше, чем повторное чтение правила[3].
Сколько цифр нужно, чтобы записать байт в шестнадцатеричном виде?
Ровно две: байт — это 8 бит, то есть две тетрады. Поэтому значения от 0 до 255 записываются от 00 до FF.
Нужно ли знать римские цифры программисту?
Для работы с компьютером — нет. Но задача перевода римского числа в обычное хорошо тренирует строки, словари и условия.
Почему hex() выдаёт маленькие буквы?
Так устроена функция в Python. Если нужны заглавные, используйте format(n, "X") или метод upper() у результата.