contributed by < ccs100203
>
linux2020
浮點數除法程式: (fdiv.c)
假設 divop() 的第二個參數必為大於 0 的整數,而且不超過 int 型態能表達的數值上界。
利用遞迴的方式做除法。簡單來說程式會不斷的對被除數與除數同除 2,直到符合終止條件就會把 result
傳回去。但遇到 slots
(除數) 是奇數時,因為會在第 8 行視為偶數直接運算,所以藉由第 10 行補上誤差。
第 5 行的 if 就是作為遞迴的終止條件,當 slots
等於 1 時就會把當前的 orig
(也就是當前運算的 result
) return
回去上一層。而 orig == 0
的判斷是用來處理 orig
(被除數)是 0,或者是數字已經小到精度不夠,程式判定他為 0 時,也會結束並回傳。
第 8 行會直接做 並作為參數進入 recursive 的下一層。注意到他有對 od
做特別處理,也就是對 odd (奇數) 會特別做處理。當 slots
是奇數時會先做 +1 才除 2,也就是無條件進位。
但這樣子在 slots
是奇數時,數值會比實際答案小,因為除數無條件進位了,所以在第 9~10 行就是用來彌補奇數時的值,也就是會取近似值,不斷的把值透過遞迴呼叫加到 result
,維持除法精準度。
假設 ,程式會把 slots
為 1 的結果全部相加起來,得以近似 3.3333…
寫成數學式的話會變成:
換句話說,就是利用等比級數的方式去算出誤差值,會計算出 ,將這些結果累加求得最後的 result
數學推導,假設 A 除以 n
這段式子可以不斷延伸下去,就會發現符合等比級數的數學式
其中在 n 屬於偶數時會使用 的方式去處理,式子就會類似下列情況,還是符合推導
假設 float 為 32-bit 寬度,考慮以下符合 IEEE 754 規範的平方根程式
EXTRACT_WORDS
輸入 float,藉由 union 的方式得到 intINSERT_WORDS
輸入 int,藉由 union 的方式得到 floatx
is less than or equal 0In IEEE 754 arithmetic, a ÷ +0 is positive infinity when a is positive, negative infinity when a is negative, and NaN when a = ±0. The infinity signs change when dividing by −0 instead.
如果 x 是 -0 的話就直接 return
,其餘則是 -NaN
x
is NaN or +INF根據 IEEE 754 的規範,Exponent 的部分全為 1 時會是 INF 或 NaN。
程式遇到 NaN 或 +INF 時會直接 return
x
is denormalized根據 IEEE 754 的規範,Exponent 為 0 時,可能遇到 subnormal 的情況
m
代表的就是 Exponent 的部分,如果 m
是 0,那程式會強制 normalize,會從 找最高位的 1,不斷對 往左 shift,一直到補進了 normalized 的 1,再將 shift 多少位數從 Exponent 的地方扣掉。
x
is normalized and Greater than 0這時候的 x
一定是 normalized 的數字並且大於 0。
- m -= 127
是把 bias 的部分扣除,得到真正的 Exponent
- ix0
存放的是 也等同
- 再來會做 m >>= 1
,意即 ,若 m
是奇數的話則會將多除掉的部分補到 ix0
內,所以才會做 ix0 += ix0
。
再來的部分就是做 sqrt,關於直式開 2 次方根,參考 Binary numeral system (base 2) 以及 直式開二次方根(page 2~5) 的做法。
解說 while loop 運作原理:
ix0
每兩個 bit 劃分為一組r
(當前處理的 bit) 與 s0
(直式左邊的數字) 相加存入 t
ix0 >= t
則從 ix0
扣掉 t
,q
(商) 則會增加 r
。而根據直式運算 2 次方根的規則,s0
應更新為上次 s0
+ 2 * r
,由於 t = s0 + r
,故程式內的寫法成立。ix0 < t
或執行完上述第 3 點,在直式規則中應一次從 ix0
新增兩個位數來處理,但這裡利用做 r >>= 1
以及 ix0 += ix0
,恰巧符合運算規則,能夠接著運算 ix0
下兩個 bit。這樣的好處是不需要在 ix0 < t
時對 s0
做額外補 0 的動作,並且也不用移動 s0
來對齊下一步的 ix0
。在 q
上也會因為 r
一次只往右 shift 1,符合其移動規則,不須額外調整。參考 Rounding、Rounding modes、Rounding rules
我想程式是利用 one
與 tiny
的運算去判斷現在的系統屬於哪種 Rounding Mode,根據當前的 rounding mode 做出符合規範的 rounding。
one - tiny < 1.0
,代表當前的 mode 不會做進位,所以不需要特別處理 q
,因為之後往右 shift 就會自動捨去one - tiny >= 1.0
,代表當前的 mode 會進位,但要判斷屬於無條件進位或是四捨五入
one + tiny > 1.0
可以知道系統屬於無條件進位,所以直接進位,做 q += 2
one + tiny <= 1.0
可以知道系統屬於四捨五入,那只會在 q & 1
為 1 的時候才會進位r
是從第 25 位開始算,所以 q
需要往右 shift 1 才能夠對齊 IEEE 754 規範中 的位置。m
(Exponent) 往左 shift 23,將他放在 IEEE 754 規範的位置。TODO
LeetCode 829. Consecutive Numbers Sum
給定一個正整數 ,問 能寫成多少種連續正整數之和,例如 可寫成 ,或 。
我看不懂題目上的推導敘述,所以重新從等差數列的方法去理解程式。
程式的作法會在每一次的迴圈做 x += 1 - i
然後再去判斷 x
能不能整除 i
i
是從 2 開始的)i
即為程式內的 i
,代表輸入的數字 N
可以相等於被 i
個連續數字累加n
則是代表連續數值累加中的第一個數字。1-i |
-0 | -1 | -2 | -3 | -4 | -5 |
---|---|---|---|---|---|---|
i |
1 | 2 | 3 | 4 | 5 | 6 |
n |
n | n+1 | n+2 | n+3 | n+4 | n+5 |
當 i
為 2 的時候,代表 ,而 的部分藉由 1 - i
扣掉了,所以實際上是判斷 是否為 0 (可否整除),這樣便可以判別是否能由 2 個連續數字累加為 。
再來當 i
為 3,代表 ,新的 也在這次的 1 - i
扣掉, 則是在上一次的迴圈就扣掉了,所以判斷式變成 是否為 0。從這邊我們可以往後推論每個 i
的情況,而迴圈一直執行到 i >= x
會結束,因為 x
此時無法繼續扣除 1 - i
,就算兩者相等扣完之後 x
也只剩下 1,不可能整除 i
。
程式內的 i
是從 2 開始的,原因在於 i
等於 1 是絕對會成立的情況,所以節省了一次計算。