Разделение 16-битного int на два 8-битных int в python - PullRequest
5 голосов
/ 26 июня 2010

Мне нужно преобразовать данное 16-битное целое число в два 8-битных целых числа, которые затем берут и используют в качестве выходных данных, где они направляются, беру два 8-битных целых числа и рекомбинирует их как 16-битный вход (к сожалению, вне моего контроля).Мое решение работает, но кажется нечистым.Для грубого числа я немного сдвигаю исходное число, а для точного числа я смотрю на него по модулю 256.

Так что я должен делать деление по полу для грубого числа, или я должен брать самое низкое8 бит для точного числа (и если да, то как?)?

Или я сумасшедший, и использование двух разных методов для разделения числа не проблема?

def convert(x):
    ''' convert 16 bit int x into two 8 bit ints, coarse and fine.

    '''
    c = x >> 8  # The value of x shifted 8 bits to the right, creating coarse.
    f = x % 256  # The remainder of x / 256, creating fine.
    return c, f

Ответы [ 6 ]

12 голосов
/ 26 июня 2010

Я бы сделал

c = (x >> 8) & 0xff
f = x & 0xff

Это безопаснее, см., Например,

>>> (10303 >> 8) & 0xff
40
>>> (1030333333 >> 8) & 0xff
163
>>> (1030333333 >> 8) 
4024739

Так как в python вы не можете контролировать , если число есть или нет16 бит, вы должны принудительно установить его в максимально 16-битное значение.Это не требуется, если вы уверены, что у вас есть 16-битное значение, но в этом случае функция является более общей и позволяет вам интересоваться только 16-битными значениями, независимо от того, что содержится в контейнере.

7 голосов
/ 26 июня 2010

В питоне бит-трейдинг не имеет особых преимуществ, поэтому я бы сказал:

c, f= divmod(your_number, 256)

РЕДАКТИРОВАТЬ: чтобы сделать ваше намерение еще более очевидным для источника просмотра с полномочиями двух (если такой зверь существует), вы можете заменить простой 256 гораздо более красочными альтернативами, такими как 1<<8, 2**8, 0x100 или 0400. Постоянное сворачивание, выполняемое оптимизатором глазков начиная с версии 2.5, гарантирует, что любой из них точно такой же, как при использовании 256 (я, очевидно, говорю о первых двух альтернативах, которые являются выражениями, которые оценивают 256; последние два постоянная 256).

$ python
Python 2.6.4 (r264:75706, Dec  7 2009, 18:45:15)
[GCC 4.4.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import dis
>>> dis.dis(compile("c, f= divmod(your_number, 1<<8)", "", "exec"))
  1           0 LOAD_NAME                0 (divmod)
              3 LOAD_NAME                1 (your_number)
              6 LOAD_CONST               3 (256)
              9 CALL_FUNCTION            2
             12 UNPACK_SEQUENCE          2
             15 STORE_NAME               2 (c)
             18 STORE_NAME               3 (f)
             21 LOAD_CONST               2 (None)
             24 RETURN_VALUE
2 голосов
/ 26 июня 2010

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

1 голос
/ 26 июня 2010

Вы говорите, что используете эти числа в качестве выходных данных, что говорит о том, что они будут преобразованы в строки в некоторой точке вниз по линии. Имея это в виду, я бы посоветовал вам взглянуть на модуль struct , который предназначен именно для этого (упаковка чисел в строки двоичных данных). В качестве бонуса вы получаете встроенную проверку ошибок для случая, когда x больше 65535 (так что, если что-то ужасно отвратительно в вашей программе, вы получите исключение). Например,

s = struct.pack('>H', x)

является эквивалентом

if x > 65535:
    raise struct.error(...)
c, f = convert(x)
s = chr(c) + chr(f) # big-endian (network) byte ordering

Если вам нужен другой порядок байтов, вы можете написать

s = struct.pack('<H', x)

Если у вас есть целая куча чисел для конвертации за один раз, struct.pack может сделать их в связках:

x = [10333, 10475, 3021, ...] # for example
s = struct.pack('>' + 'H' * len(x), *x)
0 голосов
/ 26 июня 2010

Я бы использовал побитовое значение, а не%. Возможно, в наши дни это не имеет большого значения для коротких целых чисел, но в более широком смысле оператор & потенциально более эффективен.

Может быть некоторая проблема с тем, как% обрабатывает отрицательные числа, но я сомневаюсь, что это уместно здесь.

0 голосов
/ 26 июня 2010

Если вы используете две половины числа в разных местах, я бы рекомендовал использовать две отдельные функции, но если вы собираетесь использовать их в одном месте, одна функция будет работать так же хорошо.

Есть несколько правильных способов разбить число, поэтому в конечном итоге все сводится к личным предпочтениям.Ваш код будет работать нормально, лишь бы вы передавали только числа длиной не более 16 бит.(что, вероятно, не будет большой проблемой, но вы должны знать об этом)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...