Я должен преобразовать данное целое число на 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
Я бы сделал
c = (x >> 8) & 0xff
f = x & 0xff
Это безопаснее, см. например,
>>> (10303 >> 8) & 0xff
40
>>> (1030333333 >> 8) & 0xff
163
>>> (1030333333 >> 8)
4024739
Поскольку в python вы не можете контролировать, является ли число 16-битным или нет, вы должны принудительно преобразовать его в значение не более 16 бит. Это не нужно, если вы уверены, что у вас будет 16-битное значение, но таким образом функция становится более общей и позволяет вам интересоваться только 16-битными значениями, независимо от того, что содержит контейнер.
В Python использование битов не имеет особых преимуществ, поэтому я бы выбрал:
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
Вы говорите, что используете эти числа как выходные данные, что предполагает, что они будут преобразованы в строки в какой-то момент по строке. Имея это в виду, я предлагаю вам взглянуть на модуль 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)
Я бы использовал побитовое &, а не%. Вероятно, в наши дни это мало что меняет для коротких целых чисел, но в более широком смысле оператор & потенциально более эффективен.
Может возникнуть некоторая проблема с тем, как% обрабатывает отрицательные числа, но я сомневаюсь, что это актуально здесь.
Если вы используете две половины числа в разных местах, я бы рекомендовал иметь две отдельные функции, но если вы собираетесь использовать их в одном месте, одна функция будет работать точно так же.
Есть несколько правильных способов разделить число, так что в конечном итоге все сводится к личным предпочтениям. Ваш код будет работать нормально, если вы передадите только числа длиной не более 16 бит. (что, вероятно, не будет большой проблемой, но вы должны знать об этом)
Вы должны быть последовательны, если цель операций арифметическая, используйте по модулю и делению, если это просто для обработки необработанных битов, используйте сдвиг и маску.