Comparing double values in C#

Viewed 128453

I've a double variable called x. In the code, x gets assigned a value of 0.1 and I check it in an 'if' statement comparing x and 0.1

if (x==0.1)
{
----
}

Unfortunately it does not enter the if statement

  1. Should I use Double or double?

  2. What's the reason behind this? Can you suggest a solution for this?

18 Answers

Official MS help, especially interested "Precision in Comparisons" part in context of the question. https://docs.microsoft.com/en-us/dotnet/api/system.double.equals

// Initialize two doubles with apparently identical values
double double1 = .333333;
double double2 = (double) 1/3;
// Define the tolerance for variation in their values
double difference = Math.Abs(double1 * .00001);

// Compare the values
// The output to the console indicates that the two values are equal
if (Math.Abs(double1 - double2) <= difference)
   Console.WriteLine("double1 and double2 are equal.");
else
   Console.WriteLine("double1 and double2 are unequal.");

Taking a tip from the Java code base, try using .CompareTo and test for the zero comparison. This assumes the .CompareTo function takes in to account floating point equality in an accurate manner. For instance,

System.Math.PI.CompareTo(System.Math.PI) == 0

This predicate should return true.

// number of digits to be compared    
public int n = 12 
// n+1 because b/a tends to 1 with n leading digits
public double MyEpsilon { get; } = Math.Pow(10, -(n+1)); 

public bool IsEqual(double a, double b)
{
    // Avoiding division by zero
    if (Math.Abs(a)<= double.Epsilon || Math.Abs(b) <= double.Epsilon)
        return Math.Abs(a - b) <=  double.Epsilon;

    // Comparison
    return Math.Abs(1.0 - a / b) <=  MyEpsilon;
}

Explanation

The main comparison function done using division a/b which should go toward 1. But why division? it simply puts one number as reference defines the second one. For example

a = 0.00000012345
b = 0.00000012346
a/b = 0.999919002
b/a = 1.000081004
(a/b)-1 = 8.099789405475458e-5‬
1-(b/a) = 8.100445524503848e-5‬

or

a=12345*10^8
b=12346*10^8 
a/b = 0.999919002
b/a = 1.000081004
(a/b)-1 = 8.099789405475458e-5‬
1-(b/a) = 8.100445524503848e-5‬

by division we get rid of trailing or leading zeros (or relatively small numbers) that pollute our judgement of number precision. In the example, the comparison is of order 10^-5, and we have 4 number accuracy, because of that in the beginning code I wrote comparison with 10^(n+1) where n is number accuracy.

Adding onto Valentin Kuzub's answer above:

we could use a single method that supports providing nth precision number:

public static bool EqualsNthDigitPrecision(this double value, double compareTo, int precisionPoint) =>
    Math.Abs(value - compareTo) < Math.Pow(10, -Math.Abs(precisionPoint));

Note: This method is built for simplicity without added bulk and not with performance in mind.

My extensions method for double comparison:

public static bool IsEqual(this double value1, double value2, int precision = 2)
{
    var dif = Math.Abs(Math.Round(value1, precision) - Math.Round(value2, precision));
    while (precision > 0)
    {
        dif *= 10;
        precision--;
    }

    return dif < 1;
}
Related