在Python中检查一个数是否是有理数,给定浮点精度
我想知道在Python中,有什么好的方法来检查一个数字x是否是有理数(也就是说,是否存在两个整数n和m,使得x=n/m)。
在Mathematica中,可以通过函数Rationalize[6.75]
来实现,结果是27/4
。
我想这个问题应该有一个针对特定精度的答案。有没有什么常用的算法可以用来找到这两个整数呢?
7 个回答
7
任何有有限小数位的数字都是有理数。你可以通过以下方式来解决这个问题:
5.195181354985216
这就意味着它对应于
5195181354985216 / 1000000000000000
所以,由于浮点数和双精度数的精度是有限的,它们都是有理数。
10
浮点数的特性决定了我们没必要去“检查”一个浮点数是否是有理数,因为所有的浮点数实际上都是形如 n / 2e 的分数。不过,你可能想知道有没有一个“简单”的分数(也就是分母比较小,而不是大得离谱的2的幂)能够很好地接近某个给定的浮点数。
唐纳德·克努斯在他的书《计算机程序设计艺术》第二卷中讨论了这个问题。你可以看看第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)
20
在Python 2.6及以上版本中,浮点数(也就是小数)有一个叫做 as_integer_ratio
的方法:
>>> a = 6.75
>>> a.as_integer_ratio()
(27, 4)
>>> import math
>>> math.pi.as_integer_ratio()
(884279719003555, 281474976710656)
不过,由于编程语言中浮点数的定义,是没有无理数的。