views:

1061

answers:

4

Hello everybody,

The following code in C# doesn't work:

int iValue = 0;
double dValue = 0.0;

bool isEqual = iValue.Equals(dValue);

So, the question: what's the best way to compare Double and Int?

-- Best Regards, Murat

+22  A: 

You really can't compare floating point and integral values in a naive way; particularly, since there's the classic floating point representation challenges. What you can do is subtract one from the other and see if the difference between them is less than some precision you care about, like so:

int iValue = 0;
double dValue = 0.0;

var diff = Math.Abs(dvalue - iValue);
if( diff < 0.0000001 ) // need some min threshold to compare floating points
   return true; // items equal

You really have to define for yourself what equality means to you. For example, you may want a floating point value to round towards the nearest integer, so that 3.999999981 will be "equal" to 4. Or you may want to truncate the value, so it would effectively be 3. It all depends on what you're trying to achieve.

EDIT: Note that i chose 0.0000001 as an example threshold value ... you need to decide for yourself what precision is sufficient for comparison. Just realize you need to be within the normal representational bounds of double which I believe is defined as Double.Espilon.

LBushkin
This is a nice solution to the problem I mentioned. For greater accuracy (only when its necessary), use only integers, as I suggested in my answer.
San Jacinto
Would you be better comparing with the system defined constant epsilon (see here http://msdn.microsoft.com/en-us/library/system.double.epsilon.aspx) instead of a hard-coded value like 0.0000001?NB I've never coded C# (just C++) but I assume the same principle applies
pxb
I mention that in the edit to my answer. Epsilon may or may not be a good choice depending on what precision the OP cares about in his code.
LBushkin
Double.Epsilon is only useful if you are subtracting values between 0 and 1 as it's the "smallest positive Double value greater than zero". Since `double` values aren't evenly spaced and their distance increases with their magnitude you won't ever get something around Double.Epsilon if you subtract two values.
Joey
@Johannes: That's a good point. For very large positive/negative values the code would need to be more "relaxed" in how it evaluates equality.
LBushkin
@johannes I take your point about spacing of doubles. However, that makes the constant of 0.0000001 equally unsuitable as it'll also suffer the same issue. What's the solution? If the difference < 0.01% (or some other low percentage) of one of the values consider them equal?
pxb
pxb: It's not exactly easy and one of my main complaints about JUnit's `assertEqual(double, double, double)` which suffers from exactly the same problem. I once wrote a helper method which looked at the arguments and determined the proper *x* in 10^*x* so that they are equal to a given number of places. Not pretty though. But yes, you are right, that problem always remains. I just wanted to point out that `Double.Epsilon` will fail in nearly every case while the others may actually be useful in a fair number of cases.
Joey
+1  A: 

This really depends on what you consider "equal". If you want your comparison to return true if and only if the double precisely matches the integer value (i.e. has no fractional component), you should cast your int to a double to do the comparison:

bool isEqual = (double)iValue == dValue;

If something like 1.1 would be considered equal to 1, you can either cast the double to an int (if you want to ignore the fractional component altogether) or round the double if you want say 1.9 to equal 2.

Ryan Brunner
Careful with rounding, though. Many people seem surprised when 2.5 rounds to 2.
Joey
+2  A: 

It's an exceedingly bad idea to compare integers and floating-point numbers for equality in any language. It works for very simple cases, but after you do any math at all, the likliehood of the program doing what you want it to decreases dramatically.

It has to do with the way floating-point numbers are stored on a binary, digital system.

If you are very sure you want to use this, create a class to make you own number with fractions. use one int to maintain the whole number, and another int to maintain the fraction.

San Jacinto
A: 

See the this related question: http://stackoverflow.com/questions/1530069/comparing-floating-point-values

Konamiman