Мистика какая то. Можно узнать алгоритм?
Хотя ИИ предполагает, что сложность

, мои проверки показали, что для

результат получается за то же количество итераций (три). Но вероятно, тут

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

Может там например

...
Программа:
(Оффтоп)
- farey_min(frac1, frac2) = {
- /* Находит дробь с минимальным знаменателем между frac1 и frac2 */
- /* Сложность: O(log N) */
-
- my(
- /* Входные дроби в виде числитель/знаменатель */
- a = numerator(frac1), b = denominator(frac1),
- c = numerator(frac2), d = denominator(frac2),
-
- /* Границы дерева Штерна-Броко */
- l_num = 0, l_den = 1, /* левая граница: 0/1 */
- r_num = 1, r_den = 0, /* правая граница: 1/0 (∞) */
-
- /* Текущая медианта */
- m_num, m_den,
-
- /* Вспомогательные переменные для вычисления шага */
- num, den, k
-
- );
-
- /* Упорядочиваем: гарантируем a/b < c/d */
- if (a*d > b*c, [a,b,c,d] = [c,d,a,b]);
-
- while (1,
- m_num = l_num + r_num;
- m_den = l_den + r_den;
-
- if (m_num * b <= a * m_den,
- /* Медианта <= левой границы - прыгаем вправо */
- num = a*l_den - l_num*b;
- den = r_num*b - a*r_den;
- k = num \ den;
- if (k == 0, k = 1);
- l_num = l_num + k * r_num;
- l_den = l_den + k * r_den;
- ,
- if (m_num * d >= c * m_den,
- /* Медианта >= правой границы - прыгаем влево */
- num = r_num*d - c*r_den;
- den = c*l_den - l_num*d;
- k = num \ den;
- if (k == 0, k = 1);
- r_num = r_num + k * l_num;
- r_den = r_den + k * l_den;
- ,
- /* Медианта внутри интервала - найдено! */
- return (m_num / m_den);
- )
- )
- );
- }
-- 18.02.2026, 23:08 --Алгоритм Эвклида?
Разложение в непрерывную дробь и вычисление "родителей" в дереве Фарея. Сложность

где

- длина разложения в непрерывную дробь (плюс само разложение, это встроенная функция, там не знаю, но вроде сложность логарифмическая) .
Программа:
(Оффтоп)
- farey_parents(frac) = {
- /* Находит родительские дроби для ЛЮБОЙ дроби frac */
- /* Возвращает [left, right] где left < frac < right */
- my(p = numerator(frac), q = denominator(frac));
- /* Раскладываем в непрерывную дробь */
- my(cf = contfrac(frac));
- /* длиной n */
- my(n = #cf);
-
- /* Вычисляем все сходящие */
- my(pnm2 = 0, qnm2 = 1); /* p₋₂/q₋₂ */
- my(pnm1 = 1, qnm1 = 0); /* p₋₁/q₋₁ */
- my(pn, qn);
-
- for(i = 1, n-1,
- pn = cf[i]*pnm1 + pnm2;
- qn = cf[i]*qnm1 + qnm2;
- pnm2 = pnm1; qnm2 = qnm1;
- pnm1 = pn; qnm1 = qn;
- );
-
- /* pnm1/qnm1 = предпоследнее сходящее */
- /* pn/qn = последнее сходящее = исходная дробь */
-
- pn = cf[n]*pnm1 + pnm2;
- qn = cf[n]*qnm1 + qnm2;
-
- /* Левый родитель = предпоследнее сходящее */
- my(left = pnm1/qnm1);
-
- /* Правый родитель = (pn - pnm1) / (qn - qnm1) */
- my(right = (pn - pnm1) / (qn - qnm1));
-
- /* Упорядочиваем */
- if (left > right, [left, right] = [right, left]);
-
- return ([left, right]);
- }
Там есть косячок с упорядочиванием результата, но я пока не стал править.