Python中的fractions.limit_denominator是如何实现的?

10
limit_denominator(max_denominator=1000000)
Finds and returns the closest Fraction to self that has denominator at most max_denominator. This method is useful for finding rational approximations to a given floating-point number:

>>>
>>> from fractions import Fraction
>>> Fraction('3.1415926535897932').limit_denominator(1000)
Fraction(355, 113)

不应该像尝试a/999、b/998、c/997这样的方法来寻找最佳近似值。


1
就我个人而言,作为“Fraction.limit_denominator”的原始作者,一直以来我都很困扰于正确性证明部分存在于我的脑海、零散笔记和在线书籍资源中。最近我需要修改代码,但花费了太长时间去回忆它的工作原理。所以10年后,我终于发布了一个证明:https://github.com/python/cpython/issues/95723 - Mark Dickinson
1个回答

4
< p> fractions 模块是使用 Python 编写的,您可以查看源代码。它包含以下注释。

    # Algorithm notes: For any real number x, define a *best upper
    # approximation* to x to be a rational number p/q such that:
    #
    #   (1) p/q >= x, and
    #   (2) if p/q > r/s >= x then s > q, for any rational r/s.
    #
    # Define *best lower approximation* similarly.  Then it can be
    # proved that a rational number is a best upper or lower
    # approximation to x if, and only if, it is a convergent or
    # semiconvergent of the (unique shortest) continued fraction
    # associated to x.
    #
    # To find a best rational approximation with denominator <= M,
    # we find the best upper and lower approximations with
    # denominator <= M and take whichever of these is closer to x.
    # In the event of a tie, the bound with smaller denominator is
    # chosen.  If both denominators are equal (which can happen
    # only when max_denominator == 1 and self is midway between
    # two integers) the lower bound---i.e., the floor of self, is
    # taken.

看起来像是二分查找,将 x 夹在“最佳下限”和“最佳上限”近似值之间。 - Thomas Ahle
1
@ThomasAhle 不,这不是二分查找。它涉及到连分数。维基百科上的连分数文章有一个章节介绍了其背后的理论。(我曾经写过一篇博客文章,但没有什么特别之处,维基百科可能更好阅读。) - ShreevatsaR
1
@ShreevatsaR:“二分查找”并不完全离谱,从正确的角度来看。 连分数展开正在遍历Stern-Brocot树,然后通过使用完整的除法而不是简单的减法来加速该遍历。 Ian Richards撰写的文章“无泪连分数”非常好地阐述了这个想法:https://www.maa.org/sites/default/files/pdf/upload_library/22/Allendoerfer/1982/0025570x.di021121.02p0002y.pdf 。 另一方面,正确性的证明实际上并不需要连分数:https://github.com/python/cpython/issues/95723 - Mark Dickinson
@MarkDickinson 谢谢分享!(还有感谢 limit_denominator;我经常使用它。在了解它之前,我写了自己的网络工具,必须手动使用...)我会研究你提到的来源。与此同时,即使它遍历一个恰好是二叉树的概念树,我仍然认为它不应该被称为二分查找:二分查找的主要特点是使用测试(通常是比较)来确定要进一步探索哪一半,而这里似乎缺少了。 (Richards文章指向了Stark的书,我正在享受中...) - ShreevatsaR
@MarkDickinson 在阅读了Richards的文章后,我明白你的意思了:如果你以不同的方式实现算法(文章中称为“缓慢连分数法”或“费雷过程”),那么它确实是一种二分查找。因此,这可以被视为二分查找的优化版本(在这种情况下,是否仍然称其为二分查找是另一个问题...)。我会努力消化这些内容的,再次感谢! - ShreevatsaR
@ShreevatsaR:是的,我同意称当前算法为二分查找有点勉强。 :-) - Mark Dickinson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接