正确的方法来比较一个 System。 Double 到’0’(一个数字,int?)

我有一个 if表达式,

void Foo()
{
System.Double something = GetSomething();
if (something == 0) //Comparison of floating point numbers with equality
// operator. Possible loss of precision while rounding value
{}
}

这个表达式等于

void Foo()
{
System.Double something = GetSomething();
if (something < 1)
{}
}

? 因为那样我可能会有问题,输入 if,例如值为0.9。

115418 次浏览

Well, how close do you need the value to be to 0? If you go through a lot of floating point operations which in "infinite precision" might result in 0, you could end up with a result "very close" to 0.

Typically in this situation you want to provide some sort of epsilon, and check that the result is just within that epsilon:

if (Math.Abs(something) < 0.001)

The epsilon you should use is application-specific - it depends on what you're doing.

Of course, if the result should be exactly zero, then a simple equality check is fine.

I dont' think it's equal, honestly. Consider yuor own example: something = 0.9, or 0.0004. In first case it will be FALSE, in second case it will be TRUE. Dealing with this types I usually define for me precision percentage and compare within that precision. Depends on your needs. something like...

if(((int)(something*100)) == 0) {




//do something
}

Hope this helps.

Your something is a double, and you have correctly identified that in the line

if (something == 0)

we have a double on the left-hand side (lhs) and an int on the right-hand side (rhs).

But now it seems like you think the lhs will be converted to an int, and then the == sign will compare two integers. That's not what happens. The conversion from double to int is explicit and can not happen "automatically".

Instead, the opposite happens. The rhs is converted to double, and then the == sign becomes an equality test between two doubles. This conversion is implicit (automatic).

It is considered better (by some) to write

if (something == 0.0)

or

if (something == 0d)

because then it's immediate that you're comparing two doubles. However, that's just a matter of style and readability because the compiler will do the same thing in any case.

It's also relevant, in some cases, to introduce a "tolerance" like in Jon Skeet's answer, but that tolerance would be a double too. It could of course be 1.0 if you wanted, but it does not have to be [the least strictly positive] integer.

If something has been assigned from the result of an operation other than something = 0 then you better use:

if(Math.Abs(something) < Double.Epsilon)
{
//do something
}

Edit: This code is wrong. Epsilon is the smallest number, but not quite zero. When you wish to compare a number to another number, you need to think of what is the acceptable tolerance. Let's say that anything beyond .00001 you don't care about. That's the number you'd use. The value depends on the domain. However, it's mostly certainly never Double.Epsilon.

If you simply want to suppress the warning, do this:

if (something.Equals(0.0))

Of course, this is only a valid solution if you know that drift isn't a concern. I often do this to check if I'm about to divide by zero.

Here is the example presenting the problem (prepared in LinQPad - if you don't have it just use Console.Writeline instead of Dump method):

void Main()
{
double x = 0.000001 / 0.1;
double y = 0.001 * 0.01;


double res = (x-y);
res.Dump();
(res == 0).Dump();
}

Both x and y are theoretically same and equal to: 0.00001 but because of lack of "infinite precision" those values are slightly different. Unfortunately slightly enough to return false when comparing to 0 in usual way.

Prefer this method when you want to check how close is the double value to zero for both signs.

public static bool isZero(double value, double precision = 1e-6)
{
return !value.Equals(double.NaN) &&
!value.Equals(double.NegativeInfinity) &&
!value.Equals(double.PositiveInfinity) &&
Math.Abs(value) < precision;
}