Проверьте, является ли число рациональным в Python
Я хотел бы знать хороший способ проверить,является ли число x рациональным (два целых числа n, m существуют так, что x=n/m) в python.
в mathematica это делается функцией
Rationalize[6.75]
27/4
Я предполагаю, что этот вопрос имеет ответ на заданную точность. Существует ли общий алгоритм получения этих двух целых чисел?
7 ответов
в python >= 2.6 есть as_integer_ratio
способ на поплавках:
>>> a = 6.75
>>> a.as_integer_ratio()
(27, 4)
>>> import math
>>> math.pi.as_integer_ratio()
(884279719003555, 281474976710656)
однако, из-за того, как поплавки определены в языках программирования нет иррациональных чисел.
природа чисел с плавающей точкой означает, что нет смысла Регистрация если число с плавающей запятой рационально, так как все числа с плавающей запятой действительно являются дробями вида n / 2e. Тем не менее, вы вполне можете захотеть узнать, есть ли простой дробь (одна с небольшим знаменателем, а не с большой степенью 2), которая близко аппроксимирует данное число с плавающей запятой.
Дональд Кнут обсуждает эту последнюю проблему в Искусство программирования том 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)
любое число с конечным десятичным разложением является рациональным числом. Вы всегда можете решить, например
5.195181354985216
говоря, что это соответствует
5195181354985216 / 1000000000000000
так как поплавки и двойники имеют конечную точность, они все рациональны.
Python использует представление с плавающей запятой, а не рациональные числа. Взгляните на стандартная библиотека fractions
модуль для некоторых деталей о рациональных числах.
понаблюдайте, например, за этим, чтобы понять, почему это идет не так:
>>> from fractions import Fraction
>>> 1.1 # Uh oh.
1.1000000000000001
>>> Fraction(1.1) # Will only work in >= Python 2.7, anyway.
Fraction(2476979795053773, 2251799813685248)
>>> Fraction(*1.1.as_integer_ratio()) # Python 2.6 compatible
Fraction(2476979795053773, 2251799813685248)
(Ах, вы хотите увидеть случай, когда он работает?)
>>> Fraction('1.1')
Fraction(11, 10)
Как вы заметили, любое число с плавающей запятой может быть преобразовано в рациональное число путем перемещения десятичной точки и деления на соответствующую степень десять.
затем вы можете удалить наибольший общий делитель из дивиденда и делителя и проверить, соответствуют ли оба эти числа типу данных по вашему выбору.
проблема с вещественными числами в языках программирования заключается в том, что они обычно определяются как функции, возвращающие конечное представление с заданной точностью (например. функция, которая принимает n в качестве аргумента и возвращает число с плавающей запятой в пределах точности 2^-n).
вы можете определенно превратить рациональное / целое число в реальное, но даже сравнение реальных значений для равенства неразрешимо (это, по сути, проблема остановки).
вы не можете сказать, является ли действительное число x рациональный: даже в математике это обычно сложно, так как вы должны найти p и q такие, что x = p/q, и это часто не конструктивно.
однако, учитывая окно точности, вы можете найти" лучшее " рациональное приближение для этой точности, используя, например, непрерывное разложение дробей. Я считаю, что это по существу то, что делает mathematica. Но в вашем примере 6.75 уже рационально. Попробуйте вместо этого с Pi.