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

Mar*_*ano 9 c++ algorithm floating-point

作为一个学习项目,我使用c ++在软件中实现浮点运算(add,sub,mul,div).目标是更加熟悉浮点行为的底层细节.

我试图将我的处理器操作与精确位匹配,这意味着IEEE 754标准.到目前为止,它一直运行良好,添加,子和多种行为完美,我在大约1.1亿个随机操作上测试它,并获得与处理器硬件相同的结果.(虽然没有考虑边缘情况,溢出等).

在那之后,我开始转向最后一次操作,师.它工作正常并达到想要的结果,但有时,我得到最后一个尾数位错误,而不是四舍五入.我有点难以理解为什么.我一直在使用的主要参考是约翰·法里尔的精彩演讲(时间戳是在它显示如何圆形的时候):

https://youtu.be/k12BJGSc2Nc?t=1153

这种四舍五入对于所有的操作都非常有效,但是给了我这个部门的麻烦.让我举个具体的例子.我试图将645.68011474609375除以493.20962524414063

我得到的最终结果是:

我的:0-01111111-0100111100100011110000 0

c ++ _:0-01111111-0100111100100011110000 1

你可以看到除了最后一点之外的所有东西都匹配.我计算该部门的方式基于以下视频:https: //www.youtube.com/watch?v = fi8A4zz1d -s

在此之后,我计算了尾数精度24位(隐藏的一个+ 23尾数)的28位和保护的3位,圆形粘性以及可能的移位的额外一位.使用视频算法,我最多可以得到1的归一化移位,这就是为什么我在末尾有一个额外的位,以防在规范化中移入,因此将在舍入中可用.现在这是我从除法算法得到的结果:

 010100111100100011110000 0100
 ------------------------ ----
 ^                        grs^
 |__ to be normalized        |____ extra bit
Run Code Online (Sandbox Code Playgroud)

如你所见,我在第24位获得0,所以我需要向左移动一个以获得正确的标准化.这意味着我会得到:

10100111100100011110000 100
Run Code Online (Sandbox Code Playgroud)

根据John Farrier的视频,在100 grs位的情况下,如果尾数的LSB是1,我只会归一化.在我的情况下是零,这就是为什么我不对我的结果进行舍入.

我有点迷失的原因是我确信我的算法正在计算正确的尾数,我已经用在线计算器对其进行了双重检查,舍入策略适用于所有其他操作.此外,以这种方式计算会触发归一化,最终产生正确的指数.

我错过了什么吗?某个小细节?

令我感到奇怪的一件事是粘性位,在加法和乘法中你得到不同程度的移位,这导致粘性位触发的机会更高,在这种情况下,我只移动一个最大值粘性位不是很粘.

我希望我提供了足够的细节来解决我的问题.在这里你可以找到我的部门实现的底部,有点填充我用于调试的打印,但应该知道我在做什么,代码从第374行开始:

https://gist.github.com/giordi91/1388504fadcf94b3f6f42103dfd1f938

PS:同时我正在经历"科学家应该知道浮点数的一切",以便看看我是否错过了什么.

Eri*_*hil 7

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

 010100111100100011110000 0100
 ------------------------ ----
 ^                        grs^
 |__ to be normalized        |____ extra bit
Run Code Online (Sandbox Code Playgroud)

数学上精确的商继续:

 010100111100100011110000 0100 110000111100100100011110…
Run Code Online (Sandbox Code Playgroud)

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

脚注

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