October 24, 2011

Jupiter Jupiter
Lab Rat
95 posts

comparing doubles properly

 

Hi,

i have a problem with a piece of code:

  1. qreal a = 0.0f;
  2. Q_ASSERT(qAbs(a) == 0)

this causes sometimes to throw the assert, and sometimes not. but why? in my real there is a value like 6.0*10^-311 so its almost 0 but it is not 0, so the assert is right. but why isn’t it 0 when i initialized it with 0?

6 replies

October 24, 2011

Lukas Geyer Lukas Geyer
Lab Rat
2074 posts

This is due to limited precision of floating point numbers. Use qFuzzyCompare() [doc.qt.nokia.com] instead.

October 27, 2011

Jupiter Jupiter
Lab Rat
95 posts

thanks.

I also found the method qFuzzyIsNull() its not in the doc, but compares the parameter with 0.0 thats exactly what i need

October 27, 2011

ardhitama ardhitama
Lab Rat
8 posts

  1. qreal a = 0.0f;
  2. Q_ASSERT(qAbs(a) < 1e-8 && qAbs(a) > 0.0f)

Comparing to real number to zero is almost not possible in reality, but if you dare, you could also try this:

  1. qreal a = 0.0f;
  2. Q_ASSERT(qAbs(a) == 0.0f)

 Signature 

Love automagically stuffs

October 27, 2011

Volker Volker
Ant Farmer
5428 posts

Jupiter wrote:
thanks.

I also found the method qFuzzyIsNull() its not in the doc, but compares the parameter with 0.0 thats exactly what i need

qFuzzyIsNull is declared internal in the sources. Usually that’s for a reason…

You might want to open a request to make it officially public in the bug tracker [bugreports.qt.nokia.com] though.

October 24, 2013

Al79 Al79
Lab Rat
14 posts

I guess this is the reason:

“Donald Knuth a famous computer scientist, suggested the following method in his book “The Art of Computer Programming, Volume II: Seminumerical Algorithms (Addison-Wesley, 1969)”:

  1. bool IsEqual(double dX, double dY)
  2. {
  3.     const double dEpsilon = 0.000001; // or some other small number
  4.     return fabs(dX - dY) <= dEpsilon * fabs(dX);
  5. }

dEpsilon is a very small value (eg. 0.000001) that is used to help define what “close enough” is. fabs() is a function in the standard library (#include <cmath>) that returns the absolute value of it’s double parameter.[…]”

look at this link for more details [learncpp.com]

You surely just solved, but maybe it could be useful for someone else….

October 31, 2013

Asperamanca Asperamanca
Robot Herder
673 posts

The epsilon method is useful, but with a fixed epsilon, it will only work properly for a certain range of values.

This is why qFuzzyCompare uses a variable epsilon, depending on the values compared. However, when getting very close to zero, the epsilon becomes zero as well, and it’s no longer a fuzzyCompare.

I solved this by writing a wrapper that checks whether both compared values are very close to zero, then add a fixed amount (e.g. 1.0) to both of them. That way, the qFuzzyCompare I call internally never sees values that are close to zero, and works.

One word of warning: When using a fuzzy compare, expect that a value can both be equal and greater/lesser.
For example, when you first have

  1. if (fuzzyIsEqual(a, b)

but later realize that all you need is a > b, you might think that you no longer need a fuzzyCompare. Of course you can replace the code with

  1. if (a > b)

but this will not trigger in cases when the previous code did, and might cause unexpected results.

Better, in this case to do a

  1. if (fuzzyIsGreaterOrEqual(a, b)

(which of course you have to write yourself first)

 
  ‹‹ QLocalServer with Win32 pipe      New to Qt, question about code converstion ››

You must log in to post a reply. Not a member yet? Register here!