比较double和int,而不进行转换 [英] Comparing a double and int, without casting or conversion

查看:200
本文介绍了比较double和int,而不进行转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在一个C ++模块中,我们有一个表达式求值语言。

  \ 
EVDataElement NAME :: eval(const EvalContext& ec,\
const bool recursiveFlag,\
EVEvaluatorTraceFormatter * trace)\
{\
/ * EVTimer timer((DECLARE_REL_EVAL),eval,*, ,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,!=)

$ b b

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



SO,如果数据库中有一个规则表示field1 - field2> param1,它会通过传递给上面的表达式语言来验证此条件并返回结果。 / p>

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



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



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



我说我们不能使用转换的原因是因为我们从来不知道什么数据类型可能通过左和右。

解决方案

在处理不同原语的值时,你会得到通常的转换类型。



如果你比较 int s到 double 在确定两个值是否足够接近时,你需要想出要使用的任何规则。您可以考虑使用 std :: modf

请考虑: / p>

  #include< iostream> 
#include< cmath>

int main()
{
double d = 6.15 - 3.15;
std :: cout<< std :: boolalpha;
std :: cout<< d == 3.0:<< (d == 3.0)< '\\\
';
double i;
d = std :: modf(d,& i);
std :: cout<< i =< i<< ,d =<< d<< '\\\
';
std :: cout<< i == 3.0:<< (i == 3.0)< '\\\
';使用Visual Studio 2010对默认设置(即 NOT

strong>使用 fastmath )我得到:

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

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






论文每个计算机科学家应该知道的浮点算术 a>,它描述了二进制浮点数学如何工作,以及它并不总是符合人类期望。要记住的要点是,你几乎不想比较两个浮点数的相等,特别是如果一个(或两个)这些数字是数学运算的结果。



不过,在您的情况下,您尝试将 double int 进行比较,假设您需要一些四舍五入。您可能希望将 3.1 等同于 3 。你可能不会。我真的不知道。



如果你使用小学教学的舍入约定(向上舍入到.5或更高),你可能会做: / p>

  #include< iostream> 
#include< cmath>

int main()
{
double d = 6.15 - 3.15;
std :: cout<< std :: boolalpha;
std :: cout<< d == 3.0:<< (d == 3.0)< '\\\
';
//注意:这将舍入负数,方向错误
std :: cout<< d'足够接近到3.0:< (std :: floor(d + 0.5)== 3.0)< '\\\
';
}

有很多复杂的可能性, p>

In one of the C++ modules we have, we have an expression evaluation language.

                                \
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,!=)

The module allows certain configuration rules to be set.

SO, if there was a rule in the database that said field1 - field2 > param1, it verifies this condition by passing to the expression language above and returns a result.

The problem we are facing now is say param1 = 3, and field1 = 6.15, and field2 = 3.15

It says the result is true. And I think it is because the difference of 6.15 and 3.15 results in 3.00

And when 3.00 is compared with 3, it thinks 3.00 is greater. Is there any way to work around this?

The reason I said we can't use casting is because we never know what datatype might come through for left and right. I hope this question made sense.

解决方案

You're going to get the "usual conversions" when dealing with values of different primitive types. I don't think there's any way around this.

If you're comparing ints to doubles you're going to need to come up with whatever rules you want to use when determining if two values are "close enough." You may consider using the std::modf function (in <cmath>) in making the comparison.

Consider:

#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';
}

Using Visual Studio 2010 on default settings (i.e., NOT using fastmath) I get:

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

3.0 may be representable exactly in binary floating point math, but 6.15 - 3.15 isn't 3.0 in binary floating point math.


There have already been two references to the paper "What Every Computer Scientist Should Know About Floating-Point Arithmetic" which describes how binary floating point math works, and how it doesn't always fit with human expectations. The main point to remember is that you hardly ever want to compare two floating point numbers for equality, especially if one (or both) of those numbers is the result of a math operation.

In your case, though, you're trying to compare a double with an int, and I have to assume you want some rounding. You might want to consider 3.1 to be equivalent to 3. You might not. I really have no idea.

If you were to use the rounding conventions taught in elementary school (round up on .5 or higher), you might do something like:

#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';
}

There are much more complex possibilities, including one described in the paper.

这篇关于比较double和int,而不进行转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