В дальнейшем я собираюсь предположить, что наши десятичные дроби находятся в диапазоне от 0 до 1. Это должно быть просто адаптировать это к большим числам и отрицательным числам.
Вероятно, проще всего было бы выбрать наибольший знаменатель, который вы сочтете приемлемым, и затем создать список дробей от 0 до 1, у которых этот знаменатель меньше или равен им. Обязательно избегайте дробей, которые можно упростить. Очевидно, что после того, как вы перечислили 1/2, вам не нужно 2/4. Вы можете избежать дробей, которые можно упростить, проверив, что GCD числителя и знаменателя 1 соответствует алгоритму Евклида. Как только у вас есть свой список. Оцените их как числа с плавающей точкой (вероятно, удваивается, но тип данных, очевидно, зависит от вашего выбора языка программирования). Затем вставьте их в сбалансированное двоичное дерево поиска, хранящее как исходную дробь, так и оценку дроби с плавающей запятой. Вам нужно сделать это только один раз, чтобы изначально все настроить, чтобы время n * log (n) (где n - количество дробей) было не очень большим.
Затем, всякий раз, когда вы получаете число, просто ищите дерево, чтобы найти ближайший к нему номер, который находится в дереве поиска. Обратите внимание, что это немного сложнее, чем поиск точного соответствия, потому что искомый узел может не быть конечным узлом. Таким образом, при прохождении дерева ведите учет ближайшего узла, который вы посетили. Как только вы достигнете конечного узла и сравните его с вашим ближайшим узлом, который вы посетили, все готово. Какой бы ни был ваш самый близкий, это ответ на ваш вопрос.