我使用相对比较描述here。 我有两个双打。首先是计算结果:
double d1(callComputation() );
第二个定义如下:
double d2(0.009);
我对aboutEqual的实现返回false,这是正确的,因为:
std::printf("d1 = %25.20f\n", d1);
打印:
d1 = 0.00900000000000011902
和
std::printf("d2 = %25.20f\n", d2);
打印:
d2 = 0.00899999999999999932
我希望d2大致表示如下:
0.00900000000000011239 or 0.00900000000000000000 etc
,并且d1和d2的比较结果为真。但即使近似等于也无法正常工作。在这种情况下应该如何比较? 我不需要高精度的计算,但显然我对此感兴趣 计算结果的稳定性。也许点后固定的数字量(例如两个)将有助于解决此问题?
答案 0 :(得分:1)
首先,它是最接近.0009
的值,可以表示为双精度IEEE浮点数。
每个浮点运算都会导致舍入运算。基于Epsilon的策略不能确定两个浮点计算是否表示“相同”的实数。
确定在通常情况下两次计算是导致还是不导致相同的实数实际上是不可计算的;您可以减少暂停。
确定它们是否相等的“最佳”,最昂贵的通用方法是区间数学。用代表间隔的一对双打代替双打。在每次计算中,请确保将上一个双精度值的结果四舍五入,将下一个双精度值四舍五入(并且在进行除法/减法运算时,请确保不要翻转间隔,因为除法/减法运算会单调递减;对于乘以底片)。如果将包含0的间隔除以包含0的间隔,请确保两个值都变为NaN,并且如果将包含0的间隔除以结果,则结果为+ inf到-inf。
区间数学存在一些问题;它很昂贵(显着超过2倍),需要用控制舍入/舍入的原始运算替换每个原始运算,并且您会发现,在进行了不平凡的数学运算后,间隔最终变得非常大。
传统IEEE舍入产生的值通常更接近于您想要的值,因为它实际上是在每次迭代中随机舍入。如果掷硬币10,000次,您将获得一个均值为5000,方差为2500,标准差为50的随机值;因此97%的时间是4900至5100,99%+是4850至5150。每个舍入操作实际上是一个硬币加上+或-eplsion / 2(实际上更好;它的值介于+/-之间) epsilon / 2被选为最小的),因此在10k ops之后,可能的误差小于+/- 75 * epsilon。同时,间隔数学将指出该特定误差为+/- 10000 epsilon。
您需要更大的epsilon。