2014-03-03 82 views
1

如何僅使用位操作(無控制結構)切換每個半字節的第0和第3位?爲了解決這個問題,我需要創建什麼樣的口罩?任何幫助,將不勝感激。例如,8(1000)變爲1(0001)。在int的每個半字節中切換位

/* 
* SwitchBits(0) = 0 
* SwitchBits(8) = 1 
* SwitchBits(0x812) = 0x182 
* SwitchBits(0x12345678) = 0x82a4c6e1 
* Legal Operations: ! ~ &^| + << >> 
*/ 
int SwitchBits(int n) { 

} 
+0

檢查[位操作黑客(http://graphics.stanford.edu/~seander/bithacks html的);我不確定答案在那裏,但它是第一個看的地方。 –

+0

你目前的代碼是什麼? – Marian

+1

'SwitchBits(0x812)'應該是'0x112',除非您在每個*半字節*中切換位3和0,而不是每個*字節*。 (同樣,'SwitchBits(0x12345678)'應該是'0x12345671'。) – Thanatos

回答

2

代碼:

#include <stdio.h> 
#include <inttypes.h> 

static uint32_t SwitchBits(uint32_t n) 
{ 
    uint32_t bit0_mask = 0x11111111; 
    uint32_t bit3_mask = 0x88888888; 
    uint32_t v_bit0 = n & bit0_mask; 
    uint32_t v_bit3 = n & bit3_mask; 
    n &= ~(bit0_mask | bit3_mask); 
    n |= (v_bit0 << 3) | (v_bit3 >> 3); 
    return n; 
} 

int main(void) 
{ 
    uint32_t i_values[] = { 0, 8, 0x812, 0x12345678, 0x9ABCDEF0 }; 
    uint32_t o_values[] = { 0, 1, 0x182, 0x82A4C6E1, 0x93B5D7F0 }; 
    enum { N_VALUES = sizeof(o_values)/sizeof(o_values[0]) }; 

    for (int i = 0; i < N_VALUES; i++) 
    { 
     printf("0x%.8" PRIX32 " => 0x%.8" PRIX32 " (vs 0x%.8" PRIX32 ")\n", 
       i_values[i], SwitchBits(i_values[i]), o_values[i]); 
    } 
    return 0; 
} 

輸出:

0x00000000 => 0x00000000 (vs 0x00000000) 
0x00000008 => 0x00000001 (vs 0x00000001) 
0x00000812 => 0x00000182 (vs 0x00000182) 
0x12345678 => 0x82A4C6E1 (vs 0x82A4C6E1) 
0x9ABCDEF0 => 0x93B5D7F0 (vs 0x93B5D7F0) 

注意使用uint32_t以避免符號整數與符號位未定義行爲。

1

要獲得一點,可以使用AND對其進行掩蓋。要獲得最低位,例如:

x & 0x01 

想想AND的工作原理:必須設置兩個位。由於我們與1進行AND運算,所以除第一個以外的所有位都必須爲0,因爲它們在0x01中爲0。最低位將爲0或1,具體取決於x中的內容;換句話說,最低位將是x中的最低位,這正是我們想要的。視覺:

x = abcd 
AND 1 = 0001 
    -------- 
     000d 

(其中abcd代表位的插槽;我們不知道他們是什麼)

將其移動到第3位的位置,只是接班:

(x & 0x01) << 3 

視覺上,再次:

x & 0x01 = 000d 
    << 3 
    ----------- 
      d000 

要添加它,首先,我們需要清除0這個位置爲我們的位。我們使用,並再次:

x & ~0x08 

在這裏,我們顛倒0x08(這是二進制1000):這意味着除了第3位將所有的位,當我們和與x,我們得到x除那一點。

在視覺上,

0x08 = 1000 
(invert) 
----------- 
     0111 
AND x = abcd 
------------ 
     0bcd 

結合了OR:

(x & ~0x08) | ((x & 0x01) << 3) 

在視覺上,

  x & ~0x08 = 0bcd 
| ((x & 0x01) << 3) = d000 
-------------------------- 
         dbcd 

現在,這只是移動位0到第3位,而只是將覆蓋3位。我們仍然需要做3位→0。這只是另:

x & 0x08 >> 3 

我們需要清除其現貨:

x & ~0x01 

我們可以結合兩種結算件:

x & ~0x09 

然後:

(x & ~0x09) | ((x & 0x01) << 3) | ((x & 0x08) >> 3) 

那當然只處理最低的半字節。我會把其他人作爲練習。

1

請嘗試以下代碼。在這裏,您應該知道按位運算符來實施和修正放置位置。還需要了解維護,移位和切換基本屬性。

#include<stdio.h> 
#define BITS_SWAP(x) x=(((x & 0x88888888)>>3) | ((x & 0x11111111)<<3)) | ((x & ~ (0x88888888 | 0x11111111))) 

int main() 
{ 
    int data=0; 
    printf("enter the data in hex=0x"); 
    scanf("%x",&data); 
    printf("bits=%x",BITS_SWAP(data)); 
    return 0; 
} 

OP

維奈@維奈 - VirtualBox的:〜/ c_skill $ ./a.out

hex=0x1

bits=8

維奈@維奈 - VirtualBox的輸入數據:〜/ c_skill $ ./a.out

輸入數據爲hex=0x812 bits=182

維奈@維奈 - VirtualBox的:〜/ c_skill $ ./a.out

hex=0x12345678 bits=82a4c6e1

維奈@維奈 - VirtualBox的輸入數據:〜/ c_skill $

1
  1. 將低位移到高位並掩蓋結果位。
  2. 將高位移到低位並掩蓋結果位。
  3. 將所有尚未移動的位屏蔽掉。
  4. 將結果與OR組合。

代碼:

unsigned SwitchBits(unsigned n) { 
    return ((n << 3) & 0x88888888) | ((n >> 3) & 0x11111111) | (n & 0x66666666); 
} 

Alternativly,如果你想成爲非常聰明。它可以用兩個較少的操作來完成,但由於指令之間的某些依賴性,這可能實際上並不快。

  1. 移動高位與低位
  2. XOR記錄在低比特一個0如果高的低比特是相同的,並且如果1它們是不同的對準。
  3. 由此,只掩蓋每個半字節的低位。
  4. 由此乘以9,這將保持原來的低位,並將其複製到高位。
  5. 由此,XOR與原始值。在高位和低位相同的情況下,不會發生正確的改變。如果它們不同,它們將被有效地交換。

代碼:

unsigned SwitchBits(unsigned n) { 
    return ((((n >> 3)^n) & 0x11111111) * 0x9)^n; 
} 
1

嘗試XOR交換的這個變體:

uint32_t switch_bits(uint32_t a){ 
    static const mask = 0x11111111; 
    a ^= (a & mask) << 3; 
    a ^= (a >> 3) & mask; 
    a ^= (a & mask) << 3; 
    return a; 
}