Перевод чисел: от двоичной до шестнадцатеричной системы с помощью 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 позволяет реализовать любой алгоритм.

перевод в системы счисления в Python - comments

En
Python перевести в систему счисления (python)