比较double和int,不进行强制转换或转换

时间:2012-05-02 18:14:29

标签: c++ expression precision

在我们拥有的一个C ++模块中,我们有一个表达式评估语言。

                                \
EVDataElement NAME::eval(   const EvalContext &ec,                          \
                        const bool recursiveFlag,                       \
                        EVEvaluatorTraceFormatter * trace )             \
{                                                                           \
/*  EVTimer timer("(DECLARE_REL_EVAL)","eval","*", "", 1,1, 3);      */     \
    EVDataElement val (                                                     \
        (left->eval(ec, recursiveFlag, trace))                              \
        OP (right->eval(ec, recursiveFlag, trace)) );                       \
    return val;                                                             \
}

DECLARE_REL_EVAL(oLT,<)
DECLARE_REL_EVAL(oLE,<=)
DECLARE_REL_EVAL(oGT,>)
DECLARE_REL_EVAL(oGE,>=)
DECLARE_REL_EVAL(oEQ,==)
DECLARE_REL_EVAL(oNE,!=)

该模块允许设置某些配置规则。

那么,如果数据库中有一条规则说field1 - field2&gt; param1,它通过传递给上面的表达式语言来验证这种情况并返回一个结果。

我们现在面临的问题是param1 = 3,field1 = 6.15,field2 = 3.15

它说结果是真的。我认为这是因为6.15和3.15的差异导致3.00

当3.00与3比较时,它认为3.00更大。有什么方法可以解决这个问题吗?

我说我们不能使用强制转换的原因是因为我们永远不知道左右可能会出现什么数据类型。我希望这个问题有道理。

2 个答案:

答案 0 :(得分:5)

在处理不同基元类型的值时,您将获得“通常的转换”。我认为没有办法解决这个问题。

如果您要将intdouble进行比较,那么在确定两个值是否“足够接近”时,您需要提出您想要使用的规则。您可以考虑使用std::modf function (in <cmath>)进行比较。

考虑:

#include <iostream>
#include <cmath>

int main()
{
    double d = 6.15 - 3.15;
    std::cout << std::boolalpha;
    std::cout << "d == 3.0: " << (d == 3.0) << '\n';
    double i;
    d = std::modf(d, &i);
    std::cout << "i = " << i << ", d = " << d << '\n';
    std::cout << "i == 3.0: " << (i == 3.0) << '\n';
}

在默认设置下使用Visual Studio 2010(例如使用fastmath)我得到:

d == 3.0: false
i = 3, d = 4.44089e-016
i == 3.0: true

3.0可能完全可以在二进制浮点数学中表示,但6.15 - 3.15在二进制浮点数学中不是3.0


已经有两篇文章引用了论文“What Every Computer Scientist Should Know About Floating-Point Arithmetic”,它描述了二进制浮点数学如何工作,以及它如何不总是符合人类的期望。要记住的要点是你几乎不想比较两个浮点数的相等性,特别是如果这些数中的一个(或两个)是数学运算的结果。

但是,在您的情况下,您尝试将doubleint进行比较,我必须假设您需要某些舍入。您可能希望将3.1视为等同于3。你可能不会。我真的不知道。

如果你要使用小学教授的四舍五入(围绕.5或更高),你可能会做类似的事情:

#include <iostream>
#include <cmath>

int main()
{
    double d = 6.15 - 3.15;
    std::cout << std::boolalpha;
    std::cout << "d == 3.0: " << (d == 3.0) << '\n';
    // note:  this rounds negative numbers the wrong direction
    std::cout << "d is 'close enough' to 3.0: " << (std::floor(d + 0.5) == 3.0) << '\n';
}

还有更复杂的可能性,包括论文中描述的可能性。

答案 1 :(得分:1)

如果您希望field1 - field2 > param1param1 = 3field1 = 6.15 field2 = 3.15,则需要使用infinite precision算术。

请阅读上述Floating-Point Arithmetic上的论文。