作者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://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1633033894.A.470.html
2F:推 chuegou: 我直觉会用强制转型做耶 10/01 19:43
3F:推 LPH66: 有的时候转型的低阶指令会不好做, 像一楼的就是 SIMD 10/01 21:13
4F:→ LPH66: 用一加一减的做法在 SIMD 指令比写转型好做 10/01 21:14
5F:→ LPH66: 四舍五入这回事会直接变成硬体逻辑在处理 10/01 21:15
6F:推 chuegou: 阿阿 我忘了要处理四舍五入XD 10/01 23:28
7F:推 chrisdar: 12582912dec=0-10010110-10000000000000000000000single 10/11 07:30
8F:→ chrisdar: 新的问题是 为什麽Exponent是10010110 XD 10/11 07:31
9F:推 chrisdar: 3*2^22=12582912,3*2^51=6755399441055744 10/11 07:37
10F:→ chrisdar: 3*2^63=27670116110564327424 10/11 07:38
11F:→ chrisdar: 为什麽老是 3*2^(Mantissa-1) XD 10/11 07:41
12F:推 chrisdar: 没事 我没看到最後一段 请忽略 10/11 07:43