Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 923
Kevin Gale Avatar asked Oct 06 '10 16:10

Kevin Gale


People also ask

Can we compare float values in C?

Floating point comparison in C++To compare two floating point values, we have to consider the precision in to the comparison. For example, if two numbers are 3.1428 and 3.1415, then they are same up to the precision 0.01, but after that, like 0.001 they are not same.

How do you compare floating points?

If we do have to compare two floating-point numbers then rather than using “==” operator we will find the absolute difference between the numbers (which if were correctly represented, the difference would have been 0) and compare it with a very small number 1e-9 (i.e 10^-9, this number is very small) and if the ...

Can we compare float and double in C?

Since the precision of float is less than the double therefore after a certain point(23 in float and 52 in double) it would truncate the result. Hence, after promotion of float into double(at the time of comparison) compiler will pad the remaining bits with zeroes.

What happens if we compare int with float in C?

Casting the int to a float explicitly will do absolutely nothing. The int will be promoted to a float for purposes of comparison anyway.


2 Answers

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;     } } 
like image 138
Michael Borgwardt Avatar answered Sep 22 '22 07:09

Michael Borgwardt


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 );     } 
like image 23
Andrew Wang Avatar answered Sep 24 '22 07:09

Andrew Wang