Есть ли встроенная функция в python, которая преобразует двоичную строку, например '111111111111', в два дополнительных целых числа -1?
Два дополнения в Python
Ответ 1
Два дополнения вычитают (1<<bits)
, если старший бит равен 1. Принимая 8 бит, например, это дает диапазон от 127 до -128.
Функция для двух дополнений к int...
def twos_comp(val, bits):
"""compute the 2 complement of int value val"""
if (val & (1 << (bits - 1))) != 0: # if sign bit is set e.g., 8bit: 128-255
val = val - (1 << bits) # compute negative value
return val # return positive value as is
Переход из двоичной строки особенно прост...
binary_string = '1111' # or whatever... no '0b' prefix
out = twos_comp(int(binary_string,2), len(binary_string))
Немного более полезный для меня идет из шестнадцатеричных значений (32 бита в этом примере)...
hex_string = '0xFFFFFFFF' # or whatever... '0x' prefix doesn't matter
out = twos_comp(int(hex_string,16), 32)
Ответ 2
Он не встроен, но если вы хотите необычные номера длин, вы можете использовать модуль bitstring.
>>> from bitstring import Bits
>>> a = Bits(bin='111111111111')
>>> a.int
-1
Один и тот же объект может быть сгенерирован несколькими способами, в том числе
>>> b = Bits(int=-1, length=12)
Он просто ведет себя как строка бит произвольной длины и использует свойства для получения разных интерпретаций:
>>> print a.int, a.uint, a.bin, a.hex, a.oct
-1 4095 111111111111 fff 7777
Ответ 3
Начиная с Python 3.2 существуют встроенные функции для манипулирования байтами: https://docs.python.org/3.4/library/stdtypes.html#int.to_bytes.
Объединив to_bytes и from_bytes, вы получите
def twos(val_str, bytes):
import sys
val = int(val_str, 2)
b = val.to_bytes(bytes, byteorder=sys.byteorder, signed=False)
return int.from_bytes(b, byteorder=sys.byteorder, signed=True)
Проверьте:
twos('11111111', 1) # gives -1
twos('01111111', 1) # gives 127
Для более старых версий Python ответ travc хорош, но он не работает для отрицательных значений, если вы хотите работать с целыми числами вместо строк. Функция дополнений двойки, для которой f (f (val)) == val истинна для каждого val:
def twos_complement(val, nbits):
"""Compute the 2 complement of int value val"""
if val < 0:
val = (1 << nbits) + val
else:
if (val & (1 << (nbits - 1))) != 0:
# If sign bit is set.
# compute negative value.
val = val - (1 << nbits)
return val
Ответ 4
>>> bits_in_word=12
>>> int('111111111111',2)-(1<<bits_in_word)
-1
Это работает, потому что:
Два дополнения двоичного число определяется как значение полученных путем вычитания числа от большой мощности двух (в частности, от 2 ^ N для N-разрядного два дополнения). Два дополняет число, затем ведет себя как негатив оригинала число в большинстве арифметических, и оно может сосуществуют с положительными числами в естественным образом.
Ответ 5
Это даст вам два дополнения эффективно с помощью побитовой логики:
def twos_complement(value, bitWidth):
if value >= 2**bitWidth:
# This catches when someone tries to give a value that is out of range
raise ValueError("Value: {} out of range of {}-bit value.".format(value, bitWidth))
else:
return value - int((value << 1) & 2**bitWidth)
Как это работает:
Во-первых, мы удостоверились, что пользователь передал нам значение, находящееся в пределах диапазона поставляемого диапазона бит (например, кто-то дает нам 0xFFFF и указывает 8 бит). Другим решением этой проблемы было бы побитовое И (& ) значение с (2 ** битWidth) -1
Чтобы получить результат, значение сдвигается на 1 бит влево. Это перемещает MSB значения (знаковый бит) в положение, которое должно быть указано с помощью 2**bitWidth
. Когда знаковый бит равен "0", вычитание становится равным 0, а результат - value - 0
. Когда знаковый бит равен "1", вычитание становится 2**bitWidth
, а результат value - 2**bitWidth
Пример 1: Если параметры имеют value = 0xFF (255d, b11111111) и bitWidth = 8
- 0xFF - int ((0xFF < 1) и 2 ** 8)
- 0xFF - int ((0x1FE) и 0x100)
- 0xFF - int (0x100)
- 255 - 256
- 1
Пример 2: Если параметры имеют value = 0x1F (31d, b11111) и bitWidth = 6
- 0x1F - int ((0x1F < 1) и 2 ** 6)
- 0x1F - int ((0x3E) и 0x40)
- 0x1F - int (0x00)
- 31 - 0
- 31
Пример 3: value = 0x80, битWidth = 7
ValueError: Value: 128 out of range of 7-bit value.
Пример 4: value = 0x80, битWitdh = 8
- 0x80 - int ((0x80 < 1) и 2 ** 8)
- 0x80 - int ((0x100) и 0x100)
- 0x80 - int (0x100)
- 128 - 256
- -128
Теперь, используя то, что еще уже опубликовано, передайте свою bitstring в int (bitstring, 2) и перейдите к параметру значения метода twos_complement.
Ответ 6
Несколько реализаций (просто иллюстрация, не предназначенная для использования):
def to_int(bin):
x = int(bin, 2)
if bin[0] == '1': # "sign bit", big-endian
x -= 2**len(bin)
return x
def to_int(bin): # from definition
n = 0
for i, b in enumerate(reversed(bin)):
if b == '1':
if i != (len(bin)-1):
n += 2**i
else: # MSB
n -= 2**i
return n
Ответ 7
если кто-то нуждается в обратном направлении:
def num_to_bin(num, wordsize):
if num < 0:
num = 2**wordsize+num
base = bin(num)[2:]
padding_size = wordsize - len(base)
return '0' * padding_size + base
for i in range(7, -9, -1):
print num_to_bin(i, 4)
должен выводить это: 0111 0110 0101 0100 0011 0010 0001 0000 1111 1110 1101 1100 1011 1010 1001 1000
Ответ 8
Нет, нет встроенной функции, которая преобразует два дополнения двоичных строк в десятичные числа.
Простая пользовательская функция, которая делает это:
def two2dec(s):
if s[0] == '1':
return -1 * (int(''.join('1' if x == '0' else '0' for x in s), 2) + 1)
else:
return int(s, 2)
Обратите внимание, что эта функция не принимает ширину бита как параметр, вместо этого положительные входные значения должны указываться одним или несколькими ведущими нулевыми битами.
Примеры:
In [2]: two2dec('1111')
Out[2]: -1
In [3]: two2dec('111111111111')
Out[3]: -1
In [4]: two2dec('0101')
Out[4]: 5
In [5]: two2dec('10000000')
Out[5]: -128
In [6]: two2dec('11111110')
Out[6]: -2
In [7]: two2dec('01111111')
Out[7]: 127
Ответ 9
Так как erikb85 поднял производительность, travc answer против Скотт Гриффитс:
In [534]: a = [0b111111111111, 0b100000000000, 0b1, 0] * 1000
In [535]: %timeit [twos_comp(x, 12) for x in a]
100 loops, best of 3: 8.8 ms per loop
In [536]: %timeit [bitstring.Bits(uint=x, length=12).int for x in a]
10 loops, best of 3: 55.9 ms per loop
Итак, bitstring
есть, как указано в другом вопросе, почти на порядок медленнее, чем int
. Но, с другой стороны, трудно просто побить простоту - я преобразую a uint
в битовую строку, а затем в int
; вам придется много работать, чтобы не понимать этого, или найти где-нибудь, чтобы ввести ошибку. И, как следует из ответа Скотта Гриффитса, в классе гораздо больше гибкости, которая может оказаться полезной для одного и того же приложения. Но с другой стороны, ответ travc дает понять, что на самом деле происходит - даже новичок должен уметь понять, какое преобразование из unsigned int в 2s-дополнение, подписанное int, означает только чтение двух строк кода.
Во всяком случае, в отличие от другого вопроса, касающегося непосредственного манипулирования битами, все это касается выполнения арифметики на int-int с фиксированной длиной, только с определенными размерами. Поэтому я предполагаю, что если вам нужна производительность, возможно, потому, что у вас есть целая куча этих вещей, поэтому вы, вероятно, хотите, чтобы она была векторизованной. Адаптация ответа travc на numpy:
def twos_comp_np(vals, bits):
"""compute the 2 compliment of array of int values vals"""
vals[vals & (1<<(bits-1)) != 0] -= (1<<bits)
return vals
Сейчас:
In [543]: a = np.array(a)
In [544]: %timeit twos_comp_np(a.copy(), 12)
10000 loops, best of 3: 63.5 µs per loop
Возможно, вы могли бы побить это с помощью специального кода на C, но вам, вероятно, не нужно.
Ответ 10
Я использую Python 3.4.0
В Python 3 у нас есть некоторые проблемы с преобразованием типов данных.
Итак... здесь я расскажу совет для тех (как я), которые много работают с шестнадцатеричными строками.
Я возьму шестнадцатеричные данные и сделаю их дополнением:
a = b'acad0109'
compl = int(a,16)-pow(2,32)
result=hex(compl)
print(result)
print(int(result,16))
print(bin(int(result,16)))
result = -1397948151 или -0x5352fef7 или '-0b1010011010100101111111011110111'
Ответ 11
К сожалению, нет встроенной функции, чтобы отличить целое число без знака к значению с двумя дополнениями, но мы можем определить функцию для этого, используя побитовые операции:
def s12(value):
return -(value & 0b100000000000) | (value & 0b011111111111)
Первая побитовая операция и операция используется для увеличения числа отрицательных чисел (самый старший бит установлен), а второй используется для захвата оставшихся 11 бит. Это работает, поскольку целые числа в Python рассматриваются как произвольная точность двух значений дополнения.
Затем вы можете объединить это с помощью функции int
, чтобы преобразовать строку двоичных цифр в целочисленную форму без знака, а затем интерпретировать ее как 12-разрядное значение со знаком.
>>> s12(int('111111111111', 2))
-1
>>> s12(int('011111111111', 2))
2047
>>> s12(int('100000000000', 2))
-2048
Одним из приятных свойств этой функции является то, что она идемпотентна, поэтому значение уже подписанного значения не изменится.
>>> s12(-1)
-1
Ответ 12
Это работает на 3 байта. Живой код здесь
def twos_compliment(byte_arr):
a = byte_arr[0]; b = byte_arr[1]; c = byte_arr[2]
out = ((a<<16)&0xff0000) | ((b<<8)&0xff00) | (c&0xff)
neg = (a & (1<<7) != 0) # first bit of a is the "signed bit." if it a 1, then the value is negative
if neg: out -= (1 << 24)
print(hex(a), hex(b), hex(c), neg, out)
return out
twos_compliment([0x00, 0x00, 0x01])
>>> 1
twos_compliment([0xff,0xff,0xff])
>>> -1
twos_compliment([0b00010010, 0b11010110, 0b10000111])
>>> 1234567
twos_compliment([0b11101101, 0b00101001, 0b01111001])
>>> -1234567
twos_compliment([0b01110100, 0b11001011, 0b10110001])
>>> 7654321
twos_compliment([0b10001011, 0b00110100, 0b01001111])
>>> -7654321
Ответ 13
Хорошо, у меня была эта проблема с алгоритмом сжатия uLaw с типом файла WAV для PCM. И то, что я узнал, состоит в том, что два дополнения являются своего рода отрицательным значением некоторого двоичного числа, как можно увидеть здесь. И после консультации с wikipedia я счел это правдой.
Парень объяснил это тем, что нашел least significant bit
и перевернул все после него. Должен сказать, что все эти решения, приведенные выше, не очень помогли мне. Когда я попытался на 0x67ff
он дал мне некоторый результат вместо -26623
. Теперь решения, возможно, сработали, если кто-то знал, что least significant bit
сканирует список данных, но я не знал, так как данные в PCM варьируются. Итак, вот мой ответ:
max_data = b'\xff\x67' #maximum value i've got from uLaw data chunk to test
def twos_compliment(short_byte): # 2 bytes
short_byte = signedShort(short_byte) # converting binary string to integer from struct.unpack i've just shortened it.
valid_nibble = min([ x*4 for x in range(4) if (short_byte>>(x*4))&0xf ])
bit_shift = valid_nibble + min( [ x for x in [1,2,4,8] if ( ( short_byte>>valid_nibble )&0xf )&x ] )
return (~short_byte)^( 2**bit_shift-1 )
data = 0x67ff
bit4 = '{0:04b}'.format
bit16 = lambda x: ' '.join( map( bit4, reversed([ x&0xf, (x>>4)&0xf, (x>>8)&0xf, (x>>12)&0xf ]) ) )
# print( bit16(0x67ff) , ' : ', bit16( twos_compliment( b'\xff\x67' ) ) )
# print( bit16(0x67f0) , ' : ', bit16( twos_compliment( b'\xf0\x67' ) ) )
# print( bit16(0x6700) , ' : ', bit16( twos_compliment( b'\x00\x67' ) ) )
# print( bit16(0x6000) , ' : ', bit16( twos_compliment( b'\x00\x60' ) ) )
print( data, twos_compliment(max_data) )
Теперь, так как код не читается, я пройду через эту идею.
## example data, for testing... in general unknown
data = 0x67ff # 26623 or 0110 0111 1111 1111
Это всего лишь шестнадцатеричное значение, мне нужен тест, чтобы быть уверенным, но в целом это может быть что угодно в диапазоне от int. Поэтому, чтобы не перебирать целую цепочку из 65535 значений short integer
, я мог бы разделить ее на nibbles (4 бит). Это можно сделать так, если вы раньше не использовали bitwise operators
.
nibble_mask = 0xf # 1111
valid_nibble = []
for x in range(4): #0,1,2,3 aka places of bit value
# for individual bits you could go 1<<x as you will see later
# x*4 is because we are shifting bit places , so 0xFA>>4 = 0xF
# so 0x67ff>>0*4 = 0x67ff
# so 0x67ff>>1*4 = 0x67f
# so 0x67ff>>2*4 = 0x67
# so 0x67ff>>3*4 = 0x6
# and nibble mask just makes it confided to 1 nibble so 0xFA&0xF=0xA
if (data>>(x*4))&nibble_mask: valid_nibble.append(x*4) # to avoid multiplying it with 4 later
Таким образом, мы ищем least significant bit
поэтому здесь будет достаточно min(valid_nibble )
. Здесь мы получили место, где первый активный (с установленным битом) полубайт. Теперь нам просто нужно найти, где в желаемом грызке находится наш первый установленный бит.
bit_shift = min(valid_nibble)
for x in range(4):
# in my example above [1,2,4,8] i did this to spare python calculating
ver_data = data>>min(bit_shift ) # shifting from 0xFABA to lets say 0xFA
ver_data &= nibble_mask # from 0xFA to 0xA
if ver_data&(1<<x):
bit_shift += (1<<x)
break
Теперь мне нужно прояснить что-то, потому что, видя ~
и ^
могут путать людей, которые не привыкли к этому:
XOR
: ^
: 2 номера требуются
Эта операция нелогична, для каждого 2 бита она сканирует, если оба они равны 1 или 0, это будет 0, для всего остального 1.
0b10110
^0b11100
---------
0b01010
И еще один пример:
0b10110
^0b11111
---------
0b01001
1 complement
: ~
- не требуется никакого другого номера
Эта операция переворачивает каждый бит в число. Он очень похож на то, что мы делаем, но он не оставляет наименее значимого бита.
0b10110
~
0b01001
И, как мы видим здесь, 1 комплимент такой же, как и полный набор бит XOR.
Теперь, когда мы поняли друг друга, мы получим two complement
, восстановив все укусы до наименее значимого бита в одном дополнении.
data = ~data # one complement of data
Это, к сожалению, перевернуло все биты в нашем номере, поэтому нам просто нужно найти способ перевернуть числа, которые мы хотим. Мы можем сделать это с помощью bit_shift
так как это битная позиция нашего бита, которую нам нужно сохранить. Поэтому при вычислении количества данных может быть выполнено некоторое количество бит, мы можем сделать это с помощью 2**n
а для nibble получаем 16, так как мы вычисляем 0 в битах.
2**4 = 16 # in binary 1 0000
Но нам нужны байты после 1
поэтому мы можем использовать это, чтобы уменьшить значение на 1, и мы можем получить.
2**4 -1 = 15 # in binary 0 1111
Итак, рассмотрим логику в конкретном примере:
0b110110
lsb = 2 # binary 10
~0b110110
----------
0b001001 # here is that 01 we don't like
0b001001
^0b000011 # 2**2 = 4 ; 4-1 = 3 in binary 0b11
---------
0b001010
Надеюсь, это поможет поможет вам или новичкам, которые столкнулись с этой проблемой, и исследовали их решение найти решение. Имейте в виду, что этот код, который я написал, - это код франкенштейна, и поэтому я должен был объяснить это. Это можно сделать более красивым, если кто-то хочет сделать мой код симпатичным, пожалуйста, будь моим гостем.
Ответ 14
Здесь версия для преобразования каждого значения в шестнадцатеричной строке в него два дополнения версии.
In [5159]: twoscomplement('f0079debdd9abe0fdb8adca9dbc89a807b707f')
Out[5159]: '10097325337652013586346735487680959091'
def twoscomplement(hm):
twoscomplement=''
for x in range(0,len(hm)):
value = int(hm[x],16)
if value % 2 == 1:
twoscomplement+=hex(value ^ 14)[2:]
else:
twoscomplement+=hex(((value-1)^15)&0xf)[2:]
return twoscomplement
Ответ 15
Это намного проще, чем все это...
для X на N бит: Comp = (-X) и (2 ** N - 1)
def twoComplement(number, nBits):
return (-number) & (2**nBits - 1)