PDA

View Full Version : QPolygonF precision?! is it possible?!



fatecasino
12th January 2011, 02:44
I have this QPolygonF



selectedPolygon<< QPointF(1.47 ,52.21);
selectedPolygon<< QPointF(1.50 ,53.12);
selectedPolygon<< QPointF(1.52 ,54.48);
selectedPolygon<< QPointF(1.55,55.84);
selectedPolygon<< QPointF(1.57 ,57.20);
selectedPolygon<< QPointF(1.60 ,58.57);
.....................................
selectedPolygon<< QPointF(1.73 ,66.28);
selectedPolygon<< QPointF(1.75 ,68.10);
selectedPolygon<< QPointF(1.78 ,69.92);
selectedPolygon<< QPointF(1.80,72.19);
selectedPolygon<< QPointF(1.83 ,74.46);

and in debug mode when I get back these values:

int N = selectedPolygon.size();
for (int i = 0; i < N; i++)
{
x = selectedPolygon.at(i).x();
y = selectedPolygon.at(i).y();
........
}

the values comeback as:

(1.47, 52.210000000000001)
(1.5, 53.119999999999997)
(1.52, 54.479999999999997)
(1.55, 55.840000000000003)
(1.5700000000000001, 57.200000000000003)
.........................

this change causes huge errors to my calculations!!!!!!
why is this happening? is there a way to avoid it??!

tbscope
12th January 2011, 04:33
This happens because computers (any computer) have finite precision (rounding errors for example)
When dealing with precision calculations, this is a huge factor to deal with.

It is however possible to do precision calculations with the help of a few tricks.

In your case, I think it is a good idea to round the number to the nearest best value, 2 decimals. As you notice, your computer can be a lot more precise than the numbers you use, you just have to round them once more yourself. This (dealing with the precision of a computer) can be a speed penalty.
Also make sure you use the same kind of variable when reading or setting the values to minimize conversions.

SixDegrees
12th January 2011, 08:07
Also, if these tiny discrepancies are causing "huge errors" in your calculations, you need to rethink those calculations in terms of the limits imposed by floating point math operations. For example, you should never take branches based on a floating point number being identically equal to another; instead, you should check that they are within some small distance. The C++ STL provides some support for this.

MarekR22
12th January 2011, 08:09
To visualize the problem try to write 1/3 in decimal based number system, you will get 0.333333(3).
So same problem is with 1/10 in binary based system. When you converting numbers from decimal to binary (with limit of bits) and then back from binary to decimal the result might be different then initial value.

fatecasino
12th January 2011, 14:10
you are definitely right! In my Msc I did a lot of Numerical analysis, but I never met such a thing.
Finite precision errors would occur in exceptional situations that I should take care.
like finding the solution of

(x-0.0000000000000000001)*(x-0.1)*(x-0.0000000000099), or whatsoever.

Now it's like storing a simple value "1.52" and never been able to receive it back as it is (1.52).
I have used several programming languages but I don't remember having such a problem before.
Can you suggest any Qt function to round or even chop off digits?(if this is the only solution)

tbscope
12th January 2011, 14:28
Check http://doc.trolltech.com/latest/qtglobal.html

This isn't something specific to a programming language, this is inherent to any computer.

wysota
12th January 2011, 21:14
There are libraries for fixed point arithmetics available. What they do is that they store numbers in a custom format (like storing digits separaterly) and guarantee you the exact precision you declare. The downside is that calculations using such numbers are much slower because they have to be implemented in software.

fatecasino
26th January 2011, 18:07
Knowing the nature of my datasets i try to set the precision at the 4th decimal digit.
So, what happens so far is that

actual value read from data file: 0.1
value after converting QString to Double (toDouble() ): 0.10000000000000001
then I created this rounding function

double my2dPlot::round_nplaces(double value, int to)
{
double a, b,c, places = pow(10.0, to);//to = 4, places = 10000
a= value * places;// a = 1000
b= round(value * places);// b = 1000
c = b/ places;// c = 0.10000000000000001 ????!
return round(value * places) / places;

}

how is it possible to get c = 1000/10000 = 0.10000000000000001 ?!
shouldn't it be 0.1?

wysota
26th January 2011, 23:09
No, computers work in binary and not decimal values. Apparently there is no binary representation for 1000/10000. If you haven't done so yet, read this: http://en.wikipedia.org/wiki/Floating_point

fatecasino
27th January 2011, 00:00
very good article, thanks wysota!
hence
if I cannot represent a float/double with the precision i want,
if I cannot round the represented float number to the digit I want,
what is the proposed solution to read in the string "0.5" from a text and store to a double/float value as 0.5?

wysota
27th January 2011, 01:03
See post #7.

ChrisW67
27th January 2011, 02:36
if I cannot round the represented float number to the digit I want,

For the purposes of display in decimal there is nothing to stop you rounding the floating point number at a suitable number of decimal digits: see QString::number(). If you are using a float (32-bit) then you can expect about 7 significant digits and double gives 16. Your example data only has four or five digits. For the vast majority of store, retrieve and light manipulation purposes this quite adequate.