天天看點

用變換的思維寫程式

看到CSDN有網友提出能否用純位運算實作if語句

int x;
//...
if(0 != x)
{
    x = 1;
}
           

詳見

http://topic.csdn.net/u/20110710/10/19ce7d9b-01b7-4082-bb3b-1f4216c7223b.html

當然這是一道沒什麼意義的題目.相信樓主隻是為了好玩.

乍看之下似乎沒什麼可能,畢竟判斷是很基本的要素.

然而程式裡沒什麼不可能,有同學就寫出了以下幾個方案:

 方案一:

x |= x >> 16
x |= x >> 8
x |= x >> 4
x |= x >> 2
x |= x >> 1
x &= 1
           

方案二:

x = x == 0? 0:1
           

這裡方案二是不符合要求的,因為?号其實就是if判斷,隻是寫法不同而已

方案一有點暴力.

我當時随便想了下提出了

x=((1<<x)>>(x-1))>>1
           

并簡單測試了幾個數,但後來被發現在臨界點32位的時候是有問題的,不知道是否32的倍數都會有問題,沒去測試,

思考其原因可能是優化的結果,或者是帶進位移位造成的,因為按理論是不會有問題的.

不過做程式時一些臨界點是很重要的,也是一般測試程式必要的測試點.

後來有同學提出了

x = (~((uint)x-1) | (uint)x) >> 31
           

比較完美的解決了問題,

x=(((uint)1<<x)>>(x-1))>>1
           

這個思想是讓1在非0的時候不移動,在0的時候往右移1位,可惜受到進位的影響,在32倍數時出現問題.

此外還有同學提出了!!x的方案,

x=!!x
           

這個方案非常簡潔明了,負負得正,消除其他位的1,可惜的是這個方案核心還是使用了比較

彙編代碼為

cmp dword ptr [x],0  
setne al 
           

是以最後總結方案為

x = (~((uint)x-1) | (uint)x) >> 31
           

這個方案還可以有另一個形式

((-(unsigned int)x) | x )>> 31
           

不過這個确實很好玩的,有時侯寫程式就應該多想想其他的思路,說不定就會有妙招出來.

遇到問題,不妨換個角度去思考,也許就豁然開朗了.

人生也是如此,在遇到絕境時,不妨換條路走走.說不定就是另一番天地.

用變換的思維寫程式