1

在我们拥有的一个 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 > param1,它会通过传递给上面的表达式语言来验证这个条件并返回一个结果。

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

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

并且当 3.00 与 3 比较时,它认为 3.00 更大。有没有办法解决这个问题?

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

4

2 回答 2

5

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

如果您将ints 与doubles 进行比较,则在确定两个值是否“足够接近”时,您将需要提出您想要使用的任何规则。您可以考虑使用std::modf函数 (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 ”一文,它描述了二进制浮点数学的工作原理,以及它如何并不总是符合人类的期望。要记住的要点是,您几乎不想比较两个浮点数是否相等,特别是如果这些数字中的一个(或两个)是数学运算的结果。

但是,在您的情况下,您正在尝试将 adouble与 an进行比较int,并且我必须假设您想要一些舍入。您可能要考虑3.1等效于3. 你可能不会。我真的不知道。

如果您要使用小学教授的四舍五入约定(四舍五入为 0.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';
}

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

于 2012-05-02T18:26:31.137 回答
1

如果你想要field1 - field2 > param1for param1 = 3field1 = 6.15那么field2 = 3.15你将需要使用infinite precision算术。

请阅读上面提到的浮点算术论文。

于 2012-05-02T18:55:44.603 回答