Рассмотрим класс типа double
class path_cost {
double length;
double time;
};
Если я хочу лексикографически упорядочить список path_costs
, у меня проблема. Читайте дальше:)
Если я использую точное равенство для теста на равенство, вот так
bool operator<(const path_cost& rhs) const {
if (length == rhs.length) return time < rhs.time;
return length < rhs.length;
}
результирующий порядок, вероятно, будет неправильным, потому что небольшое отклонение (например, из-за неточностей в расчете длины) может привести к сбою теста длины, так что, например,
{ 231.00000000000001, 40 } < { 231.00000000000002, 10 }
ошибочно удерживается.
Если я альтернативно использую допуск, подобный этому
bool operator<(const path_cost& rhs) const {
if (std::fabs(length-rhs.length)<1-e6)) return time < rhs.time;
return length < rhs.length;
}
тогда алгоритм сортировки может ужасно потерпеть неудачу, так как оператор <больше не является транзитивным (то есть, если a <b и b <c, то a <c может не выполняться) </p>
Есть идеи? Решения? Я думал о разбиении реальной линии, чтобы числа в каждом разделе считались равными, но это все равно оставляет слишком много случаев, когда проверка на равенство не проходит, но не должна.
(ОБНОВЛЕНИЕ Джеймса Керрана, надеюсь, объясняя проблему):
Даны цифры:
- A = {231.0000001200, 10}
- B = {231.0000000500, 40}
C = {231.0000000100, 60}
- A. Длина и B. Длина отличаются на 7-e7, поэтому мы используем время, и A
B. Длина и C. Длина отличаются на 4-е7, поэтому мы используем время, а B
A.Length и C.Length отличаются на 1,1-e6, поэтому мы используем длину и A> C.
(Обновление Эсбен Мозе Хансен)
Это не чисто теоретическое. Стандартные алгоритмы сортировки имеют тенденцию к сбою или, что хуже, при использовании нетранзитивного оператора сортировки. И это именно то, с чем я спорил (а мальчику было так весело отлаживать;))