Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 从ulong中删除位的快速方法_Algorithm_Bit Manipulation - Fatal编程技术网

Algorithm 从ulong中删除位的快速方法

Algorithm 从ulong中删除位的快速方法,algorithm,bit-manipulation,Algorithm,Bit Manipulation,我想从64位字符串(由无符号长字符串表示)中删除位。我可以通过一系列掩码和移位操作来实现这一点,或者像下面的代码那样迭代每一位。有没有什么巧妙的方法可以让这个动作更快 public ulong RemoveBits(ulong input, ulong mask) { ulong result = 0; ulong readbit = 1; ulong writebit =1; for (int i = 0; i < 64; i++) {

我想从64位字符串(由无符号长字符串表示)中删除位。我可以通过一系列掩码和移位操作来实现这一点,或者像下面的代码那样迭代每一位。有没有什么巧妙的方法可以让这个动作更快

public ulong RemoveBits(ulong input, ulong mask)
{
    ulong result = 0;
    ulong readbit = 1;
    ulong writebit =1;
    for (int i = 0; i < 64; i++)
    {   
        if ((mask & readbit) == 0) //0 in the mask means retain that bit
        {
            if ((input & readbit) > 0)
            {
                result+= writebit;  
            }
            writebit*=2;
        }
        readbit *= 2;
    }
    return result;
}
public ulong RemoveBits(ulong输入,ulong掩码)
{
ulong结果=0;
ulong readbit=1;
ulong writebit=1;
对于(int i=0;i<64;i++)
{   
如果((mask&readbit)==0)//0在掩码中表示保留该位
{
如果((输入和读取位)>0)
{
结果+=可写息税前利润;
}
账面息税前利润*=2;
}
readbit*=2;
}
返回结果;
}
在性能关键的场景中,我需要执行
RemoveBits
数百万次


它可能过于抽象而无济于事,但使用的不同掩码的数量虽然在编译时未知,但在运行时早期(在性能关键位之前)就确定了,并且可能少于100个。基本上,我使用位字符串来表示一个
n元组
,并且
RemoveBits
投影到一个
m元组
(m

有一个非常好的站点,它被称为。它有许多位操作的快速算法。你可能想看一看(我在这里逐字复制,这不是我自己的工作)这个算法:

无分支条件设置或清除位

bool f;         // conditional flag
unsigned int m; // the bit mask
unsigned int w; // the word to modify:  if (f) w |= m; else w &= ~m; 

w ^= (-f ^ w) & m;

// OR, for superscalar CPUs:
w = (w & ~m) | (-f & m);
在某些体系结构上,分支的缺乏可以弥补 这似乎是两倍的操作。例如,非正式的 AMD Athlon上的速度测试™ XP 2100+表明速度提高了5-10%。 Intel Core 2 Duo运行超标量版本的速度比 第一个。Glenn Slayden告诉我关于 2003年12月11日。Marco Yu与我分享了超标量版本 2007年4月3日,并在两天后提醒我输入错误


虽然有这种特殊的操作,但比特旋转黑客网站并没有

这个想法是离线计算一个可以放入以下模板的幻数列表。该模板由一个重复6=lg 64次的基本步骤组成:对k=1、2、…、6的输出位mod 2**k的索引进行校正,假设在每个步骤开始时索引是正确的mod 2**(k-1)

例如,假设我们希望转换

x = a.b..c.d
    76543210
进入

a
位于位置
7
,需要转到
3
(正确位置mod 2)。位
b
位于位置
5
,需要转到
2
(mod 2位置不正确)。位
c
位于位置
2
,需要转到
1
(mod 2位置不正确)。位
d
位于位置
0
,需要保持(正确位置mod 2)。第一个中间步骤是这样移动
b
c

a..b..cd
76543210
这是通过以下方式实现的:

x = (x & 0b10000001) | ((x >>> 1) & 0b00010010);
         //76543210                 //76543210
这里,
>>
表示逻辑移位,
0bxxxxxxxx
表示大端二进制文字。现在我们剩下两个问题:一个是奇数索引位,另一个是偶数-。这个算法之所以快速,是因为现在可以并行处理这些问题

为完整起见,其他两个操作如下所示。位
a
现在位于位置
7
,需要转到
3
(正确位置mod 4)。位
b
现在位于位置
6
,需要转到
4
(mod 4位置不正确)。位
c
d
需要保留(mod 4的正确位置)。得到

是的

a
现在位于位置
7
,需要转到
3
(8模位置不正确)。位
b
c
d
需要保留(正确位置mod 8)。得到

是的

这里有一些Python概念的证明(对不起)

def计算掩码对(保留索引):
掩码对=[]
保留索引=已排序(保留索引)
移位=1
while(保留的索引!=列表(范围(len(保留的索引))):
mask0=0
mask1=0
对于枚举(保留索引)中的(i,j):
断言(我这被称为。不幸的是,没有特殊的硬件支持(作为一种新的硬件支持存在),没有真正的好方法来实现它。以下是黑客喜悦中给出的一些方法,修改为C#和64位
ulong
s,但未经测试:

ulong compress(ulong x, ulong m) {
   ulong r, s, b;    // Result, shift, mask bit. 

   r = 0; 
   s = 0; 
   do {
      b = m & 1; 
      r = r | ((x & b) << s); 
      s = s + b; 
      x = x >> 1; 
      m = m >> 1; 
   } while (m != 0); 
   return r; 
} 
ulong压缩(ulong x,ulong m){
ulong r,s,b;//结果,移位,掩码位。
r=0;
s=0;
做{
b=m&1;
r=r |((x&b)>1;
m=m>>1;
}而(m!=0);
返回r;
} 
这样做的好处是分支比问题中的代码少得多

还有一种方法,循环迭代次数要少得多,但步骤要复杂得多:

ulong compress(ulong x, ulong m) {
   ulong mk, mp, mv, t; 
   int i; 

   x = x & m;           // Clear irrelevant bits. 
   mk = ~m << 1;        // We will count 0's to right. 

   for (i = 0; i < 6; i++) {
      mp = mk ^ (mk << 1);             // Parallel prefix. 
      mp = mp ^ (mp << 2); 
      mp = mp ^ (mp << 4); 
      mp = mp ^ (mp << 8); 
      mp = mp ^ (mp << 16); 
      mp = mp ^ (mp << 32);
      mv = mp & m;                     // Bits to move. 
      m = m ^ mv | (mv >> (1 << i));   // Compress m. 
      t = x & mv; 
      x = x ^ t | (t >> (1 << i));     // Compress x. 
      mk = mk & ~mp; 
   } 
   return x; 
}
ulong压缩(ulong x,ulong m){
乌隆mk、mp、mv、t;
int i;
x=x&m;//清除不相关的位。

mk=~m什么语言?如果这太抽象而不能局限于一种语言,那么在“计算机科学”中可能会更好SE站点。所以你想删除
input
中设置在
mask
中的所有位吗?然后试试
input&~mask
@Gumbo-我不只是想置零一点,我还想右移任何位到它的左边。@conductor。我使用的是C#。我发布的或多或少是第二个版本,带有
x
独立的计算机我相信你的话,它看起来很复杂
x = (x & 0b10000011) | ((x >>> 2) & 0b00000100);
         //76543210                 //76543210
....abcd
76543210,
x = (x & 0b00000111) | ((x >>> 4) & 0b00001000);
         //76543210                 //76543210
def compute_mask_pairs(retained_indexes):
    mask_pairs = []
    retained_indexes = sorted(retained_indexes)
    shift = 1
    while (retained_indexes != list(range(len(retained_indexes)))):
        mask0 = 0
        mask1 = 0
        for (i, j) in enumerate(retained_indexes):
            assert (i <= j)
            assert ((i % shift) == (j % shift))
            if ((i % (shift * 2)) != (j % (shift * 2))):
                retained_indexes[i] = (j - shift)
                mask1 |= (1 << j)
            else:
                mask0 |= (1 << j)
        mask_pairs.append((mask0, mask1))
        shift *= 2
    return mask_pairs

def remove_bits_fast(mask_pairs, x):
    for (log_shift, (mask0, mask1)) in enumerate(mask_pairs):
        x = ((x & mask0) | ((x >> (2 ** log_shift)) & mask1))
    return x

def remove_bits_slow(retained_indexes, x):
    return sum(((((x // (2 ** j)) % 2) * (2 ** i)) for (i, j) in enumerate(sorted(retained_indexes))))

def test():
    k = 8
    for mask in range((2 ** k)):
        retained_indexes = {i for i in range(k) if (((mask // (2 ** k)) % 2) == 0)}
        mask_pairs = compute_mask_pairs(retained_indexes)
        for x in range((2 ** k)):
            assert (remove_bits_fast(mask_pairs, x) == remove_bits_slow(retained_indexes, x))
test()
ulong compress(ulong x, ulong m) {
   ulong r, s, b;    // Result, shift, mask bit. 

   r = 0; 
   s = 0; 
   do {
      b = m & 1; 
      r = r | ((x & b) << s); 
      s = s + b; 
      x = x >> 1; 
      m = m >> 1; 
   } while (m != 0); 
   return r; 
} 
ulong compress(ulong x, ulong m) {
   ulong mk, mp, mv, t; 
   int i; 

   x = x & m;           // Clear irrelevant bits. 
   mk = ~m << 1;        // We will count 0's to right. 

   for (i = 0; i < 6; i++) {
      mp = mk ^ (mk << 1);             // Parallel prefix. 
      mp = mp ^ (mp << 2); 
      mp = mp ^ (mp << 4); 
      mp = mp ^ (mp << 8); 
      mp = mp ^ (mp << 16); 
      mp = mp ^ (mp << 32);
      mv = mp & m;                     // Bits to move. 
      m = m ^ mv | (mv >> (1 << i));   // Compress m. 
      t = x & mv; 
      x = x ^ t | (t >> (1 << i));     // Compress x. 
      mk = mk & ~mp; 
   } 
   return x; 
}