[心得] 浮点数取整讨论

楼主: mikemike1021 (mike)   2021-10-01 04:31:31
论坛版: 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 也可以看到
同样的结果
如果有任何错误或缺漏,再麻烦留言指正及补充了
作者: Chikei ( )   2021-10-01 17:21:00
作者: chuegou (chuegou)   2021-10-01 19:43:00
我直觉会用强制转型做耶
作者: LPH66 (-6.2598534e+18f)   2021-10-01 21:13:00
有的时候转型的低阶指令会不好做, 像一楼的就是 SIMD用一加一减的做法在 SIMD 指令比写转型好做四舍五入这回事会直接变成硬件逻辑在处理
作者: chuegou (chuegou)   2021-10-01 23:28:00
阿阿 我忘了要处理四舍五入XD
作者: chrisdar   2021-10-11 07:30:00
12582912dec=0-10010110-10000000000000000000000single新的问题是 为什么Exponent是10010110 XD3*2^22=12582912,3*2^51=67553994410557443*2^63=27670116110564327424为什么老是 3*2^(Mantissa-1) XD没事 我没看到最后一段 请忽略

Links booklink

Contact Us: admin [ a t ] ucptt.com