簡體   English   中英

如何在不使用C / C ++循環的情況下切換n次?

[英]How to toggle a bit n times without using loop in C/C++?

我想切換n次而不循環。
像在切換3次之后的1(bit)將為0,依此類推。 為了切換1次,我使用bit ^ = 1。 我實際上搜索了一些操作公式來做到這一點。

如果我理解正確,則需要切換N次。

現在,將垃圾箱切換N次等於翻轉N%2次,因此:

b ^= (N%2);

Modulo 2與N&1相同,因此您還可以編寫:

b ^= (N&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

為了好玩,讓我們以一種幼稚的方式來編寫它並享受歡樂:

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

如果您僅獨立地操作位,則這是不可能的。

那是因為特定的位不知道其前兩個狀態。

如果要一個周期為4的周期,則至少需要2位。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM