contributed by < BensonYang1999
>
由於兩個無號整數相加時有可能會發生溢位,因此考慮使用以下不同方法
其中的 a & b & 1
是用來補償小數進位的部份,原理為判斷兩數是否都是奇數
以下面的例子為例
a=5, b=7 => a>>1=2, b>>1=3 => added=5
因此需要補加上1,才會得到最終的數值6
在你所不知道的 C 語言:數值系統篇有提到利用 bit-wise operator 實作加法器 x + y = x ^ y + ( x & y ) << 1
由加法式可以進階推導出 (x + y) / 2 = (x & y) + ((x ^ y) >> 1
因此可以利用上式實作兩數平均
延伸問題:
移動平均(Moving average),又稱滾動平均值、滑動平均,在統計學中是種藉由建立整個資料集合中不同子集的一系列平均數,來分析資料點的計算方法。
移動平均通常與時間序列資料一起使用,以消除短期波動,突出長期趨勢或周期。短期和長期之間的閾值取決於應用,移動平均的參數將相應地設置。例如,它通常用於對財務數據進行技術分析,如股票價格、收益率或交易量。它也用於經濟學中研究國內生產總值、就業或其他宏觀經濟時間序列。
利用 gcc 中的
-S
指令可以輸出組合語言,額外加上-O3
可確保編譯啟開啟最高等級的最佳化
方法1
方法2
方法3
利用diff比較方法1與方法2的差別
利用diff比較方法2與方法3的差別
使用 diff -u
命令,更好觀察。另外,方法 1
應該補充數值範圍的檢查程式碼。
考慮 a < b
及 a >= b
兩種情況
當 a < b
& 右邊會等於 0xFFFFFFFF ,即可以省略 & -(a < b)
這部份
剩下的部份 a ^ (a ^ b)
可進一部簡化為 b
因此最後的算式 => return b;
當 a >= b
& 右邊會等於 0 ,代表 ((a ^ b) & 0)
會等於0
因此最後的算式 => return a;
延伸問題:
請在 Linux 核心原始程式碼中,找出更多類似的實作手法。請善用 git log 檢索。
討論無號整數的 min
,可以透過簡單修改 max
的程式碼達成
有號整數的部份,由於此運算方式可以適用於有號數,因此只需修改變數型態即可
參考本題的註解
從第14行開始沒有在註解中說明,查閱網路資料後可得知其為 Euclid's algorithm ,其結束條件為兩數相等,因此判斷 COND
的空格應該填入 v
,也就是被減數不等於0時
而最後RET的地方需要把一開始同除的2次方給補回去,因此應該是 u << shift
延伸問題:
查閱 GNU 說明書,得知本函數可以取得變數中從最低位數有幾的0,也就可以判斷其因數包含2的多少次方,因此可以用來加速原本使用 while 判斷的地方,也就是說程式可以修改為
仔細觀察後發現,發現第4~8行其實可以整並,改寫為
完整程式碼
利用傳入大數的方式,讓執行時間變長,可以明顯比較效能差異
我利用 linux 內建指令 time
進行計時,並帶入 uint64 的最大值 18446744073709551615 與其 -1 ,結果如下
兩者時間都太短了,因此改變方式,使用計算相同數字多次計時,結果如下
大概加快 25%
依照本題的提示,考慮使用 -bitwise
,由於再 C 語言裡面負號的計算方式是將所有bits反轉後再加 1 ,因此可以利用此特性,與 bitwise
做 & 運算,及可以達成找到最低的 1 的位置,即本題的要求
延伸問題: