Suppose that you have 100000 points on the curve y = x^2
. You want to find the convex hull of these points. All the coordinates are floating numbers.
In my graham scan implementation the only place where I operate on floating numbers is when I initially sort all the points by their coordinates and then I have one function that determines whether three points make a left or a right turn.
Points:
struct point {
double x;
double y;
};
Sorting comparator:
inline bool operator() (const point &p1, const point &p2) {
return (p1.x < p2.x) || (p1.x == p2.x && p1.y > p2.y);
}
Left/Right turn:
inline int ccw(point *p1, point *p2, point *p3) {
double left = (p1->x - p3->x)*(p2->y - p3->y);
double right = (p1->y - p3->y)*(p2->x - p3->x);
double res = left - right;
return res > 0;
}
My program says that out of 100 000 points only 68894 are part of the convex hull. But since they are on the curve, all of them should be part of the convex hull.
For your eye it doesn't make any difference. See figure below. The red points are part of the convex hull.
But if you look close enough, and zoom into the points, you'll see that some of them are blue, so they are not included in the convex hull.
Now my initial assumption is that floating point errors are causing this problem.
I guess I could use an external library that has an arbitrary precision for floating point numbers, but I'm more interested in the simple data types that we have for example in C++.
How could I increase the accuracy? I've read about epsilons, but how would using an epsilon help here? I would still assume some points that are close to each other to be the same, so I won't get an accuracy closer to 100%.
What's the best way to approach this problem?
long double
? – mchsqrt
orsin
, but will be exact for any polynomial with rational coefficients as long as the independent variable is rational as well. – triple_r