Python: реализация 16-битного дополнения

Я реализовал дополнение в дополнение к 16-битным целым числам в python, однако я пытаюсь выяснить, есть ли лучший способ сделать это.

 # This function returns a string of the bits (exactly 16 bits)
 # for the number (in base 10 passed to it)
 def get_bits(some_num):
        binar = bin(some_num)[2::]
        zeroes = 16 - len(binar)
        padding = zeroes*"0"
        binar = padding + binar
        return binar


# This function adds the numbers, and handles the carry over
# from the most significant bit
def add_bits(num1, num2):
        result = bin(int(num1,2) + int(num2,2))[2::]
        # There is no carryover
        if len(result) <= 16 :
                result = get_bits(int(result,2))
        # There is carryover
        else :
                result = result[1::]
                one = '0000000000000001'
                result = bin(int(result,2) + int(one,2))[2::]
                result = get_bits(int(result,2))
        return result

А теперь пример запуска это будет:

print add_bits("1010001111101001", "1000000110110101")

возвращает:

0010010110011111

Является ли то, что написано, безопасным с точки зрения результатов (заметьте, я не делал здесь никаких отрицаний, поскольку эта часть тривиальна, меня больше интересуют промежуточные этапы)? Есть ли лучший питонический способ сделать это? Спасибо за любую помощь.

2 ответа

Решение

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

MOD = 1 << 16

def ones_comp_add16(num1,num2):
    result = num1 + num2
    return result if result < MOD else (result+1) % MOD

n1 = 0b1010001111101001
n2 = 0b1000000110110101
result = ones_comp_add16(n1,n2)

print('''\
  {:016b}
+ {:016b}
------------------
  {:016b}'''.format(n1,n2,result))

Выход:

  1010001111101001
+ 1000000110110101
------------------
  0010010110011111

Преобразование назад и вперед между числами, списками однобитовых строк и строк, вероятно, не выглядит как очень Pythonic способ начать.

Более конкретно, преобразование int в последовательность битов с использованием bin(i)[2:] довольно хакерский Это может стоить сделать в любом случае (например, потому что это более кратко или более эффективно, чем делать это численно), но даже если это так, было бы лучше обернуть его в функцию, названную для того, что он делает (и, возможно, даже добавить комментарий объясняя, почему ты так сделал).


У вас также есть излишне усложняющий код. Например, чтобы сделать перенос, вы делаете это:

one = '0000000000000001'
result = bin(int(result,2) + int(one,2))[2::]

Но вы знаете, что int(one,2) это просто число 1, если вы не облажались, так почему бы просто не использовать 1, который короче, более читабелен и очевиден, и устраняет любой шанс испортить?


И вы не следуете стилю PEP 8.


Таким образом, придерживаясь своей базовой схемы "использовать строку для битов, используйте только основные строковые операции, которые не изменились с Python 1.5 до 3.5 вместо formatи сделать основное сложение на целые числа вместо битов ", я бы написал это примерно так:

def to_bits(n):
    return bin(n)[2:]

def from_bits(n):
    return int(n, 2)

def pad_bits(b, length=16):
    return ["0"*length + b][-length:]

def add_bits(num1, num2):
    result = to_bits(from_bits(num1) + from_bits(num2))
    if len(result) <= 16: # no carry
        return pad_bits(result)
    return pad_bits(to_bits(from_bits(result[1:]) + 1))

Но еще лучшим решением было бы полностью абстрагировать строковое представление. Создайте класс, который знает, как вести себя как целое число, но также знает, как вести себя как последовательность битов. Или просто найти один на PyPI. Тогда ваш код станет тривиальным. Например:

from bitstring import BitArray

def add_bits(n1, n2):
    """
    Given two BitArray values of the same length, return a BitArray
    of the same length that's the one's complement addition.
    """
    result = n1.uint + n2.uint
    if result >= (1 << n1.length):
        result = result % n1.length + 1
    return BitArray(uint=result, length=n1.length)

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

Другие вопросы по тегам