(x&y) + ((x^y)>>1)作用及其優點
作用
《程式設計師面試寶典》第四版39頁的題:
int func(int x, int y)
func(729,271)是多少?思路最簡單也最直接的就是將x和y都先轉換為二進位制,然後老老實實的做按位與,按位異或等運算,最後得出結果。
首先說明該表示式的作用就是求兩數的平均值,也就是說func(729,271)= (729+271)/2=500。下面說明該表示式的思路。對於二進位制的位運算(&、|、^、~),某位的運算無非就是三種情況:(1)1與1運算;(2)1與0運算;(3)0與0運算。
1與0運算:1&0結果為0,1^0結果為1,那麼只考慮^運算,該位就是1。而0^1可看成(0+1) =1。
1與1運算:兩個數的二進位制運算中若某位上兩個數均為1,則1&1為1,1^1的結果為0,那麼只考慮&運算。而1&1可看成(01+01)>>1 =01(考慮進製)。當然可以看成是(1+1)/2=1,但是這時的1是十進位制,不是二進位制。
0與0運算:0&0為0,0^0為0,則均不用考慮,該位為0即可。
由上面分析可得,對(x & y)與((x ^ y) >> 1)的計算,可以把x和y對應的二進位制每一位拆開來分別計算,那麼可分成三類,每一類分別計算,最後相加。其中,一類是x,y對應位都是1,用x&y計算;一類是x,y中對應位有且只有一位是1,用(x^y)>>1計算;還有一另是x,y中對應位均為0,無須計算,因此這一類可以忽略,也就是說實際只需考慮前兩類即可。
舉例子來說:5和13對應的二進位制分別為0101和1101,把對應的二進位制數拆開來看:5=0000+0100+0000+0001,13=1000+0100+0000+0001,那麼
5&13=
0000 +
0100
+0000 +
0001&
&& &
1000
0100
0000
0001
5^13=
0000
+0100 +
0000 +
0001 ^
^ ^
^ 1000
0100
0000
0001 所以
(5&13)+ (5^13)>>1=
0100
+0001
+0000
>>1
&&^
0100
0001
1000
即((5^13)>>1)+ (5&13) =((0000 ^ 1000)>>1) + (0100 & 0100 + 0001 & 0001)
由以上分析可得:
(5^13)>>1 = (0000 ^ 1000)>>1
=(0000 + 1000)>>1
5&13 = 0100 & 0100 + 0001 & 0001
=(0100 + 0100)>>1 + (0001 + 0001)>>1
所以((5^13)>>1)8 + (5&13) =((0000 ^ 1000)>>1) + (0100 & 0100 + 0001 & 0001)
=(0000 + 1000)>>1 + (0100 + 0100)>>1 + (0001 + 0001)>>1
=((0000 + 1000) + (0100 + 0100) + (0001 + 0001))>>1
而5+13=
0000
+0100
+0000 +
0001++
& +1000
0100
0000
0001
即5+13 =(0000 + 1000) + (0100 + 0100) + (0001 + 0001)。已知乙個十進位制數除以2相當於其對應的二進位制向右移一位,所以有:
(5+13)/2 =/2
=((0000 + 1000) + (0100 + 0100) + (0001 + 0001))>>1
= (5^13)>>1 + (5&13)
因此(5+13)/2 = (5&13) + (5^13)>>1 (表示將裡面的二進位制轉換成十進位制數)
綜上可得,求平均數的過程是先用與運算對數值做部分平均值的提取,然後用異或並右移運算獲得餘下部分的平均值,因此這兩部分的平均值相加後就得出了原來兩數的平均值。實際上,這是乙個加法分解然後綜合的過程。如上面的5和13,先做與運算,也就相當於從5和13 裡分別先減去5,剩下0和8,再將這兩數相加得8(異或運算),然後再除以2(右移),結果為4。最後5+4等於9,即得最後所要的結果。
儘管上面的過程看來上去實際用處不是很大,但如果是用在沒有乘除法指令的簡單微控制器系統,移位和邏輯運算操作就顯得很重要了。
優點
由上可知原函式返回值就是(x+y)/2,因此可改寫為:return (x+y)/2。但實際上,這樣的改寫雖然使得函式的功能清晰了然,但是這樣的改寫並不好,因為對於兩個int型別的整數x,y,如果用(x+y)/2求他們平均值,完全有可能會產生溢位。因為x+y可能會大於int_max,但是我們知道它們的平均值是肯定不會溢位的。所以使用
(x & y) + ((x ^ y) >> 1)
來計算平均值的好處就是可以避免溢位,因為位運算不涉及加法,所以肯定不會產生溢位。
關於 x y x y 1 的解析
原題 int f int x,int y f 729,271 x y x y 1 書上解析說這個函式的功能是取兩個數的平均數。不太明白,查了資料加上整理一下,僅作記錄。一種解釋是 把x和y裡對應的每一位 指二進位制位 都分成三類,每一類分別計算平均值,最後彙總。其中,一類是x,y對應位都是1,用x ...
x y x y 1 求平均值
x y x y 1 把x和y裡對應的每一位 指二進位制位 都分成 三部分,每一部分 分別計算平均值,最後彙總 其中,第一部分 是x,y對應位都是1,用x y計算其平均值 第二部分 是x,y中對應位有且只有一位是1,用 x y 1計算其平均值 第二部分 是x,y中對應位均為0,無須計算。下圖詳細說明 ...
求平均數 x y x y 1 原理
x y x y 1 能求x與y的平均數,其原理1如下 設兩數如下 x y取出同為1的位,如下 00110 由此數一定小於等於原來如何乙個數,由此數加乙個數可以得到原來數,由此將原來的兩數相加變成4數相加,如下 相當於 00110乘以2 x y乘以2 而後兩數相加就是x y,相當於 x y乘以2 x ...