Перевод чисел: от двоичной до шестнадцатеричной системы с помощью Python
Перевод чисел между системами счисления в Python
В Python встроены удобные средства для перевода целых чисел в двоичную, восьмеричную и шестнадцатеричную системы и обратно. Однако часто возникает необходимость работать с произвольными основаниями. В статье рассмотрены основные подходы, их цели и типичные ошибки.
Как использовать встроенные функции для перевода в двоичную, восьмеричную и шестнадцатеричную системы?
Самый простой способ - функции bin(), oct(), hex() и обратная функция int() с указанием основания.
# Перевод из десятичной в двоичную, восьмеричную, шестнадцатеричную
n = 255
print(bin(n)) # '0b11111111'
print(oct(n)) # '0o377'
print(hex(n)) # '0xff'
# Перевод обратно в десятичную
print(int('11111111', 2)) # 255
print(int('377', 8)) # 255
print(int('ff', 16)) # 255
Python перевести в систему счисления (перевод в системы счисления в python)
Результат bin(), oct(), hex() - строки с префиксами 0b, 0o, 0x. Если префикс не нужен, используется format() или срез строки.
print(format(255, 'b')) # '11111111'
print(format(255, 'o')) # '377'
print(format(255, 'x')) # 'ff'
print(format(255, 'X')) # 'FF' – заглавные буквы
Типичные ошибки:
- ValueError при передаче строки с некорректными символами (например, int('1g', 16)). Решение - проверять входные данные или использовать обработку исключений.
- Основание в int() должно быть от 2 до 36. Для большего основания встроенные средства не подходят.
- Функции bin(), oct(), hex() работают только с основаниями 2, 8, 16.
Цель использования: быстрая конвертация в стандартные системы счисления для визуализации, логирования или простых преобразований.
Как перевести десятичное число в систему с произвольным основанием от 2 до 36?
Встроенные функции ограничены тремя основаниями. Для произвольного основания потребуется собственная реализация.
def to_base(n, base):
if n == 0:
return '0'
digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
res = ''
negative = n < 0
n = abs(n)
while n > 0:
res = digits[n % base] + res
n //= base
return '-' + res if negative else res
print(to_base(255, 16)) # 'FF'
print(to_base(100, 2)) # '1100100'
print(to_base(0, 8)) # '0'
Алгоритм: последовательное деление на основание, остаток преобразуется в символ по словарю. Обработка нуля и отрицательных чисел выполняется отдельно.
Проблемы:
- Для оснований больше 36 требуется расширить алфавит (использовать строчные буквы, символы).
- При n=0 возвращать '0', иначе алгоритм не выдаст ни одного символа.
- Работа только с целыми числами; дробная часть требует другого подхода.
Как перевести число из произвольной системы счисления (строки) в десятичное?
Обратная задача решается умножением каждого разряда на основание в степени.
def from_base(s, base):
digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
s = s.upper()
if '-' in s:
s = s.replace('-', '')
sign = -1
else:
sign = 1
val = 0
for ch in s:
if ch not in digits[:base]:
raise ValueError(f"Неверный символ '{ch}' для основания {base}")
val = val * base + digits.index(ch)
return sign * val
print(from_base('FF', 16)) # 255
print(from_base('1100100', 2)) # 100
print(from_base('0', 8)) # 0
Строка приводится к верхнему регистру, знак минус обрабатывается отдельно. Для каждого символа определяется его числовое значение через индекс в алфавите.
Частая ошибка: путаница между строчными и прописными буквами. Решение - нормализация регистра. Также стоит проверять, что символ допустим для данного основания.
Как использовать f-строки и format() для форматированного вывода в разных системах?
format() и f-строки позволяют задавать ширину поля, заполнение, а также добавлять префикс системы.
n = 255
print(f"Двоичная: {n:b}") # '11111111'
print(f"Восьмеричная: {n:o}") # '377'
print(f"Шестнадцатеричная: {n:x}") # 'ff'
print(f"С префиксом: {n:#x}") # '0xff'
print(f"С выравниванием: {n:08b}") # '11111111' – ширина 8, заполнение нулями
Символ # перед спецификатором добавляет префикс 0b, 0o, 0x. Цифра после двоеточия задаёт минимальную ширину, а 0 - символ заполнения.
Нельзя задать произвольное основание, только 2, 8, 16. Если нужно основание 3 или 7, f-строки не помогут.
Как реализовать перевод в системы с основанием больше 36 (например, base62)?
Для представления чисел с большим основанием используют расширенный алфавит, включающий строчные и прописные буквы, а также цифры.
ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
def to_base62(n):
if n == 0:
return ALPHABET[0]
res = ''
while n > 0:
res = ALPHABET[n % 62] + res
n //= 62
return res
def from_base62(s):
return sum(ALPHABET.index(ch) * (62 ** i) for i, ch in enumerate(reversed(s)))
print(to_base62(123456789)) # '8m0Kx'
print(from_base62('8m0Kx')) # 123456789
Ключевой момент: порядок алфавита должен быть согласован. В приведённом примере сначала цифры, потом строчные, потом заглавные - это распространённая схема.
Необходимо следить за уникальностью символов. При использовании различных стандартов (например, base64 с + и /) алфавит меняется. Также важно обрабатывать большие числа - Python справляется с произвольной точностью.
Дополнительные примеры с пояснениями
Перевод больших чисел в шестнадцатеричную систему
Функция hex() работает с целыми числами любой длины.
big = 10**100
print(hex(big))
# Результат (начало): '0x1249ad2594c37ceb0b2784c4ce0bf38ace40f8a2b8e...'
0x1249ad2594c37ceb0b2784c4ce0bf38ace40f8a2b8e9e5f0c7a0b8b2c8d4e6f0a0b0c0d0e0f0...
Обратное преобразование через int(s, 16) также корректно для строк любой длины.
Рекурсивная реализация перевода в двоичную систему
Рекурсия может быть наглядной для понимания, но имеет ограничение глубины стека.
def to_bin(n):
if n == 0:
return '0'
if n == 1:
return '1'
return to_bin(n // 2) + str(n % 2)
print(to_bin(42)) # 101010
101010
Недостаток: для больших чисел может возникнуть переполнение стека. На практике лучше использовать цикл.
Обработка отрицательных чисел
Встроенные функции и ручные реализации корректно работают с отрицательными числами, сохраняя знак.
print(bin(-255)) # '-0b11111111'
print(oct(-255)) # '-0o377'
print(hex(-255)) # '-0xff'
print(int('-0b11111111', 2)) # -255
-0b11111111 -0o377 -0xff -255
При ручной реализации знак сохраняется отдельно, как показано ранее.
Перевод дробных чисел (умножение дробной части)
Для перевода дробной части десятичного числа в другую систему используется последовательное умножение на основание.
def frac_to_base(f, base, precision=10):
if f == 0:
return '0'
res = ''
for _ in range(precision):
f *= base
digit = int(f)
res += '0123456789ABCDEF'[digit]
f -= digit
if f == 0:
break
return res
# Перевод 0.625 в двоичную: 0.625*2=1.25 -> 1, 0.25*2=0.5 -> 0, 0.5*2=1.0 -> 1 -> 0.101
print(frac_to_base(0.625, 2)) # '101'
101
Целая и дробная части переводятся отдельно и объединяются через точку.
Использование format с префиксом и шириной для выравнивания
Часто требуется вывести числа в табличном виде с фиксированной шириной колонок.
values = [0, 15, 255, 1024]
for v in values:
print(f"{v:>5} -> {v:08b} -> {v:#06x}")
0 -> 00000000 -> 0x0000
15 -> 00001111 -> 0x000f
255 -> 11111111 -> 0x00ff
1024 -> 100000000 -> 0x0400
Спецификатор :>5 выравнивает по правому краю шириной 5, :08b - двоичное с заполнением нулями до 8 символов, :#06x - шестнадцатеричное с префиксом и общей шириной 6.
Полноценная реализация base64 (без padding)
Base64 часто используется для кодирования бинарных данных, но можно реализовать и для целых чисел.
ALPHABET64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
def to_base64(n):
if n == 0:
return ALPHABET64[0]
res = ''
while n > 0:
res = ALPHABET64[n % 64] + res
n //= 64
return res
def from_base64(s):
return sum(ALPHABET64.index(ch) * (64 ** i) for i, ch in enumerate(reversed(s)))
print(to_base64(123456789)) # '7MqK'
print(from_base64('7MqK')) # 123456789
7MqK 123456789
Важно: стандартный base64 добавляет символ '=' для выравнивания блоков, здесь реализована компактная версия без padding.
Перевод в римскую систему (непозиционная)
Хотя это выходит за рамки позиционных систем, для полноты можно упомянуть, как реализовать перевод в римские цифры. Однако в Python нет встроенной поддержки, и это требует специального алгоритма.
def to_roman(num):
values = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]
symbols = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I']
res = ''
for v, s in zip(values, symbols):
while num >= v:
res += s
num -= v
return res
print(to_roman(2024)) # MMXXIV
MMXXIV
Данный пример показывает, что не все системы счисления являются позиционными, но Python позволяет реализовать любой алгоритм.