当两个相等的双精度的相对比较不起作用时,我该怎么办?

What should I do when relative comparison of two equal doubles doesn't work?

本文关键字:不起作用 比较 相对比 我该怎么办 相对 双精度 两个      更新时间:2023-10-16

我使用相对比较,因为它在这里描述。 我有两个双打。其中第一个是计算结果:

double d1(callComputation() );

第二个定义如下:

double d2(0.009);

我对近似相等的实现返回错误,这是正确的,因为:

std::printf("d1 = %25.20fn", d1);

指纹:

d1 =    0.00900000000000011902

std::printf("d2 = %25.20fn", d2);

指纹:

d2 =    0.00899999999999999932

我预计 d2 将大致表示如下:

0.00900000000000011239 or 0.00900000000000000000 etc 

并且比较 d1 和 d2 的结果将为真。但即使大约平等也不合适。在这种情况下,我应该如何比较? 我不需要高精度的计算,但显然我对 计算结果的稳定性。也许点后固定数量的数字(例如两个(将有助于解决这个问题?

首先,这是最接近.0009的值,可以表示为双精度 IEEE 浮点数。

每个浮点运算都可能导致舍入运算。 基于 Epsilon 的策略对于确定两个浮点计算是否表示"相同"的实数并不可靠。

在一般情况下,确定两个计算是否产生相同的实数实际上是不可计算的;您可以将 Halt 减少到它。

确定它们是否相等的"最佳"最昂贵的通用方法是区间数学。 用一对代表间隔的双打代替你的双打。 在每次计算中,确保上双精度的结果向上舍入,下双精度的结果向下舍入(除法/减法时,请确保不要翻转区间,因为除法/减法是单调递减的;乘以负数也是如此(。 如果将包含 0 的区间除以包含 0 的区间,请确保两个值都变为 NaN,如果除以包含 0 的区间,则结果为 +inf 到 -inf。

区间数学有一些问题;它很昂贵(远远超过2倍(,需要用控制向上/向下舍入的操作替换每个基元运算,你会发现在大量的数学运算之后,区间最终变得惊人地大。

传统的 IEEE 舍入生成的值通常更接近您想要的值,因为它实际上随机舍入每次迭代。 如果您掷硬币 10,000 次,您将获得一个平均值为 5000、方差为 2500、标准差为 50 的随机值;所以97%的时间你会在4900到5100,99%+在4850到5150。 每个舍入操作实际上是一枚硬币添加 + 或 - epplsion/2(实际上更好;它添加一个介于 +/- epsilon/2 之间的值,被选为最小的值(,因此在 10k 操作后,可能的误差小于 +/- 75*epsilon。 同时,区间数学将声明某个误差为 +/-10000 epsilon。

TL;博士

你需要一个更大的厄普西隆。