在std::remainder()调用双精度体后检测零

Detect zero after std::remainder() call on doubles

本文关键字:检测 双精度 std remainder 调用      更新时间:2023-10-16

我有这样的代码:

double a = remainder(92.66, 0.01);
double b = remainder(92.87, 0.01);

结果是a = -5.33948e-15b = -2.61423e-15

这里的答案显然是零,如果我把两个数都乘以100,然后做整数模数,它将是。但我想用双精度来做这个。问题是,余数返回一个比DBL_EPSILON大的数字-那么确定ab是否为零的正确(最佳近似)方法是什么?

DBL_EPSILON是1.0可以加的最小的数量。如果您的数字大于1.0,那么该数字的epsilon也将成比例地大。只需将DBL_EPSILON乘以数字即可获得阈值。

double a = remainder(92.66, 0.01);
if (a <= DBL_EPSILON * 92.66)
    a = 0.0;

比较浮点数是否相等是困难的。特别是和0比较。这是直接从一篇有用的博客文章中复制的等式函数,你应该阅读一下。根据需要将float替换为double,或者创建模板。

bool AlmostEqualRelativeAndAbs(float A, float B,
            float maxDiff, float maxRelDiff)
{
    // Check if the numbers are really close -- needed
    // when comparing numbers near zero.
    float diff = fabs(A - B);
    if (diff <= maxDiff)
        return true;
    A = fabs(A);
    B = fabs(B);
    float largest = (B > A) ? B : A;
    if (diff <= largest * maxRelDiff)
        return true;
    return false;
}

现在需要计算maxDiffmaxRelDiff参数的拟合值。它们取决于你执行的计算有多不稳定。可能不会比几个DBL_EPSILON多多少。

你的问题是你的数字不能被机器精确地表示。您可以在代码中看到数字0.01、92.66和92.87。计算机看不到它们。它看到机器可以表示的最接近0.01、92.66和92.87的数字。

当你要求计算余数时,它会计算这些表示的余数,而不是你指定的原始数字的余数。

您必须根据您的应用程序使用多种方法中的一种来比较浮点数与零。