contributed by <HScallop
>
linux2022
EXP1 = ?
a & b & 1
EXP2 = ?
a & b
EXP3 = ?
a ^ b
當初這兩題在上課有回答出來。思考這兩題的時候,覺得很類似於以前上邏輯設計的時候 full-adder 的作法。
在 EXP1 的程式碼因為先各自 >> 1 /2
,所以除了最小位數外,不需要再考慮 propagation ,而 EXP2, EXP3 就像是經典的 full-adder 加法後,再 >> 1 /2
的結果。
從上圖可以看出 sum 就是 a ^ b propagation 則是 a & b 。
EXP4 = ?
a ^ b
EXP5 = ?
a < b
可以參考 解讀計算機編碼 - 不需要分支的設計想法上是利用 diff = a - b
還有 (diff >> 31) 判斷 diff < 0
,如果 diff < 0
b
就會被加上 (a - b)
轉換成 a
。
回到測驗本測驗的問題,還是一樣要在 b > a
時,把 a
轉換成 b
。跟前面不一樣的地方是這邊想用 XOR
來實作。
所以推測在 b > a
時,會用 a ^ a ^ b
把 a
變成 b
。
COND = ?
v
RET = ?
u << shift
line 4
u
或v
會有一個是0
所以u | v
會是非0
的另外一個數。
line 6-8
!((u | v) & 1)
這邊的AND 1
就是最小一位數的 mask 只要u
或v
有一個是奇數,就會跳出迴圈。
line 9-21
while loop on line 9: u is even and v is odd.
while loop on line 12: u is odd and v is even.
line 11 開始的 do while 迴圈是輾轉相除法的實作,比較特別的是他會把相減之後的數留在v
,繼續用 u is odd and v is even 的規則簡化。
所以這邊COND
是輾轉相除法的終止條件。
而RET
是最後結果,需要注意剛剛照著規則提出的 2 要乘回來。
改寫的程式碼:
EXP6 = ?
bitset & -bitset
其實在原本的題目中就有說明第 9 行的作用是找出最小的位數的 1
,這邊利用了 2's complement 的特性。
e.g.
2's complement:
比較可以發現,只會有最小一位的 1
和更小位數的 0
會一樣,其他位置都已經被反轉。
第一段程式碼第 8 行的迴圈被取代了,運用 __builtin_ctzll
,不需要一位一位檢查。