将位串转换为有符号 int

问题描述

我编码和解码了一堆系数(与我之前的 question 相关)。该过程基于 RLE,其中对一堆系数进行编码,并且运行时编码仅关注零。简而言之,这是原始数组:

[200,-145,51,-34,29,0]

编码成如下所示的二进制数据:

['000011001000','11001>101101111<','000010001110110011','00010000111>1011110<','00011000110011101','000100011']

为了避免看起来像 -10010001 (-145) 的二进制数,我手动对负数执行了二进制补码(因为我找不到内置方法)。在这种情况下,数字 (-145,-34) 的结果是 (101101111,1011110)。 为避免混淆,我将它们标记在上面的数组中以解决这个问题。

这被填充为可被8整除(最后一个元素在开头插入了0),分成字节并写入文件

当我读取文件时,我成功解码了大部分内容,并且系数的数量与起始的相同。问题出现在负值上:

[200,367,94,0]

我得到了 367 而不是 -145 而不是 -34 我得到了 94。

是否有任何内置方式(或任何类型的方式)将位串转换为有符号值?我觉得这会解决我的问题。我一直找不到方法,现在卡住了。

解决方法

对于无符号数,字长并不重要,因为前导零在那里没有意义。例如 5=101=0101=00101=0...0101。但是,对于二进制补码,字长有所不同,因为第一位表示负数。例如,-3=101 != 0101=5。如果您不知道第一位是什么,您就无法判断该数字是否为负数。

您的编码似乎使用了可变字宽。由于您已经可以对数字进行解码,因此您已经知道每个单词的宽度。

# these variables should be set by your decoder
# in this case we read -145 encoded as 101101111
width = 9
word = 367

# add this to your decoder to fix the sign
firstBit = word >> (width - 1)
if (firstBit == 1):
  leadingOnes = (-1 << width)
  word = leadingOnes | word

同样可以在没有分支的情况下在单个语句中完成,但我认为这对于 CPython 来说平均来说可能会更慢,而且可读性肯定会降低。

word |= -(word >> (width - 1)) << width

当然,您必须确保使用前导 0 对非负数进行编码,以便将它们与负数区分开来。