Linux 核心設計
成大課程
contributed by < hbr890627
>
想對二個無號整數取平均值,用以下程式可以避免 overflow ,正常執行。
可改寫為以下等價的實作:
其中:
a >> 1
,向右 shift 一個位元,等價於 a/=2
。
b >> 1
,向右 shift 一個位元,等價於 b/=2
。
但若是在 shift 之後才將兩者相加,可能會漏掉最右邊的位元,如: 01 + 01 = 10
,需要在當 a
, b
都為奇數時,補上 1 , 因此 EXP1 = a & b & 1。
最後要再 & 1
,是因為只需要取最右邊位元的資訊就好。
可以再次改寫為以下等價的實作:
參考第 1,2 週課堂問答簡記中, Eddielin0926
的解釋,可以將其思考成全加器除二,原本是 a + b >> 1
,將 carry 提出來後就變成 (a & b) + ((a ^ b) >> 1)
。
EXP2 = a & b
EXP3 = a ^ b
在〈解讀計算機編碼〉一文中的「不需要分支的設計」一節提供的程式碼 min
:
diff >> 31
,取最左邊的位元,看是正數或負數。
如果是正數, diff & (diff >> 31)
等於零,會 return b
。
如果是負數, diff & (diff >> 31)
等於 diff
,會 return b
+ diff
= a
。
將上面程式碼進行改寫,可以得到以下實作 (max
):
考慮兩種情況:
a >= b
時,根據 XOR 的特性,((EXP4) & -(EXP5))
要等於 0 時, 才會 return a
,因此 -(EXP5)
要等於 0 才有機會, EXP5 = a < b 。a < b
時,根據 XOR 的特性,((EXP4) & -(EXP5))
內應該要有包含 a ^ b
的部分,才能再 a ^ (a ^ b)
後 return b
,EXP4 = a ^ b 。以下為 64 位元 GCD (greatest common divisor, 最大公因數) 求值函式:
可改寫為:
u
, v
是否都為偶數,並紀錄 shift 的次數。u
其中二的因數提出來。v
變為 0 為止,因此 COND = v!=0
,將其簡化符合Linux的風格,COND = v。return
剩下不為 0
的數字,RET = u << shift。在影像處理中,bit array (也稱 bitset) 廣泛使用,考慮以下程式碼: