[c#] Comparing double values in C#

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?

This question is related to c# .net double

The answer is


1) Should i use Double or double???

Double and double is the same thing. double is just a C# keyword working as alias for the class System.Double The most common thing is to use the aliases! The same for string (System.String), int(System.Int32)

Also see Built-In Types Table (C# Reference)


Double and double are identical.

For the reason, see http://www.yoda.arachsys.com/csharp/floatingpoint.html . In short: a double is not an exact type and a minute difference between "x" and "0.1" will throw it off.


Double (called float in some languages) is fraut with problems due to rounding issues, it's good only if you need approximate values.

The Decimal data type does what you want.

For reference decimal and Decimal are the same in .NET C#, as are the double and Double types, they both refer to the same type (decimal and double are very different though, as you've seen).

Beware that the Decimal data type has some costs associated with it, so use it with caution if you're looking at loops etc.


Use decimal. It doesn't have this "problem".


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.


double and Double are the same (double is an alias for Double) and can be used interchangeably.

The problem with comparing a double with another value is that doubles are approximate values, not exact values. So when you set x to 0.1 it may in reality be stored as 0.100000001 or something like that.

Instead of checking for equality, you should check that the difference is less than a defined minimum difference (tolerance). Something like:

if (Math.Abs(x - 0.1) < 0.0000001)
{
    ...
}

You need a combination of Math.Abs on X-Y and a value to compare with.

You can use following Extension method approach

public static class DoubleExtensions
    {
        const double _3 = 0.001;
        const double _4 = 0.0001;
        const double _5 = 0.00001;
        const double _6 = 0.000001;
        const double _7 = 0.0000001;

        public static bool Equals3DigitPrecision(this double left, double right)
        {
            return Math.Abs(left - right) < _3;
        }

        public static bool Equals4DigitPrecision(this double left, double right)
        {
            return Math.Abs(left - right) < _4;
        }

        ...

Since you rarely call methods on double except ToString I believe its pretty safe extension.

Then you can compare x and y like

if(x.Equals4DigitPrecision(y))


Comparing floating point number can't always be done precisely because of rounding. To compare

(x == .1)

the computer really compares

(x - .1) vs 0

Result of sybtraction can not always be represeted precisely because of how floating point number are represented on the machine. Therefore you get some nonzero value and the condition evaluates to false.

To overcome this compare

Math.Abs(x- .1) vs some very small threshold ( like 1E-9)

As a general rule:

Double representation is good enough in most cases but can miserably fail in some situations. Use decimal values if you need complete precision (as in financial applications).

Most problems with doubles doesn't come from direct comparison, it use to be a result of the accumulation of several math operations which exponentially disturb the value due to rounding and fractional errors (especially with multiplications and divisions).

Check your logic, if the code is:

x = 0.1

if (x == 0.1)

it should not fail, it's to simple to fail, if X value is calculated by more complex means or operations it's quite possible the ToString method used by the debugger is using an smart rounding, maybe you can do the same (if that's too risky go back to using decimal):

if (x.ToString() == "0.1")

Floating point number representations are notoriously inaccurate because of the way floats are stored internally. E.g. x may actually be 0.0999999999 or 0.100000001 and your condition will fail. If you want to determine if floats are equal you need to specify whether they're equal to within a certain tolerance.

I.e.:

if(Math.Abs(x - 0.1) < tol) {
   // Do something 
}

To compare floating point, double or float types, use the specific method of CSharp:

if (double1.CompareTo(double2) > 0)
{
    // double1 is greater than double2
}
if (double1.CompareTo(double2) < 0)
{
    // double1 is less than double2
}
if (double1.CompareTo(double2) == 0)
{
    // double1 equals double2
}

https://docs.microsoft.com/en-us/dotnet/api/system.double.compareto?view=netcore-3.1


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.


Exact comparison of floating point values is know to not always work due to the rounding and internal representation issue.

Try imprecise comparison:

if (x >= 0.099 && x <= 0.101)
{
}

The other alternative is to use the decimal data type.


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


From the documentation:

Precision in Comparisons The Equals method should be used with caution, because two apparently equivalent values can be unequal due to the differing precision of the two values. The following example reports that the Double value .3333 and the Double returned by dividing 1 by 3 are unequal.

...

Rather than comparing for equality, one recommended technique involves defining an acceptable margin of difference between two values (such as .01% of one of the values). If the absolute value of the difference between the two values is less than or equal to that margin, the difference is likely to be due to differences in precision and, therefore, the values are likely to be equal. The following example uses this technique to compare .33333 and 1/3, the two Double values that the previous code example found to be unequal.

So if you really need a double, you should use the techique described on the documentation. If you can, change it to a decimal. It' will be slower, but you won't have this type of problem.


Examples related to c#

How can I convert this one line of ActionScript to C#? Microsoft Advertising SDK doesn't deliverer ads How to use a global array in C#? How to correctly write async method? C# - insert values from file into two arrays Uploading into folder in FTP? Are these methods thread safe? dotnet ef not found in .NET Core 3 HTTP Error 500.30 - ANCM In-Process Start Failure Best way to "push" into C# array

Examples related to .net

You must add a reference to assembly 'netstandard, Version=2.0.0.0 How to use Bootstrap 4 in ASP.NET Core No authenticationScheme was specified, and there was no DefaultChallengeScheme found with default authentification and custom authorization .net Core 2.0 - Package was restored using .NetFramework 4.6.1 instead of target framework .netCore 2.0. The package may not be fully compatible Update .NET web service to use TLS 1.2 EF Core add-migration Build Failed What is the difference between .NET Core and .NET Standard Class Library project types? Visual Studio 2017 - Could not load file or assembly 'System.Runtime, Version=4.1.0.0' or one of its dependencies Nuget connection attempt failed "Unable to load the service index for source" Token based authentication in Web API without any user interface

Examples related to double

Round up double to 2 decimal places Convert double to float in Java Float and double datatype in Java Rounding a double value to x number of decimal places in swift How to round a Double to the nearest Int in swift? Swift double to string How to get the Power of some Integer in Swift language? Difference between int and double How to cast the size_t to double or int C++ How to get absolute value from double - c-language