【问题标题】:c++ comparison of two double values not working properly [duplicate]两个双精度值的c ++比较无法正常工作[重复]
【发布时间】:2013-09-29 01:47:06
【问题描述】:

看看这段代码:

#include <cmath>
#include <iostream>
using namespace std;
class Sphere
{
    double r;
public:
    double V() const { return (4/3) * 3.14 * pow(r,3); }
    bool equal(const Sphere& s) const
    {
        cout  << V() << " == " << s.V() << " : " << ( V() == s.V() );
        return ( V() == s.V() );

    }

    explicit Sphere(double rr = 1): r(rr){}

};
main()
{
    Sphere s(3);
    s.equal(s);
}

输出是84.78 == 84.78 : 0,这意味着即使所有参数都是静态的,相同的方法也不会每次都返回相同的值?

但是如果我在V() 方法定义中写3.0 而不是3.14,像这样:

double V() const { return (4/3) * 3.0 * pow(r,3); }

那么,输出为:84.78 == 84.78 : 1

这里发生了什么?对于我的程序,我需要这种方法,它将比较两个对象的体积,但这是不可能的?我敲了很长时间才弄清楚问题的原因,幸运的是我找到了,但现在我不明白为什么?它与编译器(GCC)有关还是我在这里遗漏了一些重要的东西?

【问题讨论】:

  • 你根本不会像那样测试浮点数的相等性。
  • @yngum 为什么?我该怎么办?
  • 通常测试浮点值是否相等是个坏主意,因为小的舍入误差会产生意想不到的结果。但是,正如您所说,这会使用相同的输入进行两次相同的计算,因此测试应该通过。它适用于至少一个版本的 GCC:ideone.com/FPjRVN。您使用的是什么版本和平台?
  • @tuks:你的教授可能什么都没说,但另一位教授说了很多:cl.cam.ac.uk/teaching/1011/FPComp/floatingmath.pdf
  • @AdamBurry 是的,我明白了...因为 (4/3),应该是 (4.0/3)

标签: c++ comparison double


【解决方案1】:

使用== 运算符比较浮点值很容易出错; 应该相等的两个值可能不是由于算术舍入错误。比较这些的常用方法是使用 epsilon:

bool double_equals(double a, double b, double epsilon = 0.001)
{
    return std::abs(a - b) < epsilon;
}

【讨论】:

  • 没有。 “几乎等于”是一种先进的技术;它不应该被初学者使用。一个严重的问题是a almost equals bb almost equals c 并不意味着a almost equals c
  • @PeteBecker 浮点运算并非易事,没有“初学者的方式”可以做到这一点。
  • @nijansen - 真;但“几乎等于”几乎总是不是正确的解决方案。
  • 我不希望 double_equals (1e-6, -1e-5) 返回“true”。
【解决方案2】:

浮点比较有两个问题:

(1) 浮点运算通常至少涉及难以预测的微小舍入误差。因此,在数学上应该给出相同结果的两个浮点运算(如 4.7 * (1.0 / 3.14) 与 4.7 / 3.14)可能会给出不同的结果。

(2) 有时允许编译器以高于所需的精度执行浮点运算。还允许以其他时间所需的精度执行完全相同的浮点运算。因此,完全相同的操作可能会产生略有不同的结果,这就是您在此处看到的。

为了解决OP的问题,这看起来是由(2)引起的。我会尝试查找是否有任何编译器选项可以阻止编译器使用比需要更高的精度。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-11
    • 2015-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多