c++ comparison of two double values not working properly
查看此代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #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的话,如下:
1
| double V() const { return (4/3) * 3.0 * pow(r,3); } |
号
然后,输出为:84.78 == 84.78 : 1。
这是怎么回事?我需要这个方法,用于我的程序,它将比较两个对象的体积,但这是不可能的?我撞了好长时间才弄清楚问题的原因,幸运的是我找到了,但现在我不明白为什么了??它与编译器(GCC)有什么关系,还是我在这里遗漏了一些重要的东西?
- 您不需要像这样测试浮点数是否相等。
- @为什么?我该怎么办?
- 通常,测试浮点值是否相等是一个坏主意,因为小的舍入误差可能会产生意想不到的结果。但是,正如您所说,这两次使用相同的输入进行相同的计算,因此测试应该通过。它至少有一个版本的gcc:ideone.com/fpjrvn。您使用的是什么版本和平台?
- @Mikeseymour gcc version 4.7.2 (Debian 4.7.2-5),Debian喘息。但是代码稍后将在Visual Studio中进行测试,我现在应该忽略这一点吗?这是我作业的一部分。我不记得教授说了什么,没有用这种方式比较双重价值观。
- @Tuks:你的教授可能什么都没说,但另一位教授说得很多:cl.cam.ac.uk/teaching/1011/fpcomp/floatingmath.pdf
- @Mikeseymour谢谢。我想最好的方法是比较半径而不是体积…
- 没有要求相同的计算产生两次相同的结果。奇怪但真实。任何计算都可以以比任何时候都要高的精度执行,这会改变结果。只是永远不要为了相等而比较两个浮点数。减去它们,并将它们的差异与一个小的量进行比较。
- @Ericlippert我找到了一个解决方案:int(V()*1000) == int(s.V()*1000)。
- @Tuks,顺便说一句,这段代码中有一个bug。半径为3的球体的体积是113.04,而不是84.78。你应该用手核对一下你的计算结果。
- @这不是解决办法。
- @阿达姆布利是的,我明白了…因为(4/3),应该是(4.0/3)
- @戴维德芬南是的,我想这很糟糕…abs(V()-s.V())<0.0001可能是最好的
- whoops,意思是选择这个问题:stackoverflow.com/questions/21346694/&hellip;。嗯,我猜离得足够近了。
- 类似于stackoverflow.com/questions/17333/&hellip;
使用==运算符比较浮点值非常容易出错;两个应该相等的值可能不是由于算术舍入错误造成的。比较这些的常用方法是使用epsilon:
1 2 3 4
| bool double_equals(double a, double b, double epsilon = 0.001)
{
return std::abs(a - b) < epsilon;
} |
- 更多详细讨论请参见:cygnus software.com/papers/comparingfloats/&hellip;
- 不,"几乎等于"是一种高级技术,初学者不应该使用它。一个严重的问题是,a almost equals b和b almost equals c并不意味着a almost equals c。
- @彼得贝克尔的浮点运算并不琐碎,没有"初学者的方法"可以做到这一点。
- @尼詹森-是的,但"几乎相等"几乎总是不正确的解决方案。
- 我不希望双_等于(1e-6,-1e-5)返回"true"。
浮点比较有两个问题:
(1)浮点运算通常至少涉及很难预测的微小舍入误差。因此,在数学上给出相同结果的两个浮点运算(如4.7*(1.0/3.14)与4.7/3.14)可能给出不同的结果。
(2)编译器可以执行浮点运算,有时精度比需要的要高。它还允许执行完全相同的浮点运算,而只使用其他时间所需的精度。因此,相同的操作可能会产生稍微不同的结果,这就是您在这里看到的。
为了解决OP的问题,这看起来是由(2)引起的。我将尝试找出是否有任何编译器选项可以阻止编译器使用比需要更高的精度。