Search code examples
c#.netfloating-point

Floating point comparison functions for C#


Can someone point towards (or show) some good general floating point comparison functions in C# for comparing floating point values? I want to implement functions for IsEqual, IsGreater an IsLess. I also only really care about doubles not floats.


Solution

  • Writing a useful general-purpose floating point IsEqual is very, very hard, if not outright impossible. Your current code will fail badly for a==0. How the method should behave for such cases is really a matter of definition, and arguably the code would best be tailored for the specific domain use case.

    For this kind of thing, you really, really need a good test suite. That's how I did it for The Floating-Point Guide, this is what I came up with in the end (Java code, should be easy enough to translate):

    public static boolean nearlyEqual(float a, float b, float epsilon) {
        final float absA = Math.abs(a);
        final float absB = Math.abs(b);
        final float diff = Math.abs(a - b);
    
        if (a == b) { // shortcut, handles infinities
            return true;
        } else if (a == 0 || b == 0 || absA + absB < Float.MIN_NORMAL) {
            // a or b is zero or both are extremely close to it
            // relative error is less meaningful here
            return diff < (epsilon * Float.MIN_NORMAL);
        } else { // use relative error
            return diff / (absA + absB) < epsilon;
        }
    }
    

    You can also find the test suite on the site.

    Appendix: Same code in c# for doubles (as asked in questions)

    public static bool NearlyEqual(double a, double b, double epsilon)
    {
        const double MinNormal = 2.2250738585072014E-308d;
        double absA = Math.Abs(a);
        double absB = Math.Abs(b);
        double diff = Math.Abs(a - b);
    
        if (a.Equals(b))
        { // shortcut, handles infinities
            return true;
        } 
        else if (a == 0 || b == 0 || absA + absB < MinNormal) 
        {
            // a or b is zero or both are extremely close to it
            // relative error is less meaningful here
            return diff < (epsilon * MinNormal);
        }
        else
        { // use relative error
            return diff / (absA + absB) < epsilon;
        }
    }