contributed by < hankluo6
>
1
將兩數 分成,整數部分及小數部分:
就能列出算式:
求出 與 皆為奇數時需要加一,EXP1 = a & b & 1
。
根據加法器原理可得:
所以:
得出 EXP2 = a & b
,EXP3 = a ^ b
。
TODO
檢查輸入的數值是否合法,_precision
及 _weight_rcp
必須為編譯時期能決定的常數、_precision
不能大於 30、_weight_rcp須為 2 的倍數,因為
add是用 shift 實作,最後初始化
internal`。
read
數值時沒有將小數部分印出。
根據目前 internal
的數值分成兩部分:
internal > 0
:internal <= 0
2
EXP5
為 boolean 運算,可知結果只可能為 0x0000
及 0xFFFF
,當為 0x0000
時,回傳 a ^ 0 = a
,當為 0xFFFF
時,回傳 a ^ EXP4
。
所以當 a > b
時,EXP5 = 1
才能滿足條件,得出 EXP5 = a > b
。
而當 b >= a
時,a ^ EXP4 = b
,可得 EXP4 = a ^ b
(根據 XOR 的特性 a ^ a = 0
)。
改寫〈解讀計算機編碼〉一文的「不需要分支的設計」
只需在判斷大小的 diff >> 31
加上 NOT
運算,相反大小判斷便能改成回傳 max
。
這實作僅在 INT32_MIN
<= (a - b) <= INT32_MAX
成立時,才會發揮作用。
3
根據輾轉相除法 的演算法可求出答案:
COND = v
RET = u << shift
在每次回圈中,持續保持 v
為最小值,當 v
為 0 時,表示無法再提出公因數,便跳出迴圈。而在函式剛開始時,透過迴圈將最大公因數的 2 的次方提出,記錄在 shift
當中,故最後回傳時需再將次方乘回去。
__builtin_ctz
改寫 GCD在 x86_64 上透過 __builtin_ctz 改寫 GCD,分析對效能的提升;
效能分析:
隨機產生 64 bit 的資料,並測量 1000000 次的運行時間
gcd64 | __builtin_ctz gcd64 |
---|---|
0.667711 s | 0.425873 s |
可發現效能有有效的提昇,約提昇 秒。
4
根據提示找出目前最低位元的 1 即為 bitset & (-bitset)
,因為 -bitset = ~bitset + 1
,~bitset
將所有位元反轉,+1
會將位元為 1 的部分 (原本為 0) 往 MSB 進位,直到位元為 0 (原本為 1) 的位元,AND 運算後該位元為唯一與 bitset
相同的位元,故能找到最低位元的 1。
ctz/clz
效能比較其中 bit ratio 為 bitmap 中為 bit 為 true
的比率,可以發現原本的方法不管 bit 數多寡,其運行效率大致相同;而使用 ctz
的方法會受到 bit 數量,當 bit 數量越多,就執行越多次 __builtin_ctzll
,在 bit 比率大約 50% 時為分水嶺。故可以得出結論:bit 比率小於 50% 時 __builtin_ctzll
效率較好,反之則為原本的方法較好。
5
根據長除法演算法,可利用當前餘數 求出下個位數的數字及對應的餘數。程式內的 char *p
即指向一個 1024 bytes 空間的指標,在迴圈內會紀錄對應的商。
當出現重複的小數數值時,表示構成循環小數,便能直接從 hash table 中取出剩下的數字,並加上 (
以及 )
後回傳。
所以 MMM
應為將有存放小數數字的節點加入到 hash table 中的操作,即為 list_add
,EEE
決定該節點插入的是 hash table 中的第幾個 bucket,從 find
中可以知道 hash function 為 number % size
,所以 EEE
為 &heads[remainder % size]
,當找到重複的數字時,pos >= 0
進到條件式中,while
迴圈將非循環的小數部分存到 p
中,而 node->index
紀錄數字為小數點後第幾個數,所以 PPP
應為 pos--
。
6
根據你所不知道的 C 語言:記憶體管理、對齊及硬體特性在成員位址不能整除時,會自動加入 padding 做 alignment。&((struct { char c; t _h; } *)0)->_h
取出 _h
成員相對於 0 的位址,相減便能求出 alignment 的位址。