可以看出,x-1的功能是:將最右側(cè)的1翻轉(zhuǎn)了,并讓其后的0變成了1,而保持了其他位不變。然后x&(x-1)就使得x的最右側(cè)的1翻轉(zhuǎn)成0。 該位運(yùn)算在上一篇中被用來(lái)計(jì)算二進(jìn)制中有多少個(gè)1,其思路是:不停的翻轉(zhuǎn)右側(cè)的1,知道將該數(shù)翻轉(zhuǎn)成0為止。 2. 向右連續(xù)傳播最右側(cè)的1位:x|(x-1) 比如說(shuō)x=00101000,那么x,x-1和x|(x-1)的二進(jìn)制表示分別如下:
從上面的過(guò)程可以看出x|(x-1)使得x中最右邊的1的右邊的0都被1填充了,注意這不能理解成:翻轉(zhuǎn)最右側(cè)的連續(xù)的0,而應(yīng)該理解成用最右側(cè)的1填充了它右邊的所有0位。或許你要問(wèn)為什么,那么你假設(shè)x =00101001,那么x|(x-1)仍然等于00101001,它并沒(méi)有將最右側(cè)的兩個(gè)0翻轉(zhuǎn)! 3. 檢查無(wú)符號(hào)數(shù)x是否是2的整數(shù)次冪:if((x&(x-1))==0)return true; 由1可知:x&(x-1)的作用是將最右側(cè)的1翻轉(zhuǎn)為0,假如翻轉(zhuǎn)之后結(jié)果變成了0,則說(shuō)明原來(lái)的數(shù)x的二進(jìn)制表示中只包含一個(gè)1,那么它必定是2的整數(shù)次冪。這個(gè)簡(jiǎn)單,我就不圖示了。記住:2的整數(shù)次冪跟2的整數(shù)次冪減1進(jìn)行與運(yùn)算的結(jié)果必然為0。 4. 檢查無(wú)符號(hào)數(shù)x是否等于2的整數(shù)次冪減1:if((x&(x+1))==0) return true; 2的整數(shù)次冪減1再加1之后就等于2的整數(shù)次冪,于是可以用3的方法來(lái)判斷,這也非常簡(jiǎn)單,不再圖示。 5. 將右側(cè)的連續(xù)1位串翻轉(zhuǎn)成0位串,其他保持不變:((x|(x-1))+1)&x 比如x等于00101100,那么
由2得知:x|(x-1) 使得x中最右邊的1的右邊的0都被1填充了;而(x|(x-1))+1 就使得x中那個(gè)連續(xù)的1位串和它右邊的0位串都變成0,并且將連續(xù)的1位串的左邊那位0變成了1,并保持其他位不變;(x|(x-1)+1)&x使得x中那個(gè)連續(xù)的1位串和它右邊的所有位都置為0,而保持那個(gè)連續(xù)的1位串的左邊保持不變,于是就實(shí)現(xiàn)了將最右邊的連續(xù)的1位串翻轉(zhuǎn)的功能。 文字解釋繞來(lái)繞去的,非常拗口啊,沒(méi)辦法啊,這個(gè)關(guān)系本省就繞,希望不會(huì)把各位繞糊涂了。 6. 檢查無(wú)符號(hào)整數(shù)x是否等于2的兩個(gè)整數(shù)次冪之差: if((((x|(x-1))+1)&x)==0)==0) return true; 所謂2的兩個(gè)整數(shù)次冪之差就是2k-2j,比如k等于6,j等于2,那么26的二進(jìn)制是:00100000,22的二進(jìn)制表示為00000100,26-22的二進(jìn)制表示為00111100,由此可以看出2k-2j的特征是:二進(jìn)制表示形式中從第j位到第k-1位都是1(從0開(kāi)始數(shù)),其他bit位都是0。 由上可知:通過(guò)位運(yùn)算在保持其他bit位不被改變的情況下,將這些為1的bit位全部翻轉(zhuǎn)為0,如果所得的結(jié)果等于0,那么原來(lái)的數(shù)就是一定是2的兩個(gè)整數(shù)次冪之差!事實(shí)上5中已經(jīng)介紹了((x|(x-1))+1)&x的功能就是將x的二進(jìn)制表示中右側(cè)連續(xù)的1位串翻轉(zhuǎn)為0位串,因此只需要應(yīng)用3計(jì)算((X|(x-1))+1)&x的值,然后判斷它是否等于0即可,為了說(shuō)明這個(gè)問(wèn)題,我再圖示演示了這一過(guò)程,這里的x等于00111100
從上表看出,由于最后計(jì)算結(jié)果等于0,所以x就是兩個(gè)2的整數(shù)次冪的差,其實(shí)x = 60 = 26-22。 |
|
來(lái)自: lixinhecom > 《C語(yǔ)言》