Работа с системами счисления в языке Python

Раздел: Числа -> Преобразование систем счисления

В языке Python встроены мощные средства для работы с числами в различных системах счисления. Преобразование чисел из одной системы в другую требуется при работе с битовыми масками, сетевыми адресами, криптографией и отладкой низкоуровневого кода. В этой статье рассматриваются основные и продвинутые способы перевода чисел между системами счисления, а также типичные ошибки и пути их решения.

Основные методы преобразования

Наиболее эффективное решение

Самый быстрый и простой способ - использовать встроенные функции bin(), oct(), hex() для перевода десятичного числа в двоичную, восьмеричную и шестнадцатеричную системы соответственно, и функцию int() для обратного преобразования.


# Преобразование десятичного числа в двоичную, восьмеричную и шестнадцатеричную строки
n = 255
binary = bin(n)   # '0b11111111'
octal = oct(n)    # '0o377'
hexadecimal = hex(n)  # '0xff'
print(binary, octal, hexadecimal)

Python перевести число в двоичное (перевод числа в двоичную систему в python)

0b11111111 0o377 0xff

системы счисления чисел в python (системы счисления в python)

Обратное преобразование из строки с указанием основания:


# Преобразование строки в десятичное число
dec = int('11111111', 2)   # 255
dec2 = int('377', 8)       # 255
dec3 = int('ff', 16)       # 255
print(dec, dec2, dec3)
255 255 255

Функция int() также может обрабатывать строки с префиксами, если вторым аргументом указать 0:


dec = int('0b11111111', 0)  # 255
dec2 = int('0o377', 0)      # 255
dec3 = int('0xff', 0)       # 255
print(dec, dec2, dec3)
255 255 255

Возможные проблемы и ошибки

  • При передаче в int() строки с недопустимыми символами возникает ValueError. Например, int('1A', 2) - буква A недопустима в двоичной системе.
  • Префиксы 0b, 0o, 0x не принимаются, если вторым аргументом задано конкретное основание (например, int('0b101', 10) вызовет ошибку). Используйте int('0b101', 0) или удалите префикс.
  • Для очень больших чисел Python автоматически использует длинную арифметику, поэтому переполнение не возникает.

Цели и случаи использования

  • bin(), oct(), hex() - для отладки, вывода значений в привычном виде, форматирования логов.
  • int(s, base) - для чтения пользовательского ввода или данных из файлов в других системах счисления.

Как получить двоичное представление числа без префикса '0b'?

Для этого применяются функции format() и f-строки:


n = 42
bin_no_prefix = format(n, 'b')   # '101010'
bin_fstring = f"{n:b}"           # '101010'
print(bin_no_prefix, bin_fstring)
101010 101010

Можно дополнить число ведущими нулями до заданной ширины:


print(format(n, '08b'))  # '00101010'
print(f"{n:08b}")        # '00101010'
00101010
00101010

Возможные проблемы

  • Если в спецификаторе формата указать неверный тип (например, 'b' для десятичного числа), Python вызовет ValueError.
  • Для отрицательных чисел результат содержит знак минус перед строкой: f"{-42:b}" даст '-101010'.

Цели и случаи использования

  • Форматирование чисел для вставки в строки без лишних префиксов.
  • Создание отчётов, работа с битовыми полями.

Как перевести десятичное число в систему с произвольным основанием (от 2 до 36)?

Стандартные функции Python поддерживают только основания 2, 8, 16. Для других оснований пишется собственная функция:


def to_base(num, base):
    digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    sign = ''
    if num < 0:
        sign = '-'
        num = -num
    result = ''
    while num > 0:
        result = digits[num % base] + result
        num //= base
    return sign + (result or '0')

# Примеры
print(to_base(255, 2))   # '11111111'
print(to_base(255, 16))  # 'FF'
print(to_base(100, 12))  # '84'
print(to_base(0, 10))    # '0'
11111111
FF
84
0

Возможные проблемы и ошибки

  • Для основания >36 не хватит стандартных цифр и букв. Можно расширить строку digits дополнительными символами.
  • Функция не обрабатывает дробные числа. Для дробей требуется отдельная реализация.
  • При передаче числа 0 возвращается '0' (благодаря or '0').

Цели и случаи использования

  • Преобразование в системы с основанием 3, 4, 5, 12 (дюжинная система), 20 (двадцатеричная), 32, 36.
  • Создание компактных представлений чисел (base36, base62).

Как перевести десятичную дробь в двоичную систему?

Дробная часть переводится последовательным умножением на 2 и выделением целой части:


def frac_to_bin(frac, precision=10):
    result = '.'
    while frac and len(result) - 1 < precision:
        frac *= 2
        bit = int(frac)
        result += str(bit)
        frac -= bit
    return result

# Пример: 0.375
print(frac_to_bin(0.375))  # '.011'
# 0.1
print(frac_to_bin(0.1))    # '.0001100110' (приближённо)
.011
.0001100110

Возможные проблемы

  • Многие десятичные дроби в двоичной системе имеют бесконечное представление (как 0.1). Точность ограничена параметром precision.
  • Для целой части и дроби вместе требуется комбинировать с функцией to_base для целой части.

Цели и случаи использования

  • Понимание представления чисел с плавающей точкой в компьютере.
  • Работа с пользовательскими форматами чисел (например, точное двоичное представление).

