按位操作出现问题

Trouble with bitwise manipulation

本文关键字:问题 位操作      更新时间:2023-10-16

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

  • 假设我们有一个二进制数:(msb10101110 (lsb)
  • 从位 X 开始,一旦遇到第一个零位,我想将所有其他位(向左)归零。
  • 尽可能地做到这一点,所需的操作次数和 CPU 周期绝对最少

一个例子:

    数字 = 10101110,起始位置 = 1(
  • 位置 1 处的位 = 1)
  • 位置++ - 位 2 = 1,继续前进
  • 位置++ - 位置 3 = 1 处的位,继续前进
  • 位置++ - 位在位置 4 = 0,哎呀...零遇到...现在,一切都必须归零。

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


有什么想法吗?

小菜一碟。

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指令,否则没有这样的运气来获得最高设置的位,所以你很幸运你的问题要求最低。

好吧,到底是什么:

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

值得一提的是,它们都用gcc-4.7 -O3编译。左边,右边是我的:(两者都使用无符号的长和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
CROPLEFT(int X,int POS) {
    int mask = 1 << POS;
    while (X & mask)
        mask <<= 1;
    return (X & (mask - 1));
}

尾随的零替换为 1:

x = x | (x-1);

将尾随的 1 替换为零:

x = x & (x+1);

编辑:哎呀,看来我误读了这个问题,上面的代码将正确的位归零,而不是左位!

要将左位归零,我们需要一个最终的 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