Эффективно определить, что рациональные числа равны

У меня есть набор из многих рациональных чисел с числителем и знаменателем каждого из них, которые хранятся в виде большого (сотни или тысячи бит) целых чисел без знака. Я хотел бы иметь возможность эффективно проверить, равно ли любое заданное рациональное число a/b в множестве любое другое рациональное число c/d в наборе.

Самый простой метод - проверить, будет ли a*d == b*c, конечно, но я бы хотел что-то более эффективное, чем вычисление полных продуктов.

Некоторые примечания по моему конкретному случаю использования:

  • Пар, которые я буду тестировать, имеет высокую вероятность быть равным (потому что я уже предварительно вычисляю и сравниваю их по их приближениям с плавающей запятой), поэтому ранние выходы, если они неравны, не спасут меня много времени.
  • Я в порядке с предварительным вычислением дополнительных данных для каждого из чисел, но каждый номер будет использоваться только в нескольких сравнениях, поэтому дорогостоящая предварительная вычисление (такая как простая факторизация), вероятно, не стоит.
  • Иногда ложные негативы бывают прекрасными, но ложных срабатываний нет.

Я думаю, что это может быть теоретически невозможно, но на всякий случай выбросить его в улей.

Ответы

Ответ 1

Вы можете отфильтровать многие не равные пары фракций, сравнивая длины бит. Пусть l (a) = floor (log2 (a)) + 1 длина бит a. Если a/b = c/d, чем l (a) + l (d) = l (c) + l (b).

Вы можете использовать это для ускорения, когда вы сначала сравниваете длины и сравниваете продукты, только если сумма длин равна.

Ответ 2

Вторая попытка;) Если вы должны повторно проверять новые номера для заданного ограничения, вы должны сохранить относительно простые дроби в упорядоченном наборе. Функция сравнения набора должна сначала сравнивать счетчики, а знаменатели, если счетчики равны. Сравнение может быть выполнено в линейном времени, и, таким образом, для нахождения элемента в упорядоченном множестве с элементами M требуются шаги O (N log M). Уменьшение стоимости фракции O (N ²). Таким образом, для тестирования номера для сдерживания требуются шаги O (N ² + N log M) и вычисления набора O (MN ²).

Изменить: Вместо использования сортированного или древовидного набора вы можете использовать хэш-набор, который уменьшает необходимое количество шагов для поиска O (N ² + N) = O (N ²).

Ответ 3

Это не будет очень полезно в вашем случае, если вы уже прекомпилируете приближение с плавающей запятой; он может по-прежнему сэкономить некоторое время в конвейере (или в некоторых приближениях).

Вы изучаете целочисленные значения a, b, c и d.

Рациональные числа, одинаковые, означают, что они описывают одну и ту же прямую через начало координат.

Если c > a, то также должно быть, что d > b, иначе мы были бы в серой области справа внизу; если c < а, наоборот, должно быть, что d < b, или мы будем в верхнем левом сером углу. Серые области не имеют возможности равенства, и если числа были случайными (т.е. Не фильтруемыми с аппроксимацией по платам), мы бы исключили N/2 из них с сравнениями N 2 bigint.

Из оставшихся 50% мы можем исключить половину, заметив, что если a > b, то черная линия находится ниже биссектрисы первого и третьего квадрантов, и должно быть, что c > d, иначе C/D будет быть на другой стороне биссектрисы; мы были бы в верхнем оранжевом секторе без какого-либо равенства. То же самое или < b кейс. Таким образом, другие два сравнения bigint уменьшают число, подлежащее проверке, до одной четверти оригинала; они могут быть аппроксимированы в плавающей точке, и если они "почти равны", мы находимся в крошечной красной зоне, где нужны другие методы.

Вы также можете расширить этот метод, заметив, что для любого k отношение a к kb должно быть таким же, как отношение между c и kd для того, чтобы a/b и c/d были равны; и если k - целая степень 2, что позволяет несколько возможных оптимизаций.

(В какой-то момент, конечно, стоимость этого будет превышать стоимость теста a*d==b*c).

числа на плоскости