Comparing Double Values in C#

Comparing double values in C#

It's a standard problem due to how the computer stores floating point values. Search here for "floating point problem" and you'll find tons of information.

In short – a float/double can't store 0.1 precisely. It will always be a little off.

You can try using the decimal type which stores numbers in decimal notation. Thus 0.1 will be representable precisely.


You wanted to know the reason:

Float/double are stored as binary fractions, not decimal fractions. To illustrate:

12.34 in decimal notation (what we use) means

1 * 101 + 2 * 100 + 3 * 10-1 + 4 * 10-2

The computer stores floating point numbers in the same way, except it uses base 2: 10.01 means

1 * 21 + 0 * 20 + 0 * 2-1 + 1 * 2-2

Now, you probably know that there are some numbers that cannot be represented fully with our decimal notation. For example, 1/3 in decimal notation is 0.3333333…. The same thing happens in binary notation, except that the numbers that cannot be represented precisely are different. Among them is the number 1/10. In binary notation that is 0.000110011001100….

Since the binary notation cannot store it precisely, it is stored in a rounded-off way. Hence your problem.

C# Compare two double with .Equals()

You could create an extension method

public static class DoubleExtension 
{
public static bool AlmostEqualTo(this double value1, double value2)
{
return Math.Abs(value1 - value2) < 0.0000001;
}
}

And use it like this

doubleValue.AlmostEqualTo(doubleValue2)

Comparing double values


How can i compare till first four bits

I assume you mean 4 digits, not 4 bits.

Just take the Absolute value of the difference:

if (Math.Abs(largest - 0.94289988675) < 0.0001) 
{
//proceed
}

Equality is a pretty difficult concept with floating point types, never use the simple ==

The right way to compare a System.Double to '0' (a number, int?)

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.

Safe to compare C# doubles against assigned values?

Well, yes and no. If all of the floating-point values you are comparing are stored as constants and the constants are the same data width (i.e., you compare float to float and double to double), this is a safe operation. But if everything you were comparing was a constant, why not use integers or enums?

In general, comparing floating-point numbers for equality is unsafe. The reason for this is that floating-point numbers can't perfectly store all values. This is a lot like the problem with the number 1/3 in decimal which we would have to write as 0.33333... The same problem exists for storing fractional parts in binary, and numbers that have finite representations in decimal notation are not guaranteed to have finite binary representations. Since we are limited to 32 or 64 bits, part of the number gets truncated. This means that performing math operations on floating-point numbers could result in unexpected consequences.

Consider this quote from this post from Bruce M. Bush:

At the heart of many strange results is one fundamental:
floating-point on computers is usually base 2, whereas the external
representation is base 10. We expect that 1/3 will not be exactly
representable, but it seems intuitive that .01 would be. Not so! .01
in IEEE single-precision format is exactly 10737418/1073741824 or
approximately 0.009999999776482582.

You should usually check equality in floating-point values using some small epsilon for variance.

public class Foo
{
//Choose a small value that is appropriate for your needs
//see the info below for some info from Microsoft
private static double epsilon = 0.00001;
private double defaultEfficiency = 100.0;
public double efficiencyBar = defaultEfficiency;

public bool IsBarAtDefaultValue()
{
//we use the absolute value of the difference. If this is smaller than
//epsilon, then the value is "good enough" for equal
if (Math.Abs(efficiencyBar - defaultEfficiency) < epsilon)
return true;
else
return false;
}
}

You could use something like Double.Epsilon for your epsilon value, but this is probably way too small for your needs and is recommended against in the documentation:

If you create a custom algorithm that determines whether two floating-point numbers can be considered equal, we do not recommend that you base your algorithm on the value of the Epsilon constant to establish the acceptable absolute margin of difference for the two values to be considered equal. (Typically, that margin of difference is many times greater than Epsilon.)

And in their documentation on the Double.Equals() method:

Because Epsilon defines the minimum expression of a positive value whose range is near zero, the margin of difference between two similar values must be greater than Epsilon. Typically, it is many times greater than Epsilon. Because of this, we recommend that you do not use Epsilon when comparing Double values for equality.

Both places are good sources of additional information on comparing floating-point numbers safely.

What's the best way to compare Double and Int?

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.Epsilon.

Linq data type comparison with Double

You can use the usual way of comparing double for proximity by calculating the absolute difference, and comparing it to a small value:

Math.Abs(x - y) < 1E-8 // 1E-8 is 0.00000001

For example, you can use this approach in a LINQ query like this:

&& vio.Bows.Any(nw => Math.Abs(nw.XCoordinate-currVio.XCoordinate) < 0.001)

Is it wrong to compare a double to 0 like this: doubleVariable==0?

Nope it's perfectly legal if you are only going to compare against 0 as the right side of comparison will automatically casted to double. On the other hand, it would yield all the round-off errors if you where to compare against == 0.10000001

You are better or reading the discussion about float to 0 comparison here: Is it safe to check floating point values for equality to 0?

Also this discussion is very informative about weird precision problems on floats: Why the result is different for this problem?

i.e. below will yield false:

double d1 = 1.000001; double d2 =0.000001;
Console.WriteLine((d1-d2)==1.0);

to compare double and decimal should I cast double to decimal or decimal to double?

It depends on the data. Decimal has greater precision; double has greater range. If the double could be outside the decimal range, you should cast the decimal to double (or indeed you could write a method that returns a result without casting, if the double value is outside the decimal range; see example below).

In this case, it seems unlikely that the double value would be outside the decimal range, so (especially since you're working with price data) you should cast the double to decimal.

Example (could use some logic to handle NaN values):

private static int Compare(double d, decimal m)
{
const double decimalMin = (double)decimal.MinValue;
const double decimalMax = (double)decimal.MaxValue;
if (d < decimalMin) return -1;
if (d > decimalMax) return 1;
return ((decimal)d).CompareTo(m);
}


Related Topics



Leave a reply



Submit