Floating point comparison functions for C#

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;
    }
}

From Bruce Dawson's paper on comparing floats, you can also compare floats as integers. Closeness is determined by least significant bits.

public static bool AlmostEqual2sComplement( float a, float b, int maxDeltaBits ) 
{
    int aInt = BitConverter.ToInt32( BitConverter.GetBytes( a ), 0 );
    if ( aInt <  0 )
        aInt = Int32.MinValue - aInt;  // Int32.MinValue = 0x80000000

    int bInt = BitConverter.ToInt32( BitConverter.GetBytes( b ), 0 );
    if ( bInt < 0 )
        bInt = Int32.MinValue - bInt;

    int intDiff = Math.Abs( aInt - bInt );
    return intDiff <= ( 1 << maxDeltaBits );
}

EDIT: BitConverter is relatively slow. If you're willing to use unsafe code, then here is a very fast version:

    public static unsafe int FloatToInt32Bits( float f )
    {
        return *( (int*)&f );
    }

    public static bool AlmostEqual2sComplement( float a, float b, int maxDeltaBits )
    {
        int aInt = FloatToInt32Bits( a );
        if ( aInt < 0 )
            aInt = Int32.MinValue - aInt;

        int bInt = FloatToInt32Bits( b );
        if ( bInt < 0 )
            bInt = Int32.MinValue - bInt;

        int intDiff = Math.Abs( aInt - bInt );
        return intDiff <= ( 1 << maxDeltaBits );
    }

Further to Andrew Wang's answer: if the BitConverter method is too slow but you cannot use unsafe code in your project, this struct is ~6x quicker than BitConverter:

[StructLayout(LayoutKind.Explicit)]
public struct FloatToIntSafeBitConverter
{
    public static int Convert(float value)
    {
        return new FloatToIntSafeBitConverter(value).IntValue;
    }

    public FloatToIntSafeBitConverter(float floatValue): this()
    {
        FloatValue = floatValue;
    }

    [FieldOffset(0)]
    public readonly int IntValue;

    [FieldOffset(0)]
    public readonly float FloatValue;
}

(Incidentally, I tried using the accepted solution but it (well my conversion at least) failed some of the unit tests also mentioned in the answer. e.g. assertTrue(nearlyEqual(Float.MIN_VALUE, -Float.MIN_VALUE)); )