覆盖特定范围内某些位的最佳方法

时间:2010-08-05 13:49:28

标签: python bit-manipulation

给定一系列位,覆盖特定范围的最佳方法是什么。

例如,给定:

0100 1010

假设我想用10覆盖中间2位来产生结果:

0101 0010

这样做的最佳方式是什么?

起初,我以为我只是将我想要的覆盖位移到正确的位置(10000),然后使用按位OR。但我意识到虽然它保留了其他位,但是没有办法指定我想要实际覆盖哪些位。

我正在研究Python的bitarray模块,但我只是想仔细检查一下我是不是在寻找一个非常简单的按位操作来为我做这个。

感谢。

6 个答案:

答案 0 :(得分:7)

这是通过在应用按位OR之前首先屏蔽要擦除的位(强制它们保留其他位,然后保留其他位)来完成的。

对模式使用按位AND(在本例中为11100111

如果您已经拥有该模式的“正面”版本(此处为00011000),这更容易生成,您可以使用所谓的“负面”版本11100111获取1的补码,在Python中以~和大多数具有类C语法的语言提供。

答案 1 :(得分:6)

a = 0b01001010
a &= 0b11100111
a |= 0b00010000

and首先将目标位置零:

  01001010
& 11100111
  --------
  01000010

然后or用所需数据填充它们:

  01000010
| 00010000
  --------
  01010010

答案 2 :(得分:4)

我看到你在“位操纵”的静脉中得到了很好的答案。但是,如果你必须做很多这方面的工作,我仍然会建议阅读讨论here并从中进行链接,并且,正如维基建议的那样,找到了一些软件包this way(BitVector,BitPacket) ,bitarray) - 可读性很重要,经验表明,从应用程序级流中删除非显而易见的内联代码,转而使用命名良好的API,可以增强它。

如果您决定进行操作,则给定位索引自动生成位范围掩码显然至关重要。我建议从只有一位的“原子位掩码”开始,通过移位来构建:

>>> bin(1 << 7)
'0b10000000'

如你所见,1 << 7有一个后跟7个零 - 因此:

>>> bin((1 << 7) - 1)
'0b1111111'

(1 << 7) - 1正好有7个(你需要括号,因为移位运算符<<的优先级低于减法运算符-的优先级),因为最低有效位也称为LSB (当然还剩下所有的零)。

给出一种简单的方法来制作“具有N个的位掩码”(作为LSB),将包含N的位置包括在M排除的集合中,并且所有其他清除很容易 - 使用命名函数以获得额外的可读性:

>>> def n_lsb(x): return (1 << x) - 1
... 
>>> def n_to_m(n, m): return n_lsb(n) & ~ n_lsb(m)
... 
>>> bin(n_to_m(7, 3))
'0b1111000'

所以,现在,将其中包含的N位排除在某个模式之外,如其他答案所示:

>>> def set_bits(i, n, m, pat): return (i & ~n_to_m(n, m))|(pat<<m)
... 
>>> bin(set_bits(511, 7, 3, 0b0101))
'0b110101111'

虽然这个答案本身不允许你做任何比其他人更多的事情,我希望它可以帮助“教你钓鱼”(而不仅仅是给你一条鱼;-)从而帮助你(以及其他读者。

顺便说一下,我建议将按位和算术运算的混合减少到最少 - 在这个A中,我使用的唯一算术运算是- 1中的n_lsb,这是一个非常明显的例子;在更一般的情况下,两个补码算术(从按位的角度来看,普通的整数算术看起来像)可能很棘手。

答案 3 :(得分:2)

您可以分两步完成:

  1. 创建一个包含所有0的数字 想写那个看起来像 1111 0111并使用AND
  2. 创建一个包含所有1的数字 看起来像0001 0000并使用 OR
  3. 顺便说一句:第一个数字可以通过从255中减去1移位到零的位置来轻松创建。例如,执行255 - (0000 1000)。

        a = 255 - (1 << x)
        b = 1 << y
        result = (source & a) | b
    

    其中x和y是各自位的位置。

答案 4 :(得分:1)

>>> bin(0b01001010 & 0b11110111 | 0b00010000)
'0b1010010'

答案 5 :(得分:0)

这是我从几个答案中得出的一些基本的按位函数集(感谢@Alex Martelli的出色回答)。 只需打开一个新的python文件,将其命名为BITManipulation.py,然后将此代码复制到该代码中,即可从您的代码中将其导入,您无需使用位即可访问所有功能。 无论如何,我总是建议深入了解它的工作原理。

    """
BitManipulation.py
This file is used to define some basic bit manipulations functions
"""

#@func: get_bit
#@params: value,n
#@return: the N-th bit from value
def get_bit(value, n):
    return ((value >> n & 1) != 0)

#@func: set_bit
#@params: value,n
#@return: value with the N-th bit Set to 1
def set_bit(value, n):
    return value | (1 << n)

#@func: clear_bit
#@params: value,n
#@return: value with the N-th bit Set to 0
def clear_bit(value, n):
    return value & ~(1 << n)

#@func: n_lsb
#@params: x ( Example 7)
#@return: a number with exactly x bits of 1 ( Example 0b1111111 )
def n_lsb(x):
    return (1 << x) - 1

#@func: n_to_m
#@params: n,m (n > m)( Example 5,3 )
#@return: a number with bits n -> m set to 1 ( Example 0b00011000 )
def n_to_m(n, m):
    return n_lsb(n) & ~ n_lsb(m)

#@func: set_bits
#@params: x,n,m,pat (n > m)( Example 511,5,3,0b0101 )
#@return: sets bits n -> m in x to pat ( Example 0b110101111 )
def set_bits(x, n, m, pat):
    return (x & ~n_to_m(n, m))|(pat<<m)