2016-08-18 16 views
1

我想切换n次没有循环。
像1(位)切换3次后会变为0等等。 对于切换位1次,我使用位^ = 1。 我实际上在搜索一个位操作公式来做到这一点。如何在C/C++中不使用循环切换n次?

+1

你可以给至少3个实际例子和它们各自的结果;你正在尝试做什么? – WhiZTiM

+0

恐怕你的问题还不清楚。你能否尝试更多地解释它,理想情况下用一个例子(可以是伪代码)? – Angew

+1

你需要看到切换位还是只需要结果?如果你所需要的只是结果,这很容易。要么切换一次,要么保持独立,取决于您想要切换的次数。 – NathanOliver

回答

6

周期性如果我理解正确的话,您至少需要2位,你要切换有点N倍。现在

,切换仓N次等于触发N%的2倍这样:

b ^= (N%2); 

模2相同​​所以你也可以这样写:

b ^= (N&1); 
+0

尽管@shloim回答了这个问题,但是所有的答案取决于“如果你理解正确”......在回答之前尝试纠正这样的问题。 –

0

这是不可能的,如果你只有独立操纵位。

这是因为一个特定位不知道它的前两个状态。

如果你想有一个周期与4

1

广义解:

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

gcc 5.3产生该代码:

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

为了好玩,让我们把它写在naiive方式,享受欢乐:

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

    return word; 
} 

输出(5.3):

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 

8/

当然

时,一个优化器拥有它所需要的所有信息,甚至可以使代码变得高效:

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

结果:

main: 
     mov  eax, edi 
     xor  eax, 8 
     ret