Природа чисел с плавающей запятой означает, что нет смысла проверять, является ли число с плавающей запятой рациональным, поскольку все числа с плавающей запятой на самом деле являются дробями вида n em > / 2 e. Однако вы можете захотеть узнать, существует ли простая дробь (с малым знаменателем, а не с большой степенью двойки), которая близко аппроксимирует данное число с плавающей запятой.
Дональд Кнут обсуждает эту последнюю проблему в томе II Искусство компьютерного программирования. См. Ответ к упражнению 4.53–39. Идея состоит в том, чтобы искать дробь с наименьшим знаменателем в пределах диапазона, расширяя конечные точки диапазона как непрерывные дроби, пока их коэффициенты равны, а затем, когда они различаются, брать простейшее значение между ними. Вот довольно простая реализация на Python:
from fractions import Fraction
from math import modf
def simplest_fraction_in_interval(x, y):
"""Return the fraction with the lowest denominator in [x,y]."""
if x == y:
# The algorithm will not terminate if x and y are equal.
raise ValueError("Equal arguments.")
elif x < 0 and y < 0:
# Handle negative arguments by solving positive case and negating.
return -simplest_fraction_in_interval(-y, -x)
elif x <= 0 or y <= 0:
# One argument is 0, or arguments are on opposite sides of 0, so
# the simplest fraction in interval is 0 exactly.
return Fraction(0)
else:
# Remainder and Coefficient of continued fractions for x and y.
xr, xc = modf(1/x);
yr, yc = modf(1/y);
if xc < yc:
return Fraction(1, int(xc) + 1)
elif yc < xc:
return Fraction(1, int(yc) + 1)
else:
return 1 / (int(xc) + simplest_fraction_in_interval(xr, yr))
def approximate_fraction(x, e):
"""Return the fraction with the lowest denominator that differs
from x by no more than e."""
return simplest_fraction_in_interval(x - e, x + e)
И вот некоторые результаты:
>>> approximate_fraction(6.75, 0.01)
Fraction(27, 4)
>>> approximate_fraction(math.pi, 0.00001)
Fraction(355, 113)
>>> approximate_fraction((1 + math.sqrt(5)) / 2, 0.00001)
Fraction(377, 233)
person
Gareth Rees
schedule
24.11.2010