def twos_comp(val, bits):
"""compute the 2's 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)
Two's complement subtracts off (1<<bits) if the highest bit is 1. Taking 8 bits for example, this gives a range of 127 to -128.
A function for two's complement of an int...
def twos_comp(val, bits):
"""compute the 2's 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
Going from a binary string is particularly easy...
binary_string = '1111' # or whatever... no '0b' prefix
out = twos_comp(int(binary_string,2), len(binary_string))
A bit more useful to me is going from hex values (32 bits in this example)...
hex_string = '0xFFFFFFFF' # or whatever... '0x' prefix doesn't matter
out = twos_comp(int(hex_string,16), 32)
For old versions of Python, travc's answer is good,但如果想使用整数而不是字符串,则它不适用于负值。对于每个 val,f(f(val)) == val 为 true 的二进制补码函数是:
def twos_complement(val, nbits):
"""Compute the 2's 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
For older versions of Python, travc's answer is good but it does not work for negative values if one would like to work with integers instead of strings. A twos' complement function for which f(f(val)) == val is true for each val is:
def twos_complement(val, nbits):
"""Compute the 2's 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
The two's complement of a binary
number is defined as the value
obtained by subtracting the number
from a large power of two
(specifically, from 2^N for an N-bit
two's complement). The two's
complement of the number then behaves
like the negative of the original
number in most arithmetic, and it can
coexist with positive numbers in a
natural way.
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))
return value - int((value << 1) & 2**bitWidth)
ValueError: Value: 128 out of range of 7-bit value.
示例 4:value = 0x80,bitWitdh = 8
0x80 - int((0x80 << 1) & 2**8)
0x80 - int((0x100) & 0x100)
0x80 - int(0x100)
128 - 256
-128
现在,使用其他人已经发布的内容,通过将您的位字符串转换为 int(bitstring, 2) 并传递给 twos_complement 方法的 value 参数。
This will give you the two's complement efficiently using bitwise logic:
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))
return value - int((value << 1) & 2**bitWidth)
How it works:
First, we make sure that the user has passed us a value that is within the range of the supplied bit range (e.g. someone gives us 0xFFFF and specifies 8 bits) Another solution to that problem would be to bitwise AND (&) the value with (2**bitWidth)-1
To get the result, the value is shifted by 1 bit to the left. This moves the MSB of the value (the sign bit) into position to be anded with 2**bitWidth. When the sign bit is '0' the subtrahend becomes 0 and the result is value - 0. When the sign bit is '1' the subtrahend becomes 2**bitWidth and the result is value - 2**bitWidth
Example 1: If the parameters are value=0xFF (255d, b11111111) and bitWidth=8
0xFF - int((0xFF << 1) & 2**8)
0xFF - int((0x1FE) & 0x100)
0xFF - int(0x100)
255 - 256
-1
Example 2: If the parameters are value=0x1F (31d, b11111) and bitWidth=6
0x1F - int((0x1F << 1) & 2**6)
0x1F - int((0x3E) & 0x40)
0x1F - int(0x00)
31 - 0
31
Example 3: value = 0x80, bitWidth = 7
ValueError: Value: 128 out of range of 7-bit value.
Example 4: value = 0x80, bitWitdh = 8
0x80 - int((0x80 << 1) & 2**8)
0x80 - int((0x100) & 0x100)
0x80 - int(0x100)
128 - 256
-128
Now, using what others have already posted, pass your bitstring into int(bitstring, 2) and pass to the twos_complement method's value parameter.
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
A couple of implementations (just an illustration, not intended for use):
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
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)
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)
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
No, there is no builtin function that converts two's complement binary strings into decimals.
A simple user defined function that does this:
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)
Note that this function doesn't take the bit width as parameter, instead positive input values have to be specified with one or more leading zero bits.
Examples:
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
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 慢一个数量级。但另一方面,它也很简单——我将 uint 转换为位字符串,然后转换为 int;你必须努力不才能理解这一点,或者找到任何引入错误的地方。正如 Scott Griffiths 的回答所暗示的那样,该类有更多的灵活性,这可能对同一个应用程序有用。但第三方面,travc 的答案清楚地表明了实际发生的情况 - 即使是新手也应该能够仅通过阅读 2 行代码就能够理解从无符号 int 到 2s 补码有符号 int 的转换意味着什么。
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
So, bitstring is, as found in the other question, almost an order of magnitude slower than int. But on the other hand, it's hard to beat the simplicity—I'm converting a uint to a bit-string then to an int; you'd have to work hard not to understand this, or to find anywhere to introduce a bug. And as Scott Griffiths' answer implies, there's a lot more flexibility to the class which might be useful to the same app. But on the third hand, travc's answer makes it clear what's actually happening—even a novice should be able to understand what conversion from an unsigned int to a 2s complement signed int means just from reading 2 lines of code.
Anyway, unlike the other question, which was about directly manipulating bits, this one is all about doing arithmetic on fixed-length ints, just oddly-sized ones. So I'm guessing if you need performance, it's probably because you have a whole bunch of these things, so you probably want it to be vectorized. Adapting travc's answer to numpy:
def twos_comp_np(vals, bits):
"""compute the 2's compliment of array of int values vals"""
vals[vals & (1<<(bits-1)) != 0] -= (1<<bits)
return vals
Now:
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
You could probably beat that with custom C code, but you probably don't have to.
Unfortunately there is no built-in function to cast an unsigned integer to a two's complement signed value, but we can define a function to do so using bitwise operations:
The first bitwise-and operation is used to sign-extend negative numbers (most significant bit is set), while the second is used to grab the remaining 11 bits. This works since integers in Python are treated as arbitrary precision two's complement values.
You can then combine this with the int function to convert a string of binary digits into the unsigned integer form, then interpret it as a 12-bit signed value.
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
Here's a version to convert each value in a hex string to it's two's complement version.
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
def twos_comp(val, bits=16):
"""compute the 2's complement of int value """
if bits == 0: # Use as many bits needed for the value.
bits = val.bit_length()
return ((val & (2 ** bits) - 1) - (2 ** bits)) * -1
测试代码:
value = 6752
print(f'{value:05d} = 0x{value:04x} = 0b{value:016b}')
value = twos_comp(value)
print(f'{value:05d} = 0x{value:04x} = 0b{value:016b}')
value = twos_comp(value)
print(f'{value:05d} = 0x{value:04x} = 0b{value:016b}')
Still a very relevant question, but none of the answers worked in my scenario - which is surprising.
Here's a very simple function to calculate n-bit 2's complement integer values from an integer value.
This function especially ensures that the returned value is NOT seen as a negative value by python, as it breaks the very nature of 2's complement numbers.
2's complement numbers were originally created to work with both positive and negative values on architectures that do not natively support them. It's a conversion and is all about using the bits available to represent and calculate with both positive and negative numbers.
Therefore the number of bits can be specified, defaults to 16, and can by setting it to 0, be set to the required number of bits for the given value.
def twos_comp(val, bits=16):
"""compute the 2's complement of int value """
if bits == 0: # Use as many bits needed for the value.
bits = val.bit_length()
return ((val & (2 ** bits) - 1) - (2 ** bits)) * -1
Test code:
value = 6752
print(f'{value:05d} = 0x{value:04x} = 0b{value:016b}')
value = twos_comp(value)
print(f'{value:05d} = 0x{value:04x} = 0b{value:016b}')
value = twos_comp(value)
print(f'{value:05d} = 0x{value:04x} = 0b{value:016b}')
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's 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
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's 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
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 值短整数,我可以决定将其分割为 半字节(4 位)。如果您没有使用过按位运算符 之前。
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
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
Ok i had this issue with uLaw compression algorithm with PCM wav file type. And what i've found out is that two's complement is kinda making a negative value of some binary number as can be seen here.And after consulting with wikipedia i deemed it true.
The guy explained it as finding least significant bit and flipping all after it. I must say that all these solutions above didn't help me much. When i tried on 0x67ff it gave me some off result instead of -26623. Now solutions may have worked if someone knew the least significant bit is scanning list of data but i didn't knew since data in PCM varies. So here is my answer:
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) )
Now since code is unreadable i will walk you through the idea.
## example data, for testing... in general unknown
data = 0x67ff # 26623 or 0110 0111 1111 1111
This is just any hexadecimal value, i needed test to be sure but in general it could be anything in range of int. So not to loop over whole bunch of 65535 values short integer can have i decided to split it by nibbles ( 4 bits ). It could be done like this if you haven't used bitwise operators before.
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
So we are searching for least significant bit so here the min(valid_nibble ) will suffice. Here we've gotten the place where first active (with setted bit) nibble is. Now we just need is to find where in desired nibble is our first setted bit.
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
Now here i need to clarify somethings since seeing ~ and ^ can confuse people who aren't used to this:
This operation flips every bit in a number. It is very similar to what we are after but it doesn't leave the least significant bit.
0b10110
~
0b01001
And as we can see here 1's compliment is same as number XOR full set bits.
Now that we've understood each other, we will getting two's complement by restoring all bites to least significant bit in one's complement.
data = ~data # one's complement of data
This unfortunately flipped all bits in our number, so we just need to find a way to flip back the numbers we want. We can do that with bit_shift since it is bit position of our bit we need to keep. So when calculating number of data some number of bits can hold we can do that with 2**n and for nibble we get 16 since we are calculating 0 in values of bits.
2**4 = 16 # in binary 1 0000
But we need the bytes after the 1 so we can use that to diminish the value by 1 and we can get.
2**4 -1 = 15 # in binary 0 1111
So lets see the logic in concrete example:
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
I hope this help'd you or any newbie that had this same problem and researched their a** off finding the solution. Have in mind this code i wrote is frankenstein code , that i why i had to explain it. It could be done more prettier, if anyone wants to make my code pretty please be my guest.
发布评论
评论(20)
如果最高位为 1,则二进制补码减去
(1<。以 8 位为例,这给出了 127 到 -128 的范围。
一个对 int 进行补码的函数...
从二进制字符串获取特别简单...
对我来说更有用的是从十六进制值(本例中为 32 位)...
Two's complement subtracts off
(1<<bits)
if the highest bit is 1. Taking 8 bits for example, this gives a range of 127 to -128.A function for two's complement of an int...
Going from a binary string is particularly easy...
A bit more useful to me is going from hex values (32 bits in this example)...
从Python 3.2开始,有用于字节操作的内置函数: https:// /docs.python.org/3/library/stdtypes.html#int.to_bytes。
通过组合 to_bytes 和 from_bytes,您可以得到
Check:
For old versions of Python, travc's answer is good,但如果想使用整数而不是字符串,则它不适用于负值。对于每个 val,f(f(val)) == val 为 true 的二进制补码函数是:
Since Python 3.2, there are built-in functions for byte manipulation: https://docs.python.org/3/library/stdtypes.html#int.to_bytes.
By combining to_bytes and from_bytes, you get
Check:
For older versions of Python, travc's answer is good but it does not work for negative values if one would like to work with integers instead of strings. A twos' complement function for which f(f(val)) == val is true for each val is:
它不是内置的,但如果您想要不寻常的长度数字,那么您可以使用 bitstring 模块。
同样的对象可以通过多种方式创建,包括
它只是表现得像一串任意长度的位,并使用属性来获得不同的解释:
It's not built in, but if you want unusual length numbers then you could use the bitstring module.
The same object can equivalently be created in several ways, including
It just behaves like a string of bits of arbitrary length, and uses properties to get different interpretations:
这是有效的,因为:
This works because:
这将使用按位逻辑有效地为您提供二进制补码:
工作原理:
首先,我们确保用户向我们传递的值在所提供的位范围内(例如,有人给我们 0xFFFF 并指定 8 位)该问题的另一个解决方案是将值与 (2**bitWidth)-1 按位与 (&)
要获得结果,该值将向左移动 1 位。这会将值的 MSB(符号位)移动到要与
2**bitWidth
进行“与”的位置。当符号位为“0”时,减数变为 0,结果为值 - 0
。当符号位为“1”时,减数变为2**bitWidth
,结果为value - 2**bitWidth
示例 1:如果参数 value=0xFF ( 255d, b11111111) 和 bitWidth=8
示例2:如果参数 value=0x1F (31d, b11111) 且 bitWidth=6
示例 3:value = 0x80,bitWidth = 7
ValueError: Value: 128 out of range of 7-bit value.
示例 4:value = 0x80,bitWitdh = 8
现在,使用其他人已经发布的内容,通过将您的位字符串转换为
int(bitstring, 2)
并传递给twos_complement
方法的 value 参数。This will give you the two's complement efficiently using bitwise logic:
How it works:
First, we make sure that the user has passed us a value that is within the range of the supplied bit range (e.g. someone gives us 0xFFFF and specifies 8 bits) Another solution to that problem would be to bitwise AND (&) the value with (2**bitWidth)-1
To get the result, the value is shifted by 1 bit to the left. This moves the MSB of the value (the sign bit) into position to be anded with
2**bitWidth
. When the sign bit is '0' the subtrahend becomes 0 and the result isvalue - 0
. When the sign bit is '1' the subtrahend becomes2**bitWidth
and the result isvalue - 2**bitWidth
Example 1: If the parameters are value=0xFF (255d, b11111111) and bitWidth=8
Example 2: If the parameters are value=0x1F (31d, b11111) and bitWidth=6
Example 3: value = 0x80, bitWidth = 7
ValueError: Value: 128 out of range of 7-bit value.
Example 4: value = 0x80, bitWitdh = 8
Now, using what others have already posted, pass your bitstring into
int(bitstring, 2)
and pass to thetwos_complement
method's value parameter.几个实现(仅作为说明,不用于使用):
A couple of implementations (just an illustration, not intended for use):
您可以使用 bit_length() 函数将数字转换为其二进制补码:
You can use the bit_length() function to convert numbers to their two's complement:
如果有人也需要相反的方向:
应该输出这个:
0111
0110
0101
0100
0011
0010
0001
0000
1111
1110
1101
1100
1011
1010
1001
1000
in case someone needs the inverse direction too:
should output this:
0111
0110
0101
0100
0011
0010
0001
0000
1111
1110
1101
1100
1011
1010
1001
1000
您可以将整数转换为字节,然后使用
struct.unpack
转换:you could convert the integer to bytes and then use
struct.unpack
to convert:不,没有内置函数可以将二进制补码二进制字符串转换为十进制。
一个简单的用户定义函数可以执行此操作:
请注意,此函数不将位宽度作为参数,而是必须使用一个或多个前导零位来指定正输入值。
示例:
No, there is no builtin function that converts two's complement binary strings into decimals.
A simple user defined function that does this:
Note that this function doesn't take the bit width as parameter, instead positive input values have to be specified with one or more leading zero bits.
Examples:
由于 erikb85 提出了性能问题,这里是 travc 的回答针对 Scott Griffiths':
所以,
bitstring
是,如 另一个问题,几乎比int
慢一个数量级。但另一方面,它也很简单——我将 uint 转换为位字符串,然后转换为 int;你必须努力不才能理解这一点,或者找到任何引入错误的地方。正如 Scott Griffiths 的回答所暗示的那样,该类有更多的灵活性,这可能对同一个应用程序有用。但第三方面,travc 的答案清楚地表明了实际发生的情况 - 即使是新手也应该能够仅通过阅读 2 行代码就能够理解从无符号 int 到 2s 补码有符号 int 的转换意味着什么。不管怎样,与另一个关于直接操作位的问题不同,这个问题是关于对固定长度的整数(只是奇怪大小的整数)进行算术运算。所以我猜如果你需要性能,可能是因为你有一大堆这样的东西,所以你可能希望它被矢量化。将 travc 的答案调整为 numpy:
现在:
您可能可以使用自定义 C 代码来击败它,但您可能不必这样做。
Since erikb85 brought up performance, here's travc's answer against Scott Griffiths':
So,
bitstring
is, as found in the other question, almost an order of magnitude slower thanint
. But on the other hand, it's hard to beat the simplicity—I'm converting auint
to a bit-string then to anint
; you'd have to work hard not to understand this, or to find anywhere to introduce a bug. And as Scott Griffiths' answer implies, there's a lot more flexibility to the class which might be useful to the same app. But on the third hand, travc's answer makes it clear what's actually happening—even a novice should be able to understand what conversion from an unsigned int to a 2s complement signed int means just from reading 2 lines of code.Anyway, unlike the other question, which was about directly manipulating bits, this one is all about doing arithmetic on fixed-length ints, just oddly-sized ones. So I'm guessing if you need performance, it's probably because you have a whole bunch of these things, so you probably want it to be vectorized. Adapting travc's answer to numpy:
Now:
You could probably beat that with custom C code, but you probably don't have to.
不幸的是,没有内置函数可以将无符号整数转换为二进制补码有符号值,但我们可以使用按位运算定义一个函数来执行此操作:
第一个按位与运算用于对负数进行符号扩展(最重要的是位被设置),而第二个用于获取剩余的 11 位。这是可行的,因为 Python 中的整数被视为任意精度的二进制补码值。
然后,您可以将其与
int
函数结合使用,将二进制数字字符串转换为无符号整数形式,然后将其解释为 12 位有符号值。该函数的一个很好的特性是它是幂等的,因此已经签名的值不会改变。
Unfortunately there is no built-in function to cast an unsigned integer to a two's complement signed value, but we can define a function to do so using bitwise operations:
The first bitwise-and operation is used to sign-extend negative numbers (most significant bit is set), while the second is used to grab the remaining 11 bits. This works since integers in Python are treated as arbitrary precision two's complement values.
You can then combine this with the
int
function to convert a string of binary digits into the unsigned integer form, then interpret it as a 12-bit signed value.One nice property of this function is that it's idempotent, thus the value of an already signed value will not change.
这是将十六进制字符串中的每个值转换为其二进制补码版本的版本。
Here's a version to convert each value in a hex string to it's two's complement version.
仍然是一个非常相关的问题,但没有一个答案在我的场景中起作用 - 这是令人惊讶的。
这是一个非常简单的函数,用于从整数值计算 n 位 2 的补码整数值。
该函数特别确保返回值不会被 python 视为负值,因为它破坏了 2 的补数的本质。
2 的补数最初是为了在本身不支持它们的架构上处理正值和负值而创建的。这是一种转换,就是使用可用的位来表示和计算正数和负数。
因此可以指定位数,默认为16,并且可以通过将其设置为0,将其设置为给定值所需的位数。
测试代码:
测试代码输出:
Still a very relevant question, but none of the answers worked in my scenario - which is surprising.
Here's a very simple function to calculate n-bit 2's complement integer values from an integer value.
This function especially ensures that the returned value is NOT seen as a negative value by python, as it breaks the very nature of 2's complement numbers.
2's complement numbers were originally created to work with both positive and negative values on architectures that do not natively support them. It's a conversion and is all about using the bits available to represent and calculate with both positive and negative numbers.
Therefore the number of bits can be specified, defaults to 16, and can by setting it to 0, be set to the required number of bits for the given value.
Test code:
Test code output:
使用
~
、^
和掩码(掩码决定总位数)Use
~
,^
, and a mask (mask determines the total number of bits)从负值中减去 2^nbits:
Subtract 2^nbits from negative values:
我正在使用 Python 3.4.0
在 Python 3 中,我们在数据类型转换方面遇到了一些问题。
所以......在这里我将告诉那些经常使用十六进制字符串的人(像我一样)的技巧。
我将获取十六进制数据并对其进行补充:
结果 = -1397948151 或 -0x5352fef7 或 '-0b1010011010100101111111011110111'
I'm using Python 3.4.0
In Python 3 we have some problems with data types transformation.
So... here I'll tell a tip for those (like me) that works a lot with hex strings.
I'll take an hex data and make an complement it:
result = -1397948151 or -0x5352fef7 or '-0b1010011010100101111111011110111'
这适用于 3 个字节。 实时代码在这里
This works for 3 bytes. Live code is here
好吧,我在使用 PCM wav 文件类型 时遇到了 uLaw 压缩算法 的问题。我发现,二进制补码有点使某些二进制数的负值 as可以在这里看到。在咨询wikipedia后,我认为这是真的。
那家伙将其解释为找到
最低有效位
并翻转其后的所有内容。我必须说上面所有这些解决方案对我没有多大帮助。当我尝试0x67ff
时,它给了我一些关闭结果,而不是-26623
。现在,如果有人知道最低有效位
正在扫描数据列表,但我不知道,因为 PCM 中的数据各不相同,那么解决方案可能会起作用。所以这是我的答案:现在由于代码不可读,我将引导您完成这个想法。
这只是任何十六进制值,我需要测试来确定,但一般来说它可以是 int 范围内的任何值。因此,不要循环遍历整个 65535 值
短整数
,我可以决定将其分割为 半字节(4 位)。如果您没有使用过按位运算符
之前。因此,我们正在搜索
最低有效位
,因此这里min(valid_nibble )
就足够了。在这里,我们得到了第一个活动(具有设置位)半字节所在的位置。现在我们只需要找到所需的半字节中的第一个设置位。现在我需要澄清一些事情,因为看到
~
和^
会让不习惯的人感到困惑:XOR
:^
: 2 个数字是必需的这个操作有点不合逻辑,对于每 2 位它扫描如果两者都是 1 或 0 则为 0,其他均为 1。
另一个示例:
1 的补码
:~
- 不需要任何其他数字此操作翻转数字中的每一位。它与我们所追求的非常相似,但它没有留下最低有效位。
正如我们在这里看到的,1 的补码与数字 XOR 完整设置位相同。
现在我们已经互相理解了,我们将通过将所有位恢复为补码中的最低有效位来获得
二进制补码
。不幸的是,这翻转了我们数字中的所有位,因此我们只需要找到一种方法来翻转我们想要的数字。我们可以使用
bit_shift
来做到这一点,因为它是我们需要保留的位的位位置。因此,在计算可以容纳的数据数量时,我们可以使用 2**n 来计算,对于半字节,我们得到 16,因为我们计算的是位值 0。但是我们需要
1
之后的字节,所以我们可以用它来将值减 1,然后我们就可以得到。因此,让我们看看具体示例中的逻辑:
我希望这对您或任何遇到同样问题并研究他们的问题以找到解决方案的新手有所帮助。请记住,我编写的这段代码是弗兰肯斯坦代码,这就是我为什么必须解释它的原因。它可以做得更漂亮,如果有人想让我的代码漂亮,请成为我的客人。
Ok i had this issue with uLaw compression algorithm with PCM wav file type. And what i've found out is that two's complement is kinda making a negative value of some binary number as can be seen here.And after consulting with wikipedia i deemed it true.
The guy explained it as finding
least significant bit
and flipping all after it. I must say that all these solutions above didn't help me much. When i tried on0x67ff
it gave me some off result instead of-26623
. Now solutions may have worked if someone knew theleast significant bit
is scanning list of data but i didn't knew since data in PCM varies. So here is my answer:Now since code is unreadable i will walk you through the idea.
This is just any hexadecimal value, i needed test to be sure but in general it could be anything in range of int. So not to loop over whole bunch of 65535 values
short integer
can have i decided to split it by nibbles ( 4 bits ). It could be done like this if you haven't usedbitwise operators
before.So we are searching for
least significant bit
so here themin(valid_nibble )
will suffice. Here we've gotten the place where first active (with setted bit) nibble is. Now we just need is to find where in desired nibble is our first setted bit.Now here i need to clarify somethings since seeing
~
and^
can confuse people who aren't used to this:XOR
:^
: 2 numbers are neceseryThis operation is kinda illogical, for each 2 bits it scans if both are either 1 or 0 it will be 0, for everything else 1.
And another example:
1's complement
:~
- doesn't need any other numberThis operation flips every bit in a number. It is very similar to what we are after but it doesn't leave the least significant bit.
And as we can see here 1's compliment is same as number XOR full set bits.
Now that we've understood each other, we will getting
two's complement
by restoring all bites to least significant bit in one's complement.This unfortunately flipped all bits in our number, so we just need to find a way to flip back the numbers we want. We can do that with
bit_shift
since it is bit position of our bit we need to keep. So when calculating number of data some number of bits can hold we can do that with2**n
and for nibble we get 16 since we are calculating 0 in values of bits.But we need the bytes after the
1
so we can use that to diminish the value by 1 and we can get.So lets see the logic in concrete example:
I hope this help'd you or any newbie that had this same problem and researched their a** off finding the solution. Have in mind this code i wrote is frankenstein code , that i why i had to explain it. It could be done more prettier, if anyone wants to make my code pretty please be my guest.
这比这一切要容易得多
对于 N 位上的 X, :
比较 = (-X) & (2**N - 1)
It's much easier than all that...
for X on N bits:
Comp = (-X) & (2**N - 1)