如何取得32位無符號數二進位表示是否含有奇數個1?

語言:經典C,不能使用條件語句,循環,分支,函數調用和宏調用,除法,模運算,乘法,比較運算,插入彙編語言。最多使用7次位運算/加減法。右移是算數右移(不過是求無符號數應該沒太大影響)

這是csapp家庭作業2.65,原題最多12次運算,我的方法也是網上最多的方法,11次位/加減運算。但是第三版p118旁註稱最少僅需7次,請問如何實現?


reg [31:0]din;

always @(posedge clk)

beg....不好意思走錯片場了


做一個8bit的table,也就是256做成hash.然後把你要的計算的數學移為做與運算,查hash表,相加可得結果!


這個不是sse指令集裡面的么

__builtin_popcount

如果要說沒有sse怎麼辦?

那是生產沒有sse指令集的CPU廠商要考慮的事情。


#include &

int main(int argc, char**argv)

{

unsigned int x = atoi(argv[1]);

//這裡未檢查參數的合法性

x = (x 0x55555555) + ((x&>&>1) 0x55555555); //0101010101010101...

x = (x 0x33333333) + ((x&>&>2) 0x33333333); //0011001100110011...

x = (x 0x0F0F0F0F) + ((x&>&>4) 0x0F0F0F0F); //0000111100001111...

x = (x 0x00FF00FF) + ((x&>&>8) 0x00FF00FF);//0000000011111111...

x = (x 0x0000FFFF) + ((x&>&>16) 0x0000FFFF);

printf ("num of 1: %d
", x);

}


我認為不存在只運算7次的解法(不允許打表的情況下)。

占坑,嘗試證明或推翻。

我知道的最優秀的演算法,進行了16次運算

int bitCount_2(u32 x)
{
x-= ((x 0xAAAAAAAAu) &>&> 1);
x = ((x 0xCCCCCCCCu) &>&> 2) + (x 0x33333333u);
x = ((x &>&> 4) + x) 0x0F0F0F0Fu;
x = ((x &>&> 8) + x) 0x00FF00FFu;
x = ((x &>&> 16) + x) 0x0000FFFFu;

return x;
}

來自2014年集訓隊論文《回歸本源——位運算及其應用》

我很好奇題主的11次是如何實現的。


關於這個問題:

英文第三版問的是:是不是含有奇數個1?

中文第二版問的是:是不是含有偶數個1。

先放上所參考的網頁,大家可以直接去看這個: Question from bit twiddling site

本人找到的都是這種基於2分法的解答,其中奇數11次,偶數12次。

下面以奇數的解答為例:

方法(1):採用典型的2分策略:

/* Return 1 when x contains an odd number of 1s; 0 otherwise Assume w=32 */

int odd_ones(unsigned int x)

{

unsigned int val= x ^ (x&>&>16);

val = (val&>&>8) ^ val;

val = (val&>&>4) ^ val;

val = (val&>&>2) ^ val;

val = (val&>&>1) ^ val;

val = val 0x1;

return val;

}

方法(2):前半部分採用2分策略,後半部分的最後的4個位元組採用查表法,能夠節省2次操作:

找了一些代碼,我覺得下面的這個9次的算是容易理解,期待出現7次的解法(當然不包括查表~):

/* Return 1 when x contains an odd number of 1s; 0 otherwise Assume w=32 */

int odd_ones(unsigned int x)

{

unsigned int val = 0;

val = x ^ (x&>&>16);

val = (val&>&>8) ^ val;

val = (val&>&>4) ^ val;

val = 0xF;

return (0x6996&>&>val) 1;

}

解釋一下, 最後一行的可以實現查表的效果:
(0x6996&>&>val) 1;
// 效果等同於 ch[val],其中ch[16]={0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0};
// 可以省掉2個操作符(不考慮等號),不用查表

//===================== 分割線 @_@! ===========================

// 2017-04-01 更新 : 8次

int odd_ones(unsigned int x)

{

char* parts = (char*)(x);

char val = 0;

val = parts[0] ^ parts[1] ^ parts[2] ^ parts[3];

val = (val&>&>4) ^ val;

val = 0xF;

return (0x6996&>&>val) 0x01;

}

//===================== 分割線 @_@! ===========================

// 2017-04-02 更新 : 7次,這個簡單跑了一下,應該算符合題意吧?

// -c99

int odd_ones(unsigned int x)

{

short* _16s = (short*)(x); // 32 -&> (16^16) -&>16

_16s[0] = _16s[0] ^ _16s[1];

char* _8s = (char*)_16s; // 16 -&> (8^8) -&>8

char val = 0;

val = _8s[0] ^ _8s[1];

val = (val&>&>4) ^ val; // 8-&> (4^4) -&>4

val = 0xF;

return (0x6996&>&>val) 0x01; // 相當於是查表

}


漢明重量


打表


```cpp

int cnt = 0;

while(x) {

x = (x-1);

cnt++;

}

```


推薦閱讀:

TAG:演算法 | 數學 | 計算機科學 | CSAPP |