Найти простое рациональное число между двумя заданными рациональными числами

Я нашел проблему, связанную с рациональными числами.

приведены два рациональных числа, и задача состоит в том, чтобы найти простейшее рациональное число между ними.

для этой проблемы простота рационального числа может быть определена как рациональное число с наименьшим числителем, хотя я открыт для других предложений по этой метрике, например подобный вопрос к математике stack exchange, если это упрощает решение.

образец входы и выходы могут быть:

Inputs: 1110/416 and 1110/417, Output: 8/3
Inputs: 500/166 and 500/167, Output: 3/1

любые идеи или, по крайней мере совет, как решить эту проблему? Я борюсь.

спасибо

изменить:

дополнительные замечания:

  • тривиальным решением может быть просто попробовать все комбинации числителя / знаменателя (от 1 до самого высокого числителя или знаменателя соответственно), уменьшите их и посмотрите, находится ли число между ними. Я не уверен, какова будет сложность O, но я бы предположил что-то вроде n2.

3 ответов


соответствующая математика описана в статье Википедии о продолжение фракций. Короче говоря, вы вычисляете две непрерывные фракции для нижней и верхней конечных точек, а затем пробуете четыре комбинации, где непрерывная фракция усекается после общей конечной точки.

вот реализация Python.

import fractions


F = fractions.Fraction


def to_continued_fractions(x):
    a = []
    while True:
        q, r = divmod(x.numerator, x.denominator)
        a.append(q)
        if r == 0:
            break
        x = F(x.denominator, r)
    return (a, a[:-1] + [a[-1] - 1, 1])


def combine(a, b):
    i = 0
    while i < len(a) and i < len(b):
        if a[i] != b[i]:
            return a[:i] + [min(a[i], b[i]) + 1]
        i += 1
    if i < len(a):
        return a[:i] + [a[i] + 1]
    if i < len(b):
        return a[:i] + [b[i] + 1]
    assert False


def from_continued_fraction(a):
    x = fractions.Fraction(a[-1])
    for i in range(len(a) - 2, -1, -1):
        x = a[i] + 1 / x
    return x


def between(x, y):
    def predicate(z):
        return x < z < y or y < z < x

    return predicate


def simplicity(x):
    return x.numerator


def simplest_between(x, y):
    return min(filter(between(x, y), (from_continued_fraction(combine(a, b)) for a in to_continued_fractions(x) for b in to_continued_fractions(y))), key=simplicity)


print(simplest_between(F(1110, 416), F(1110, 417)))
print(simplest_between(F(500, 166), F(500, 167)))

предположим, числитель хорош, если есть некоторый знаменатель, который приводит к рациональному числу между вашими входами.

вы можете проверить, хорош ли числитель в O (1). Скажем, вы хотите проверить числитель n,и ваши входные данные w,x (для w/x) и y, z (для y/z).

n хорошо, если есть целое число между nx / w, и nz / y.

затем вы можете сделать это в O (хороший числитель), проверив все числители, пока не найдете тот, который хорош. Если конечные точки действительны,это занимает не более минуты(w, y).


вы можете попробовать следующие :

  • цикл от одного числителя к другому
  • внутри этого цикла, цикл от одного знаменателя к другому. Лемма заключается в том, что каждая фракция, созданная циклом, находится между двумя конечными фракциями.
  • для каждой фракции, упростить его нахождение наибольший общий делитель числителя и знаменателя и разделить числитель на это. Это должно позволить вам найти самый маленький числитель. алгоритм Евклида делает это в O (log n).