【问题标题】:comparing double values in C比较 C 中的双精度值
【发布时间】:2012-07-31 19:09:37
【问题描述】:

我有两个双数组,比如说 A 和 B。我想将它们的结果与 7 个有效数字进行比较。下面的比较是否正确?

k = pow(10,7);
for(...)
{
 if(((int)A[i]*k)!=((int)B[i]*k))
 {
  ...
 }
}

【问题讨论】:

  • 测试一下,你会发现,它不是。
  • AT_Kiril_Kirov:你能举个例子吗?
  • @starter:您也可以尝试使用数字的科学记数法:k = 1e7; 它应该在编译时进行评估,而不是在运行时评估 pow()
  • @Constantinius pow(10,7) 可能会在编译时进行评估。不过1e7 是更好的选择。
  • 那些演员比你想要的更贴近。

标签: c


【解决方案1】:

为了比较双打,你可以使用这样的东西:

bool fequal(double a, double b)
{
    return fabs(a-b) < epsilon;
}

取自here

fabs 参考。

但请确保您了解potential pitfalls

【讨论】:

    【解决方案2】:

    不,这行不通。

    类型转换运算符的优先级高于乘法运算符。这意味着 A[i]B[i] 在乘以 1e7 之前将被转换为整数(并被截断)。 2.25 和 2.5 最终将等于您的代码。您可以通过将乘法放在括号中来解决此问题:(int)(A[i]*k)

    此外,由于您依赖截断而不是四舍五入,您最终可能会得到不正确的结果(取决于您的预期)。 1.0e-71.9e-7 将相等 (1 == 1),而 1.9e-72.1e-7 将不相等 (1 != 2)。我建议找到一个可以根据您想要的行为正确舍入的函数。

    此外,您的比较不涉及有效数字,它只是改变指数的值。在上面的示例中,只有 2 个有效数字,但是您的代码只会比较其中一个数字,因为指数的值为 -7。

    这里有一些代码可以满足你的需求:

    //create integer value that contains 7 significant digits of input number
    int adjust_num(double num) {
        double low_bound = 1e7;
        double high_bound = low_bound*10;
        double adjusted = num;
        int is_negative = (num < 0);
        if(num == 0) {
            return 0;
        }
        if(is_negative) {
            adjusted *= -1;
        }
        while(adjusted < low_bound) {
            adjusted *= 10;
        }
        while(adjusted >= high_bound) {
            adjusted /= 10;
        }
        if(is_negative) {
            adjusted *= -1;
        }
        //define int round(double) to be a function which rounds
        //correctly for your domain application.
        return round(adjusted);
    }
    
    ...
    
    if(adjust_num(A[i]) == adjust_num(B[i])) {
        ...
    }
    

    【讨论】:

    • 此外,值(尤其是缩放后)可能超出int 范围,然后转换为int 会产生实现定义的结果,通常是INT_MIN
    • @DanielFischer 是的,但这只是一个问题,因为 starter 如何将数字调整为 7 个有效数字。如果他做得正确,就不会有 32 位 int 溢出的可能性。
    • 是的,那是指OP的方法,而不是您的方法。您的代码中的一个问题是它不适用于负数 doubles 或 0(还有无穷大和 NaN)。风格问题:为什么是 adjusted/low_bound &lt; 1 而不是 adjusted &lt; low_bound
    • AT_Eric_Finn:谢谢,以上似乎工作正常。但如果我得到 -0.0000 或 0.00000 它表示它们不相等......
    • @DanielFischer 你是对的关于 0 和负值。我已经修改了代码来解决这个问题。我也同意风格问题。 Infinite 和 NaN 与将数字调整为具有一定数量的有效数字分开处理是有意义的。
    【解决方案3】:

    是的,但您必须进行一项更改。 尝试 (int)(A[i]*k) 以确保您的乘法首先执行。

    希望这会有所帮助。

    【讨论】:

      【解决方案4】:

      当您使用两个浮点值来确定它们理想情况下的值是否相等时,您应该对计算值之间的距离有一些估计(或者,最好是经过验证的界限)计算值相等。如果你有这样的界限,那么你可以执行这样的测试:“如果两个数字比误差界限更接近,则接受它们相等。”误差界限可以是单个绝对数字,也可以是相对于其中一个值的大小的数字,也可以是这些值的其他函数。

      但是,您还应该回答另一个问题。有时,即使精确计算的值不相等,上述测试也会接受相等的值(因为两个计算值非常接近,甚至可能相等)。因此,您知道即使精确计算的数字不相等,接受彼此接近的计算值是否相等也会给您带来问题。如果答案是肯定的,上述测试有时会接受相同的数字,这会给您带来问题,那么您不能使用此测试。您可能需要以不同的方式执行计算以减少错误。

      通常会给出一些建议来制造一些看似很小的阈值并使用它。这是草率的编程,不是工程。

      顺便说一句,永远不要写pow(10, 7)。写1e7。这避免了函数调用中出现任何错误的可能性,并且可以完全避免不必要的函数调用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-12-17
        • 1970-01-01
        • 1970-01-01
        • 2018-06-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-11
        相关资源
        最近更新 更多