作者mikemike1021 (mike)
看板C_and_CPP
標題[心得] 浮點數取整討論
時間Fri Oct 1 04:31:31 2021
論壇版:
https://forum.community.tw/t/topic/172
新設立的論壇,也可當個人部落格的留言系統
程式碼的部分會上色,及顯示 latex
另外最近開放詢問分類,歡迎大家來試試看跟幫忙回答XD
這一篇是從巴哈上面的一篇
https://reurl.cc/MkNL1L 所提到的取整來討論,
我對於浮點數加法在硬體上怎麼運作以及加法時的有效位數等不是很明瞭,這裡也不考
慮 subnormal 等比較特殊的情形,如果有任何地方有講錯或者有東西可以補充的,再麻
煩留言指正或補充了,謝謝
```
float custom_round(float x) {
return (x + 12582912.0f) - 12582912.0f;
}
```
主要想法
是利用浮點數 (參考 wiki - Floating-point arithmetic) 其實只有有限位數來儲存
significand/mantissa (有效數字,尾數),加上一個數,使之小數部分無法被浮點數儲
存,再把該數減掉,即可得到取整後的結果。
討論(十進位)
這裡用十進位來進行討論,比較方便表示。假設我們的浮點數 mantissa 是 4 位 (存儲
3 位) ,即 1.abc * 10^x
- 例如要將 1.234 四捨五入,可以先加 1100 (1.1*10^3),
再把他減掉1.234 + 1100 = 1101.234 (實際值) -> 1.101*10^3 (只能存 3 位)
= 1101
1101 - 1100 = 1 (結果)
- 又或者 0.987
0.987 + 1100 = 1101.987 (實際值) -> 1.101*10^3 (只能存 3 位,至於是 1101
或 1100 可能要看硬體 = 1101
1101 - 1100 = 1
設定的數不一定要固定,只要讓加法後結果只能表示到整數部分即可
二進位及誤差
那二進位跟十進位的想法是一樣的。
誤差可能會根據硬體將加法結果變回浮點數儲存時,怎麼處理有關了
Compiler Explorer 的範例
https://godbolt.org/z/99c74oKW6
介紹可以看之前寫的這篇 -
https://forum.community.tw/t/topic/65
例如 10.5 + 12582912 會得到 12582922 而非 12582923
這邊是使用 rounding half down, 當 xxx.5 時會變成 xxx;而 round 是用正常的四捨
五入 - rounding half up,當 xxx.5 時會變成 xxx+1 (更多不同取整數的方法詳見
wiki - Rounding)
當使用 10.5000009537 這些方法就給出一樣的結果了
另外一種可能的誤差則是,當加完之後,浮點數能儲存的部分只到整數部分倒數第二位
(2^0 無法表示),導致在扣掉時就也無法弄回來了。
12582912?
那為何選擇 12582912 這我就不是很清楚了,但如果拿這個數字去查,會出現使用該數字
來將浮點數轉換成整數,那他是用 1.5 * (1 <<
#stored_mantissa_bits),在 float 的
話就是 1.5 * (1 << 23),而將 12582912 放入 Floating Point Converter 也可以看到
同樣的結果
如果有任何錯誤或缺漏,再麻煩留言指正及補充了
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 46.223.162.172 (德國)
※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1633033894.A.470.html
推 chuegou: 我直覺會用強制轉型做耶 10/01 19:43
推 LPH66: 有的時候轉型的低階指令會不好做, 像一樓的就是 SIMD 10/01 21:13
→ LPH66: 用一加一減的做法在 SIMD 指令比寫轉型好做 10/01 21:14
→ LPH66: 四捨五入這回事會直接變成硬體邏輯在處理 10/01 21:15
推 chuegou: 阿阿 我忘了要處理四捨五入XD 10/01 23:28
推 chrisdar: 12582912dec=0-10010110-10000000000000000000000single 10/11 07:30
→ chrisdar: 新的問題是 為什麼Exponent是10010110 XD 10/11 07:31
推 chrisdar: 3*2^22=12582912,3*2^51=6755399441055744 10/11 07:37
→ chrisdar: 3*2^63=27670116110564327424 10/11 07:38
→ chrisdar: 為什麼老是 3*2^(Mantissa-1) XD 10/11 07:41
推 chrisdar: 沒事 我沒看到最後一段 請忽略 10/11 07:43