按位操作的麻烦

时间:2012-12-15 05:13:58

标签: c++ c 64-bit bit-manipulation

好的,伙计们,我知道我想做什么,但我不知道它是否已经存在(作为一个函数或理论上)或如何表达它,所以我需要你的帮助:

  • 假设我们有二进制数:(msb) 10101110 (lsb)
  • 从第X位开始,我想在遇到第一个零位时将所有其他位(向左)清零。
  • 以尽可能快速的方式执行此操作,并且需要绝对最少的操作数和CPU周期

示例:

  • Number = 10101110,起始位置= 1(位置1 = 1)
  • 位置++ - 位置2 = 1,继续
  • 位置++ - 位置3 = 1,继续
  • 位置++ - 位置4 = 0,oops ...零遇到......现在,一切都必须归零。

因此,我们想象函数CROPLEFT(X,POS)的最终结果,其中X = 10101110,POS = 1,将返回00001110


有什么想法吗?

4 个答案:

答案 0 :(得分:12)

一块蛋糕。

y = ~x;    // We like working with 1's, not 0's.
y &= -y;   // Mask off all but the lowest-set bit
x &= y-1;  // Make a mask for the bits below that and apply it.

并添加了位置参数:

y = ~x & -1U<<pos; // Change 1U to a larger type if needed.
y &= -y;
x &= y-1;

关键因素是第二行,并且您可以通过应用逻辑和y来仅使用其最低设置位替换值-y。可悲的是,除非你有一个特殊的cpu指令,否则没有获得最高设置位的运气,所以你很幸运,你的问题要求最低。

答案 1 :(得分:3)

好的,到底是什么:

return x & ((x ^ (x + (1UL << POS))) | ((1UL << POS) - 1))

对于它的价值,它们都使用gcc-4.7 -O3编译。 R ..在左边,我在右边:(使用无符号长和1UL两个)

        .p2align 4,,15                          .p2align 4,,15
        .globl  zapleft                         .globl  zapleft2
        .type   zapleft, @function              .type   zapleft2, @function
zapleft:                                zapleft2:           
.LFB0:                                  .LFB1:
        .cfi_startproc                          .cfi_startproc
        movl    %esi, %ecx                      movl    %esi, %ecx
        movq    %rdi, %rax                      movl    $1, %edx
        movq    $-1, %rdx                       salq    %cl, %rdx
        salq    %cl, %rdx                       leaq    (%rdx,%rdi), %rax
        notq    %rax                            subq    $1, %rdx
        andq    %rax, %rdx                      xorq    %rdi, %rax
        movq    %rdx, %rax                      orq     %rdx, %rax
        negq    %rax                            andq    %rdi, %rax
        andq    %rdx, %rax                      ret
        subq    $1, %rax                        .cfi_endproc
        andq    %rdi, %rax              .LFE1:
        ret                             .size   zapleft2, .-zapleft2
        .cfi_endproc
.LFE0:
        .size   zapleft, .-zapleft

答案 2 :(得分:1)

CROPLEFT(int X,int POS) {

    int mask = 1 << POS;

    while (X & mask)
        mask <<= 1;

    return (X & (mask - 1));
}

答案 3 :(得分:0)

用以下内容替换尾随零:

x = x | (x-1);

用零替换尾随的那些:

x = x & (x+1);

编辑:Oups,似乎我误读了这个问题,上面的代码将右边的位置为零,而不是左边的位!

要将左位置零,我们需要最后的XOR运算:

y = x | (x-1);
y = y & (y+1);
y = x ^ y;

编辑2 关于起始位置POS

我们必须在第一步中将最右边的POS位清零。

y = x & (-1U<<pos);
y = y | (y-1);
y = y & (y+1);
y = x ^ y;

编辑3 如果在POS上遇到第一组零,则忽略第一组零。
如果这不回答问题,那么代码会更短,但非常像现在的rci:

y = x | ((1U<<pos)-1); // fill trailing positions with ones
y = y & (y+1);         // replace trailing ones by zeroes
y = x ^ y;             // modify leading bits rather than trailing ones