好吧我用 uLaw compression algorithm 与PCM wav文件类型有这个问题 . 而且_____8129的补充有点像某个二进制数as can be seen here的负值 . 在咨询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 可以让我决定用半字节(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
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)
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
8
几个实现(只是一个插图,不打算使用):
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 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)
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 ,如the other question中所见,几乎比 int 慢一个数量级 . 但另一方面,'s hard to beat the simplicity—I'm将 uint 转换为位串然后转换为 int ;你必须努力工作,不要理解这一点,或找到任何可以引入错误的地方 . 而作为Scott Griffiths ' answer implies, there'的课程更灵活,可能对同一个应用程序有用 . 但是第三方面,travc 's answer makes it clear what'实际上正在发生 - 即使是新手也应该能够理解从unsigned int到2s补码signed int的转换意味着只读取2行代码 .
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
现在:
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代码击败它,但您可能不必这样做 .
0
如果有人需要反方向:
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
1
我正在使用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)))
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
14 回答
好吧我用 uLaw compression algorithm 与PCM wav文件类型有这个问题 . 而且_____8129的补充有点像某个二进制数as can be seen here的负值 . 在咨询wikipedia后我认为是真的 .
那家伙解释说它找到了
least significant bit
然后翻了一遍 . 我必须说上面所有这些解决方案对我没什么帮助 . 当我试着0x67ff
时,它给了我一些结果而不是-26623
. 现在解决方案可能有用,如果有人知道least significant bit
正在扫描数据列表但我不知道,因为PCM中的数据不同 . 所以这是我的答案:现在,由于代码不可读,我将引导您完成这个想法 .
这只是任何十六进制值,我需要测试以确定,但一般来说它可能是 int 范围内的任何东西 . 所以不要循环遍及整个 65535 值
short integer
可以让我决定用半字节(4位)分割它 . 如果您之前没有使用bitwise operators,可以这样做 .所以我们正在搜索
least significant bit
所以min(valid_nibble )
就足够了 . 在这里,我们得到了第一个活动(使用设置位)半字节的位置 . 现在我们只需要找到所需的半字节是我们的第一个设置位 .现在我需要澄清一些事情,因为看到
~
和^
可能会混淆不习惯的人:XOR:
^
:2个数字是necesery这个操作有点不合逻辑,如果它们都是1或0,它扫描的每2位,对于其他1,它将为0 .
另一个例子:
1's complement:
~
- 不需要任何其他号码此操作翻转一个数字中的每一位 . 它与我们所追求的非常相似,但它并没有留下最不重要的一点 .
正如我们在这里看到的,1的恭维与数字XOR全集位相同 .
现在我们已经相互理解了,我们将通过将所有咬合恢复到一个补码中的最低位来获得
two's complement
.不幸的是,我们的数字中的所有位都被翻转了,所以我们只需要找到一种方法来翻转我们想要的数字 . 我们可以用
bit_shift
做到这一点,因为它是我们需要保留的位的位置 . 因此,当计算数据的数量时,一些位可以保持,我们可以用2**n
来做,而对于半字节,我们得到16,因为我们在位的值中计算0 .但是我们需要在
1
之后的字节,所以我们可以使用它来减少1的值,我们可以得到 .所以让我们看看具体例子中的逻辑:
我希望这对你或任何有同样问题的新手有所帮助,并研究他们找到解决方案 . 请记住,我写的代码是frankenstein代码,我为什么要解释它 . 它可以做得更漂亮,如果有人想让我的代码漂亮,请成为我的客人 .
它比所有这些都容易得多......
对于N位的X:Comp =( - X)&(2 ** N - 1)
如果最高位为1,则二进制补码减去
(1<<bits)
. 例如,以8位为例,这给出了127到-128的范围 .两个补码的函数...
从二进制字符串开始特别容易......
对我来说更有用的是从十六进制值(本例中为32位)...
它不是内置的,但是如果你想要不寻常的长度数字,那么你可以使用bitstring模块 .
可以通过多种方式等效地创建相同的对象,包括
它就像一串任意长度的字符串,并使用属性来获得不同的解释:
这是因为:
从Python 3.2开始,有用于字节操作的内置函数:https://docs.python.org/3.4/library/stdtypes.html#int.to_bytes .
通过组合to_bytes和from_bytes,你得到了
校验:
对于旧版本的Python,travc的答案很好但如果想要使用整数而不是字符串,它对负值不起作用 . 对于每个val,f(f(val))== val为真的二进制补码函数是:
几个实现(只是一个插图,不打算使用):
这将使用按位逻辑有效地为您提供两个补码:
这个怎么运作:
首先,我们确保用户已经向我们传递了一个在提供的位范围内的值(例如某人给我们0xFFFF并指定8位)该问题的另一个解决方案是按位AND(&)值(2 **位宽)-1-
为了得到结果,该值向左移1位 . 这会将值的MSB(符号位)移动到
2**bitWidth
的位置 . 当符号位为'0'时,减数变为0,结果为value - 0
. 当符号位为'1'时,减数变为2**bitWidth
,结果为value - 2**bitWidth
示例1:如果参数是值= 0xFF(255d,b11111111)和bitWidth = 8
0xFF - int((0xFF << 1)&2 ** 8)
0xFF - int((0x1FE)&0x100)
0xFF - int(0x100)
255 - 256
-1
示例2:如果参数是值= 0x1F(31d,b11111)和bitWidth = 6
0x1F - int((0x1F << 1)&2 ** 6)
0x1F - int((0x3E)&0x40)
0x1F - int(0x00)
31 - 0
31
例3:value = 0x80,bitWidth = 7
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
现在,使用其他人已发布的内容,将您的bitstring传递给int(bitstring,2)并传递给twos_complement方法的value参数 .
由于erikb85带来了性能,这里的travc's answer对抗Scott Griffiths':
因此,
bitstring
,如the other question中所见,几乎比int
慢一个数量级 . 但另一方面,'s hard to beat the simplicity—I'm将uint
转换为位串然后转换为int
;你必须努力工作,不要理解这一点,或找到任何可以引入错误的地方 . 而作为Scott Griffiths ' answer implies, there'的课程更灵活,可能对同一个应用程序有用 . 但是第三方面,travc 's answer makes it clear what'实际上正在发生 - 即使是新手也应该能够理解从unsigned int到2s补码signed int的转换意味着只读取2行代码 .无论如何,与另一个关于直接操作位的问题不同,这个问题都是关于对固定长度的int进行算术,只是奇怪的大小 . 所以我猜你是否需要性能,这可能是因为你有很多这些东西,所以你可能希望它被矢量化 . 调整travc对numpy的回答:
现在:
您可能可以通过自定义C代码击败它,但您可能不必这样做 .
如果有人需要反方向:
应输出:0111 0110 0101 0100 0011 0010 0001 0000 1111 1110 1101 1100 1011 1010 1001 1000
不,没有内置函数将two's complement二进制字符串转换为小数 .
这是一个简单的用户定义函数:
请注意,此函数不会将位宽作为参数,而是必须使用一个或多个前导零位指定正输入值 .
例子:
我正在使用Python 3.4.0
在Python 3中,我们遇到了数据类型转换的一些问题 .
所以......在这里,我会告诉他们一些提示(像我一样)用十六进制字符串工作很多 .
我将获取十六进制数据并补充它:
结果= -1397948151或-0x5352fef7或'-0b1010011010100101111111011110111'
遗憾的是,没有内置函数将无符号整数转换为二进制补码有符号值,但我们可以使用按位运算定义一个函数:
第一个按位和操作用于对负数进行符号扩展(最高有效位设置),而第二个用于获取剩余的11位 . 这是有效的,因为Python中的整数被视为任意精度二的补码值 .
然后,您可以将其与
int
函数组合,将二进制数字字符串转换为无符号整数形式,然后将其解释为12位有符号值 .这个函数的一个很好的属性是它是幂等的,因此已经签名的值的值不会改变 .
这适用于3个字节 . Live code is here