【问题标题】:How do I represent and work with n-bit vectors in Python?如何在 Python 中表示和使用 n 位向量?
【发布时间】:2011-01-10 00:13:53
【问题描述】:

在我目前正在处理的一项作业中,我们需要使用位向量,但我非常不确定如何在 Python 中执行此操作。它们应该能够从 4 位到 20 位。我以前从未使用过位向量,但我想有人会创建您使用通常的 AND/OR/XOR 操作操作的无符号字节数组。

这里的重要限制是:除了标准 Python 提供的库之外,我不能依赖任何库。

我想我知道如何在 C 中使用 8 位无符号字节数组来做到这一点: 例如将清零数组的第 18 位变成一个,我会做类似的事情 my_bit_array[3] &= 1

但是由于 Python 是动态类型的,并且没有内置的数组类型,我该如何以 Python 的方式进行呢?

是否有可能(如何?)表达一个大小为 20 的位向量?我正在考虑制作一个 24 位/3 字节向量并忽略 4 位。

【问题讨论】:

  • 依赖外部库有什么问题?
  • @ezod:可能因为这是家庭作业。
  • @S.Lott:是的,这与那个有关,但这部分与那个关系不大。如您所见,我本可以在 C 中做到这一点,但我想知道如何在 Python 中使用语言的内置函数来做到这一点。这是与其他人相关的一般问题。
  • @oligofren:在这种情况下,外部库的建议似乎对您同样有用,假设它们是免费的——您可以查看源代码并了解它们是如何做到的(使用该语言的内置插件)以满足您的学术兴趣。

标签: python bit-manipulation bitarray bitvector


【解决方案1】:

它有列表,你可以用布尔值填充:

[False] * 20

【讨论】:

  • 这会占用 20 字节还是 20 位内存?我需要使用 lots 的这些
  • 它将占用 20+1 个指针。 True 和 False 是单例。
  • 感谢您的意见!我想在这种情况下我将不得不使用 structs 模块。
【解决方案2】:

使用struct 模块。

【讨论】:

  • 你能给我一个创建一个 3 字节数组并设置一个位的例子吗?我不知道 Python 中的基本二元运算符。
  • 我只用过一次,当时我需要写一些低级的东西。不过,文档非常好。
  • @oligofren 请参阅doughellmann.com/PyMOTW/struct/index.html 了解演练。顺便说一句,该站点为习惯 stdlib 提供了一个非常好的选择。
【解决方案3】:

BitVector 是用于此目的的纯 Python 库,应该满足您指定的需求。

【讨论】:

  • 好图书馆。没用过,但是看代码学到了很多。事实证明,在细节中,BitVector 的作者使用了一个(8 位)字节数组,就像我在思考的那样。
【解决方案4】:

bitarray 模块使用布尔值有效地做到了这一点。

【讨论】:

    【解决方案5】:

    还有纯 Python python-bitstring(支持 Python 3)。

    【讨论】:

      【解决方案6】:

      有点过时了,但为了比较,我将在此处留下另一个 stdlib 选项。使用ctypes 模块也很容易做到这一点。

      例如:

      是否有可能(如何?)表达大小为 20 的位向量? 我正在考虑制作一个 24 位/3 字节向量并忽略 4 位。

      class Simple(ctypes.LittleEndianStructure):
          _pack_ = 1
          _fields_ = [
                       ('one', ctypes.c_ubyte, 8),
                       ('two', ctypes.c_ubyte, 8),
                       ('three', ctypes.c_ubyte, 8)
                     ]
      
      s = Simple(0, 2, 256)
      bytearray(s)        # bytearray(b'\x00\x02\x00')
      s = Simple(0, 2, 255)
      bytearray(s)        # bytearray(b'\x00\x02\xff')
      
      class Simple(ctypes.BigEndianStructure):
          _pack_ = 1
          _fields_ = [
                       ('one', ctypes.c_ubyte, 8),
                       ('two', ctypes.c_ubyte, 8),
                       ('three', ctypes.c_ubyte, 8)
                     ]
      
      s = Simple(0, 2, 256)
      bytearray(s)        # bytearray(b'\x00\x02\x00')
      s = Simple(0, 2, 255)
      bytearray(s)        # bytearray(b'\x00\x02\xff')
      
      s.two |= 3
      bytearray(s)        # bytearray(b'\x00\x03\xff')
      

      或者像这样更直接的东西:

      class bit_vector(Structure):
          _fields_ = [('bits', c_uint32, 24),
                      ('unused', c_uint32, 8),
                      ]
      
      bv = bit_vector()
      # turn on the 18th bit -- being explicit just to demo it
      bv.bits |= int('000000000000000001000000', 2)
      bin(bv.bits)   # 0b1000000
      

      【讨论】:

        【解决方案7】:

        我很惊讶没有人提到ints(或者我猜在 Python 2 中是 long)。 ints 可以任意大,您可以对它们使用按位运算符,它们速度很快,而且代码看起来像 C 中的位旋转代码(我认为这是一个优势)。

        x = 0 # empty
        x |= 1<<19 # set bit 19
        x &= ~(1<<19) # clear bit 19
        x ^= 1<<19 # toggle bit 19
        x = ~x # invert *all* bits, all the way to infinity
        mask = ((1<<20)-1) # define a 20 bit wide mask
        x &= mask # ensure bits 20 and higher are 0
        x ^= mask # invert only bits 0 through 19
        
        (x >> 19) & 1 # test bit 19
        (x >> 16) & 0xf # get bits 16 through 20.
        

        我已经将它用于数百位长的位向量。

        【讨论】:

        • 当你有数百亿位时,在 i7 上每次操作需要几秒钟。
        • 这适用于较小的向量,例如 128 位。非常简单且内置。
        • 我有一个 200 万位的位向量,看起来很慢 stackoverflow.com/questions/52440611/…
        猜你喜欢
        • 1970-01-01
        • 2013-06-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多