contributed by < PinLin
>
1
(a >> 1) + (b >> 1) + (EXP1)
即是對兩個無號整數取平均值的結果,前面的 a >> 1
和 b >> 1
可以被理解為「除以二後無條件捨去至整數位」,後面的 EXP1
則是我們目前缺少的部分。
將 a
和 b
分別帶入數字,得到了下表:
a |
b |
(a >> 1) + (b >> 1) |
expected |
---|---|---|---|
2 | 2 | 2 | 2 |
2 | 3 | 2 | 2 |
3 | 2 | 2 | 2 |
3 | 3 | 2 | 3 |
我們發現當兩者都是帶入奇數時,a >> 1
和 b >> 1
將各自捨去 0.5,相加後便比我們期望得到的答案還少 1。
因此在這裏 EXP1
應作為一個補償:在 a
與 b
皆為奇數時為 1
,否則為 0
,以 (a & 1) & (b & 1)
表示,最後簡化為 a & b & 1
。
這樣的形式讓我想到了加法器的操作,只是要求平均需要多一個除以二的操作,嘗試推導了一下:
a + b = (a ^ b) + ((a & b) << 1)
(a + b) / 2 = ((a ^ b) + ((a & b) << 1)) >> 1
(a + b) / 2 = ((a ^ b) >> 1) + (a & b)
最後得證 EXP2
為 a & b
,EXP3
為 a ^ b
。
2
首先我們知道這個函式的輸出只有可能是 a
或是 b
,假設 a ^ ((EXP4) & -(EXP5))
的結果是 a
,那麼 (EXP4) & -(EXP5)
就必須是 0
;反之,若結果是 b
則將運用到 XOR 的特性,(EXP4) & -(EXP5)
的結果必須是 a ^ b
。
根據題目的限制,推斷 EXP4
為 a ^ b
,而當 b > a
時 -(EXP5)
應為 -1
,否則應為 0
,推得 EXP5
即為 a < b
。
只需將參數 a
、b
和回傳值型別改為 int32_t
即可,因為 a
和 b
皆為有號數,進行的便是有號數的比較。
3
這個函式首先在第 5~8 行中透過檢查 LSB 的方式判斷 u
跟 v
是否是 2 的倍數,是則將兩者各除以二,並將除以二的次數記錄在 shift
中。
接著在第 11~21 行中執行類似輾轉相除法的流程來嘗試找出兩者的最大公因數,由於 u
會等於操作前的 v
,v
會等於操作前的 u - v
,所以 COND
在此應該判斷 v
是否為 0
。
最後離開迴圈之後需再將 u
的值左移 shift
次,便是 u
跟 v
真正的最大公因數。
4
這段程式首先將 bitmap
一塊一塊取出作為 bitset
,接著透過 EXP6
表示式找出 bitset
目前最低位元的 1
並紀錄到 t
。
研究了一下題目提到的 -bitwise
特性,嘗試列出幾個數字和它二的補數:
發現將一個數字和其二的補數做 AND 運算,便可找出該數字最低位元的 1
,因此 EXP6
應為 bitset & -bitset
。
5
這段程式嘗試求出給定分數的比值,主要分成求出整數和小數的部分。
整數部分直接使用整除除法求得 division
和 remainder
,接著小數的部分:
remainder
,於是先配置了一段大小為 size * sizeof(struct list_head)
的空間並初始化,作為 hash table 的 buckets。remainder
不為 0
則進入迴圈,首先檢查 hash table 是否存在目前的 remainder
。
remainder
不可能等於 0
,所以至此直接回傳結果。remainder
等於 0
,便將小數的部分整併至整數的部分並回傳結果。6
這段程式利用到 struct
會以成員中最大的對齊長度來對齊所有成員的特性,因為成員 char c
對齊長度只有 1
,所以只要將目標型別帶入 t
後計算 struct
開頭到成員 t _h
的長度,就可以知道型別 t
所需的對齊長度。
7
這段程式藉由修改 fmt
的內容去控制輸出,而 fmt
的內容又是在第 17 行中透過 "FizzBuzz%u"
根據不同條件使用不同的起始位置和長度複製過去的。
根據 div3
和 div5
值的不同,列出了下表顯示我們期望的 fmt
,以及其所需的 length
和起始位置:
div3 |
div5 |
起始位置 | length |
fmt |
---|---|---|---|---|
0 | 0 | 8 | 2 | %u |
0 | 1 | 4 | 4 | Buzz |
1 | 0 | 0 | 4 | Fizz |
1 | 1 | 0 | 8 | FizzBuzz |
但是我發現在第 17 行中間的 &"FizzBuzz%u"[(9 >> div5) >> (KK3)]
在 div3
和 div5
皆為 0
時會將字串起始位置訂在 9
,這樣便無解了。所以我認為應該把此處的 9
改為 8
才對。
為了控制 length
,KK1
和 KK2
應為 div3
和 div5
。而為了控制起始位置,KK3
應該為 div3 << 2
。