浮点除法的软件实现,舍入问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浮点除法的软件实现,舍入问题相关的知识,希望对你有一定的参考价值。
作为一个学习项目,我使用c ++在软件中实现浮点运算(add,sub,mul,div)。目标是更加熟悉浮点行为的底层细节。
我试图将我的处理器操作与精确位匹配,这意味着IEEE 754标准。到目前为止,它一直运行良好,添加,子和多种行为完美,我在大约1.1亿个随机操作上测试它,并获得与处理器硬件相同的结果。 (虽然没有考虑边缘情况,溢出等)。
在那之后,我开始转向最后一次操作,师。它工作正常并达到想要的结果,但有时,我得到最后一个尾数位错误,而不是四舍五入。我有点难以理解为什么。我一直在使用的主要参考是约翰·法里尔的精彩演讲(时间戳是在它显示如何圆形的时候):
https://youtu.be/k12BJGSc2Nc?t=1153
这种四舍五入对于所有的操作都非常有效,但是给了我这个部门的麻烦。让我举个具体的例子。我试图将645.68011474609375除以493.20962524414063
我得到的最终结果是:
我的:0-01111111-01001111001000111100000
c ++ _:0-01111111-01001111001000111100001
你可以看到除了最后一点之外的所有东西都匹配。我计算该部门的方式是基于这个视频:https://www.youtube.com/watch?v=fi8A4zz1d-s
在此之后,我计算了尾数精度24位(隐藏的一个+ 23尾数)的28位和保护的3位,圆形粘性以及可能的移位的额外一位。使用视频算法,我最多可以得到1的归一化移位,这就是为什么我在末尾有一个额外的位,以防在规范化中移入,因此将在舍入中可用。现在这是我从除法算法得到的结果:
010100111100100011110000 0100
------------------------ ----
^ grs^
|__ to be normalized |____ extra bit
如你所见,我在第24位获得0,所以我需要向左移动一个以获得正确的标准化。这意味着我会得到:
10100111100100011110000 100
根据John Farrier的视频,在100 grs位的情况下,如果尾数的LSB是1,我只会归一化。在我的情况下是零,这就是为什么我不对我的结果进行舍入。
我有点迷失的原因是我确信我的算法正在计算正确的尾数,我已经用在线计算器对其进行了双重检查,舍入策略适用于所有其他操作。此外,以这种方式计算会触发归一化,最终产生正确的指数。
我错过了什么吗?某个小细节?
令我感到奇怪的一件事是粘性位,在加法和乘法中你得到不同程度的移位,这导致粘性位触发的机会更高,在这种情况下,我只移动一个最大值粘性位不是很粘。
我希望我提供了足够的细节来解决我的问题。在这里你可以找到我的部门实现的底部,有点填充我用于调试的打印,但应该知道我在做什么,代码从第374行开始:
https://gist.github.com/giordi91/1388504fadcf94b3f6f42103dfd1f938
PS:同时我正在经历“科学家应该知道浮点数的一切”,以便看看我是否错过了什么。
从除法算法得到的结果是不合适的。你展示:
010100111100100011110000 0100
------------------------ ----
^ grs^
|__ to be normalized |____ extra bit
数学上精确的商继续:
010100111100100011110000 0100 110000111100100100011110…
因此,在您进行四舍五入的点处的残留超过½ULP,因此应该向上舍入。我没有详细研究你的代码,但看起来你可能刚刚计算了一个或两个有效数字1。实际上你需要知道残差是非零的,而不仅仅是它的下一位或两位是零。如果精确数学结果中该位置处或之外的任何位将为非零,则最终粘滞位应为1。
Footnote
1“重要”是首选术语。 “尾数”是对数的小数部分的遗留项。浮点值的有效位数是线性的。尾数是对数的。
以上是关于浮点除法的软件实现,舍入问题的主要内容,如果未能解决你的问题,请参考以下文章