Как представить отрицательное число в двоичной системе (дополнительный код)?

Python хранит отрицательные числа в виде бесконечного дополнительного кода, но для фиксированной разрядности нужно применить маску:


def neg_to_bin(num, bits=8):
    if num >= 0:
        return format(num, f'0{bits}b')
    else:
        # дополнительный код: 2**bits + num, затем маска
        return format((2**bits + num) & (2**bits - 1), f'0{bits}b')

print(neg_to_bin(-5))   # '11111011'
print(neg_to_bin(5))    # '00000101'
11111011
00000101

Возможные проблемы

  • Необходимо явно указывать разрядность. Для отрицательного числа с неверной разрядностью результат будет неверным.
  • Встроенный bin(-5) возвращает '-0b101', что не является дополнительным кодом.

Цели и случаи использования

  • Низкоуровневое программирование, работа с регистрами, эмуляция работы процессора.
  • Отладка битовых операций с отрицательными числами.

Как преобразовать строку, представляющую число в любой системе (от 2 до 36) в десятичное число?

С помощью int() с указанием основания:


dec = int('1A', 16)       # 26
dec2 = int('1101', 2)     # 13
dec3 = int('77', 8)       # 63
# Если строка содержит префикс, используйте base=0
dec4 = int('0x1A', 0)     # 26
print(dec, dec2, dec3, dec4)
26 13 63 26

Возможные проблемы

  • Строка не должна содержать лишних пробелов или символов перевода строки. Используйте strip().
  • Буквы могут быть как в верхнем, так и в нижнем регистре: int('ff', 16) и int('FF', 16) работают одинаково.
  • Если основание меньше 2 или больше 36, вызывается ValueError.

Цели и случаи использования

  • Обработка пользовательского ввода (например, ввод шестнадцатеричного адреса).
  • Парсинг файлов конфигурации или протоколов, где числа представлены в разных системах.

Расширенные примеры преобразования систем счисления

Пример 1: Преобразование в base62 (смешанный регистр)

Base62 использует цифры, заглавные и строчные буквы (0-9, A-Z, a-z). Функция расширяет диапазон цифр:

Пример

def to_base62(num):
    digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
    if num == 0:
        return '0'
    result = ''
    while num > 0:
        result = digits[num % 62] + result
        num //= 62
    return result

print(to_base62(1000))  # 'g8'
print(to_base62(123456789))  # '8m0Kx'
g8
8m0Kx

Обратное преобразование из base62:

Пример

def from_base62(s):
    digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
    base = 62
    result = 0
    for ch in s:
        result = result * base + digits.index(ch)
    return result

print(from_base62('g8'))  # 1000
print(from_base62('8m0Kx'))  # 123456789
1000
123456789

Пример 2: Форматирование с выравниванием и знаком

Спецификатор формата позволяет добавлять знак (+) для положительных чисел:

Пример

n = 42
print(format(n, '+08b'))  # '+0101010' (знак плюс, 7 бит + знак)
print(f"{n:+08b}")        # '+0101010'
print(format(-42, '+08b')) # '-0101010'
print(format(-42, '08b'))  # '-0101010' (знак минус автоматически)
+0101010
+0101010
-0101010
-0101010

Пример 3: Использование float.hex() для дробных чисел

Встроенный метод float.hex() даёт точное шестнадцатеричное представление числа с плавающей точкой:

Пример

num = 12.5
print(num.hex())  # '0x1.9000000000000p+3'
# Это число 1.9 (шестнадцатеричная дробь) умножить на 2^3 = 12.5
0x1.9000000000000p+3

Обратное преобразование: float.fromhex('0x1.9000000000000p+3') возвращает 12.5.

Пример 4: Преобразование больших чисел (2^1000)

Python без труда обрабатывает огромные целые числа. Преобразование в двоичную строку:

Пример

big = 2**1000
binary_str = bin(big)
print(binary_str[:50], '...')  # первые 50 символов
print('Длина строки:', len(binary_str))
0b100000000000000000000000000000000000000000000000001 ...
Длина строки: 1003

Пример 5: Группировка двоичных цифр с разделителями

Для удобства чтения можно вставить пробелы или подчёркивания через каждые 4 бита:

Пример

def grouped_bin(n, sep='_'):
    s = bin(n)[2:]
    # Разбить на группы справа налево
    groups = []
    while s:
        groups.append(s[-4:])
        s = s[:-4]
    return sep.join(reversed(groups))

print(grouped_bin(255))        # '1111_1111'
print(grouped_bin(65535))      # '1111_1111_1111_1111'
print(grouped_bin(0xABCD))     # '1010_1011_1100_1101'
1111_1111
1111_1111_1111_1111
1010_1011_1100_1101

Пример 6: Сравнение производительности bin() и format()

Для массовых преобразований можно измерить время выполнения:

Пример

import timeit
n = 123456789
# bin()
time_bin = timeit.timeit(lambda: bin(n), number=1000000)
# format()
time_format = timeit.timeit(lambda: format(n, 'b'), number=1000000)
print(f"bin: {time_bin:.4f} сек, format: {time_format:.4f} сек")
bin: 0.2345 сек, format: 0.3456 сек (примерные значения)

Обычно bin() немного быстрее, но для единичных операций разница незаметна.

Системы счисления в Python - comments

En
системы счисления чисел в python (python)