The right way to compare a System.Double to '0' (a number, int?)
I have this if
expression,
void Foo()
{
System.Double something = GetSomething();
if (somethi开发者_JS百科ng == 0) //Comparison of floating point numbers with equality
// operator. Possible loss of precision while rounding value
{}
}
Is that expression equal with
void Foo()
{
System.Double something = GetSomething();
if (something < 1)
{}
}
? Because then I might have a problem, entering the if
with e.g. a value of 0.9.
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.
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.
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 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.
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.
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;
}
精彩评论