在Python中检查一个数是否是有理数,给定浮点精度

11 投票
7 回答
15185 浏览
提问于 2025-04-16 07:32

我想知道在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)

不过,由于编程语言中浮点数的定义,是没有无理数的

撰写回答