MPFR - 添加后精度损失

MPFR - Loss precision after addition

首先,抱歉,如果这个问题看起来 "silly",因为我是 MPFR 的新手,哈哈。

我有两个精度为 1024 的 mpfr_t 变量,它们存储了 0.2 和 0.06 的值。

但是当我添加这些变量时,事情出错了,结果(也是一个 mpfr_t 变量)的值为 0.2599999...

这很奇怪,因为 MPFR 库应该保持精度(不是吗?)。

你能帮我解决这个问题吗?非常感谢,提前这么多。

MPFR 数字以二进制(基数 2)表示。在这个系统中,唯一可以精确表示的数字具有 N·2k 的形式,其中 Nk 是整数。 0.2 = 1/5 和 0.06 = 3/50 都没有这种形式,因此它们的近似值有一些小误差。当您添加这些变量时,您会看到此错误的结果(加法运算中可能还会出现另一个错误,因为在二进制中这些数字有许多非零数字,这与十进制不同)。

此问题与以下描述的问题相同:Is floating point math broken?

编辑:

回答评论"Is there a way to avoid this situation?"中的问题,不,在实践中没有办法避免这种情况,除非在非常特殊的情况下。例如,如果您所有的数字(每个中间操作的输入和结果)都是十进制数,可以用足够小的数字表示,您可以使用十进制算术(但 MPFR 不能这样做)。在某些情况下,计算机代数系统可能会有所帮助。还有iRRAM……待会儿再说。

但是,有一些解决方案可以尝试隐藏数字错误问题。您需要估计计算值的最大可能误差。通过错误分析,您可以获得严格的界限,但这可能很困难或需要时间。请注意,严格界限通常是悲观的,但如果您使用任意精度(例如使用 MPFR),则问题不大。可以使用区间算法动态地进行分析(仍然是悲观的,甚至更糟)。但也许一个简单的估计对你来说就足够了。一旦您估计了最大误差:

  • 对于输出,选择显示的位数,使误差小于最后显示的数字的权重。
  • 对于不连续函数(例如等式测试、floor、ceil):如果计算值与不连续点之间的距离小于最大误差,则假定实际值等于不连续点。请注意,这只是一种启发式方法,但如果它失败了(这可能会被忽视并且可能会使您的估计无效),这意味着您没有以足够的精度进行计算。

注意:MPFR 不会为您做那件事。但是您可以编写代码来考虑这些规则。

基于 MPFR 的 iRRAM 封装可以以严格的方式跟踪错误(例如使用区间算法)并且 自动 以更高的精度重做所有计算如果它注意到准确度太低。然而,如果某些数学结果是一个不连续点,iRRAM 将无济于事。特别是,它不能提供严格的相等性测试。

最后,我建议您看一下 Goldberg 的论文 What Every Computer Scientist Should Know About Floating-Point Arithmetic,尤其是 取消 的概念。