.NET - floating point comparison

Comparing floating point numbers (double, float) in .net directly for equality is unsafe. The double value of the variable can change over time by a very small value. For example, if you set the variable num (double) to 0.2 objects, then after a while this object was waiting in memory, you may find that num became 0.1999999999999. So num == 0.2 will be false in this case. My solution to this problem is to create a property to round the number:

double Num { get{ return Math.Round(num, 1); } } 

After the Num call is called and the result is returned, can this returned number change to 0.19 again during the comparison (Num == 0.2)? This is unlikely, but is it guaranteed?

+6
source share
4 answers

Whether you believe it or not, this is intended behavior and conforms to some IEEE standard.

It is not possible to imagine an analog daily value, such as a massive number or a small fraction, with full precision in a single binary representation. Floating-point numbers in .NET, such as float or double, do everything possible to minimize the error when assigning numbers to them, so when you assigned the value 0.2 to a variable, the language did everything possible to select the representation with the least error.

Not that the number has somehow worsened in memory - it is a deliberate step. If you are comparing floating point numbers, you should always allow the region on either side of your comparison to be acceptable. Your representation of 0.2 is close to a very large number of decimal places. How much is enough for your application? It looks blatant to your eyes, but itโ€™s actually a very small mistake. When comparing doubles and floats (with integers or with each other), you should always consider acceptable accuracy and accept a range on both sides of the expected result.

You can also use other types, such as decimal , which has extremely good decimal precision - but is also very large compared to floats and doubles.

+3
source

No, this is not guaranteed.

From MSDN - Math.Round :

The behavior of this method follows the IEEE 754 standard, section 4. This type of rounding is sometimes called rounding to the nearest or rounding of the banker. It minimizes rounding errors that result from constant rounding of the average value in one direction.

(my emphasis)

Point - this minimizes , but does not guarantee.


When comparing floating point types, you should always test epsilon - the minimum value for which you don't care.

An example adapted from here :

 double dValue = 0.2; var diff = Math.Abs(num - dValue); if( diff < 0.0000001 ) // need some min threshold to compare floating points { // treat as equal } 

Recommended reading: What every computer scientist needs to know about floating point arithmetic .

+6
source

Variables do not change on their own. If a == b at one point in time, then a == b more and more until you change a or b.

You might have a problem with representability in floating point data types, but it's not clear what the problem is. Clearly, your current solution is almost certainly not a good idea.

+2
source

Use code like this to check double for equality:

 public static bool AreEqual(double d1, double d2, double delta) { return Math.Abs(d1 - d2) < delta; } 
0
source

Source: https://habr.com/ru/post/895448/


All Articles