Предположим, что у вас есть 100000 точек на кривой y = x^2
. Вы хотите найти выпуклую оболочку этих точек. Все координаты являются плавающими числами.
В моей реализации сканирования Грэма единственное место, где я работаю с плавающими числами, — это когда я сначала сортирую все точки по их координатам, а затем у меня есть одна функция, которая определяет, делают ли три точки поворот влево или вправо.
Точки:
struct point {
double x;
double y;
};
Сортировочный компаратор:
inline bool operator() (const point &p1, const point &p2) {
return (p1.x < p2.x) || (p1.x == p2.x && p1.y > p2.y);
}
Левый/правый поворот:
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;
}
Моя программа говорит, что из 100 000 точек только 68894 являются частью выпуклой оболочки. Но поскольку они находятся на кривой, все они должны быть частью выпуклой оболочки.
Для вашего глаза это не имеет никакого значения. См. рисунок ниже. Красные точки являются частью выпуклой оболочки.
Но если вы посмотрите достаточно близко и приблизите точки, вы увидите, что некоторые из них синие, поэтому они не включены в выпуклую оболочку.
Теперь мое первоначальное предположение состоит в том, что ошибки с плавающей запятой вызывают эту проблему.
Думаю, я мог бы использовать внешнюю библиотеку с произвольной точностью для чисел с плавающей запятой, но меня больше интересуют простые типы данных, которые есть, например, в C++.
Как я могу повысить точность? Я читал об эпсилонах, но как здесь поможет использование эпсилонов? Я бы по-прежнему считал некоторые точки, которые близки друг к другу, одинаковыми, поэтому я не получу точность ближе к 100%.
Как лучше всего подойти к этой проблеме?
long double
? - person mch   schedule 30.09.2014sqrt
илиsin
, но будет точным для любого многочлена с рациональными коэффициентами, если независимая переменная также рациональна. - person triple_r   schedule 30.09.2014