如何在不使用C / C ++循环的情况下切换n次?

时间:2016-08-18 13:57:05

标签: c++ bit-manipulation

我想在没有循环的情况下进行n次切换 切换3次后的1(位)将为0,依此类推。 为了切换1次,我使用bit ^ = 1。 我实际上搜索了一些操作公式来这样做。

3 个答案:

答案 0 :(得分:6)

如果我理解正确,您需要稍微切换N次。

现在,切换bin N次等于切换N%2次,所以:

b ^= (N%2);

模2与N&1相同,所以你也可以写:

b ^= (N&1);

答案 1 :(得分:1)

广义解决方案:

String

gcc 5.3生成此代码:

int toggle_bit_in_word(int word, int bit, int ntimes)
{
  auto archetype = ntimes & 1;
  auto toggler = archetype << bit;
  return word ^= toggler;
}

为了好玩,让我们把它写成一种方式,享受欢乐:

toggle_bit_in_word(int, int, int):
        and     edx, 1
        shlx    edx, edx, esi
        mov     eax, edx
        xor     eax, edi
        ret

输出(5.3):

int toggle_bit_in_word_naiive(int word, int bit, int ntimes)
{
  auto toggler = 1 << bit;
  while (ntimes--)
    word ^= toggler;

  return word;
}

8 - /

当然,当优化者拥有所需的所有信息时,即使是有效的代码也会变得高效:

toggle_bit_in_word_naiive(int, int, int):
        mov     ecx, 1
        mov     eax, edi
        shlx    esi, ecx, esi
        lea     edi, [rdx-1]
        test    edx, edx
        je      .L48
        lea     ecx, [rdx-8]
        shr     ecx, 3
        add     ecx, 1
        lea     r9d, [0+rcx*8]
        cmp     edi, 12
        jbe     .L4
        vmovd   xmm1, esi
        xor     r8d, r8d
        vpxor   xmm0, xmm0, xmm0
        vpbroadcastd    ymm1, xmm1
.L5:
        add     r8d, 1
        vpxor   ymm0, ymm0, ymm1
        cmp     ecx, r8d
        ja      .L5
        vpxor   xmm1, xmm1, xmm1
        vperm2i128      ymm2, ymm0, ymm1, 33
        vpxor   ymm0, ymm0, ymm2
        sub     edi, r9d
        vperm2i128      ymm2, ymm0, ymm1, 33
        vpalignr        ymm2, ymm2, ymm0, 8
        vpxor   ymm0, ymm0, ymm2
        vperm2i128      ymm1, ymm0, ymm1, 33
        vpalignr        ymm1, ymm1, ymm0, 4
        vpxor   ymm0, ymm0, ymm1
        vmovd   ecx, xmm0
        xor     eax, ecx
        cmp     edx, r9d
        je      .L47
        vzeroupper
.L4:
        xor     eax, esi
        test    edi, edi
        je      .L48
        xor     eax, esi
        cmp     edi, 1
        je      .L48
        xor     eax, esi
        cmp     edi, 2
        je      .L48
        xor     eax, esi
        cmp     edi, 3
        je      .L48
        xor     eax, esi
        cmp     edi, 4
        je      .L48
        xor     eax, esi
        cmp     edi, 5
        je      .L48
        xor     eax, esi
        cmp     edi, 6
        je      .L48
        xor     eax, esi
        cmp     edi, 7
        je      .L48
        xor     eax, esi
        cmp     edi, 8
        je      .L48
        xor     eax, esi
        cmp     edi, 9
        je      .L48
        xor     eax, esi
        cmp     edi, 10
        je      .L48
        xor     eax, esi
        xor     esi, eax
        cmp     edi, 11
        cmovne  eax, esi
        ret
.L47:
        vzeroupper
.L48:
        ret

结果:

int main(int argc, char**argv)
{
  return toggle_bit_in_word_naiive(argc, 3, 3);
}

答案 2 :(得分:0)

如果您只是独立操作位,这是不可能的。

那是因为某个特定位不知道其前两个状态。

如果您想要一个周期为4的循环,则至少需要2位。