【问题标题】:"Bitwise Not" in Python disconsidering 2's complementPython中的“按位非”不考虑2的补码
【发布时间】:2014-09-10 02:50:30
【问题描述】:

我需要在 Python 中进行“~”操作,但不考虑 2 的补码。我通过使用 XOR 设法做到了这一点,你知道另一种方法吗? (更高效)

a = 0b101
b = 0b10101

print bin(a ^ (2 ** a.bit_length() - 1)) #0b10
print bin(b ^ (2 ** b.bit_length() - 1)) #0b1010

【问题讨论】:

  • 请问为什么? bin 表示可能会让您感到困惑。 ~ 确实反转了位;它只是反转了无限个位,因此无法以文本方式表示。 bin 因此对- 进行了一些处理以使其工作,但最终隐藏了所有位都被反转的事实。
  • @Veedrac 我正在实现一个 16 位虚拟机。
  • 我认为你的方法足够好,不要认为 python 有这样做的本机方式。一个小的变化可以是使用位移而不是幂。
  • 如果是虚拟机,您可能知道寄存器宽度,因此您可以通过将表达式硬编码为a ^ 0xFFFF 来清理一下。
  • (1 << b.bit_length() - 1) 将比 (2 ** b.bit_length() - 1) 更快 - 是的,如果可以的话,硬编码一个掩码而不是调用 bit_length

标签: python binary twos-complement


【解决方案1】:

~ 已经这样做了。棘手的部分是 Python 有无限长度的整数,所以当你反转一个数字时,它是用符号扩展的——至少从概念上讲——无限个 1。这意味着你得到负数。

>>> bin(~0b101)
'-0b110'
>>> bin(~0b10101)
'-0b10110'

要将这些转换为无符号数,您需要确定您关心的位数。也许您正在使用 8 位字节。然后你可以将它们与一个字节的 1 位相加:

>>> bin(~0b101 & 0xFF)
'0b11111010'
>>> bin(~0b10101 & 0xFF)
'0b11101010'

或者如果你想匹配输入数字的确切位长,你的解决方案是合理的。为了提高效率,您可以将指数切换为左移。使用~& 而不是^ 可能更清楚。

>>> bin(~a & ((1 << a.bit_length()) - 1))
'0b10'
>>> bin(~b & ((1 << b.bit_length()) - 1))
'0b1010'

(我怀疑像&amp; 0xFFFF 这样的硬编码掩码在实践中将是正确的解决方案。对于基于bit_length() 的答案,我想不出一个好的现实世界用例。)

【讨论】:

  • 谢谢,你知道 bit_length 是使用数学还是字符串操作?
  • bit_length 不触摸字符串。
  • bit_length 在 CPython 上的时间大约是恒定的,而且似乎非常快,所以我认为它只是返回一个内部缓存值。
  • 你是对的一个简单的~b &amp; 0xFFFF 解决了github.com/leandromoreira/python_chip16/commit/…
【解决方案2】:

另一种方式,虽然有些人(包括我自己)可能会认为它更好,但:

tbl = str.maketrans("01","10")

int(bin(42)[2:].translate(tbl),2)

第一位只是建立一个转换表来反转字符串中的10位。

第二个位得到二进制表示(42 -> 0b101010),去掉前面的0b,并通过翻译反转位。然后你只需使用int(,2) 将二进制字符串转换回一个数字。


如果您可以将其限制为特定宽度而不是使用数字本身的宽度,那么这是一个简单的问题(使用 32 位的示例):

val = val ^ 0xffff

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多