浮点除法的软件实现,舍入问题

问题描述 投票:9回答:1

作为一个学习项目,我使用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:同时我正在经历“科学家应该知道浮点数的一切”,以便看看我是否错过了什么。

c++ algorithm floating-point
1个回答
7
投票

从除法算法得到的结果是不合适的。你展示:

 010100111100100011110000 0100
 ------------------------ ----
 ^                        grs^
 |__ to be normalized        |____ extra bit

数学上精确的商继续:

 010100111100100011110000 0100 110000111100100100011110…

因此,在您进行四舍五入的点处的残留超过½ULP,因此应该向上舍入。我没有详细研究你的代码,但看起来你可能刚刚计算了一个或两个有效数字1。实际上你需要知道残差是非零的,而不仅仅是它的下一位或两位是零。如果精确数学结果中该位置处或之外的任何位将为非零,则最终粘滞位应为1。

Footnote

1“重要”是首选术语。 “尾数”是对数的小数部分的遗留项。浮点值的有效位数是线性的。尾数是对数的。

© www.soinside.com 2019 - 2024. All rights reserved.