9

I use ReShaper and when I compare two double values with ==, it suggests that I should use the Math. ABS method with a tolerance. See: https://www.jetbrains.com/help/resharper/2016.2/CompareOfFloatsByEqualityOperator.html

This example

double d = 0.0;
double d2 = 0.0;
if (d == d2)
{
    /* some code */
}

is then converted to

double d = 0.0;
double d2 = 0.0;
if (Math.Abs(d - d2) < TOLERANCE)
{
    /* some code */
}

But I think it's really complicated for a developer to think about the right tolerance. So I thought this may be implemented in the Double.Equals() method.

But this method is implemented like so

public override bool Equals(Object obj) {
    if (!(obj is Double)) { 
        return false;
    } 
    double temp = ((Double)obj).m_value; 
    // This code below is written this way for performance reasons i.e the != and == check is intentional.
    if (temp == m_value) { 
        return true;
    }
    return IsNaN(temp) && IsNaN(m_value);
}

public bool Equals(Double obj)
{ 
    if (obj == m_value) {
        return true; 
    } 
    return IsNaN(obj) && IsNaN(m_value);
}

Why is that? And what is the correct way to compare double values?

Leon Husmann
  • 664
  • 1
  • 6
  • 25
  • 1
    Why not use decimal ? if(double1 < double2) will give you a problem always for really close values – mybirthname Nov 17 '16 at 11:13
  • 1
    If you find it difficult for a *developer* to get a tolerance, how should the *.NET-framework* decide on any as it has far less knowledge of what you consider to be equal. – MakePeaceGreatAgain Nov 17 '16 at 11:14
  • @HimBromBeere I thought they may use double.Epsilon as the default tolerance or would that be a bad idea? – Leon Husmann Nov 17 '16 at 11:21
  • It says in the documentation you provided that Epsilon is considered too low to be the default tolerance in the majority of cases. – Equalsk Nov 17 '16 at 11:24
  • Have a look e.g. [here](http://stackoverflow.com/questions/1398753/comparing-double-values-in-c-sharp). – Daniel Dušek Nov 17 '16 at 11:24
  • 1
    _And what is the correct way to compare double values_ - there is no way - you cannot checks `double` for **real** equality. Do not use `double` for cases where you need check for equality, use `decimal` instead – Fabio Nov 17 '16 at 11:58
  • `double.Equals` is intended to be compatible with various things that assume `Equals` is a equivalence relation, so it definitely cannot use a tolerance – harold Nov 17 '16 at 13:11
  • I'm not so sure that `decimal` is the answer. The real issue is why you where comparing doubles in the first place. That shouldn't have occurred. Take a long critical look at what the code is supposed to do. – H H Nov 17 '16 at 13:38

3 Answers3

12

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)
Martin Backasch
  • 1,829
  • 3
  • 20
  • 30
Pepernoot
  • 3,409
  • 3
  • 21
  • 46
  • 8
    This method can be very dangerous for big project where everybody uses this extension method. Imagine situation where `value1.EqualDouble(value2) == true` so then if `value1.EqualDouble(value3) == true` it easy to assume that `value2.EqualDouble(value3) == true` too - but it is not in some cases. So suggest at least change name to something more informative `CloseTo` fro example – Fabio Nov 17 '16 at 12:01
  • Thanks! the Double.Equals Method that C# has doesn't implement an epsilon so testing something like 0.5 == 0.5 gave me a bad flag. By the way I modified your method for a normal method instead of an extension, something like: public static bool AlmostEqualTo(double value1, double value2) { return Math.Abs(value1 - value2) < 0.0000001; } – Felipe Gutierrez Dec 05 '18 at 01:15
0

https://learn.microsoft.com/en-us/dotnet/api/system.numerics.complex.equals?view=net-6.0

If the obj parameter is not a Complex object, but it is a data type for which an implicit conversion is defined, the Equals(Object) method converts obj to a Complex object whose real part is equal to the value of obj and whose imaginary part is equal to zero before it performs the comparison. The following example illustrates this by finding that a complex number and a double-precision floating-point value are equal.

double n1 = 16.33;
System.Numerics.Complex c1 =
new System.Numerics.Complex(16.33, 0);
Console.WriteLine(c1.Equals(n1));               // Returns true.
YUu
  • 69
  • 8
-2

I ended up using

double piConstant = 3.142;
double piFractional = 7/22;
if(piConstatnt.String("{0:0.00}")==piFractional.String("{0:0.00}")
{
    // some code
}

This lets me control the precision by setting the desired string format. https://www.csharp-examples.net/string-format-double/

In case you want more info on Equals method from microsoft. https://learn.microsoft.com/en-us/dotnet/api/system.double.equals?view=net-5.0

fantagons
  • 9
  • 3