【问题标题】:Calculating large fractions in Python?在 Python 中计算大分数?
【发布时间】:2018-05-02 17:24:04
【问题描述】:

我正在尝试在 Python 2.7 中计算分数。 limit_denominator 方法非常适合此代码的前 15 次迭代。但是,然后代码陷入循环,输出的分母小于 1,000,000

Fraction = 1217471/860882

当我不使用limit_denominator 时,我会得到这样的重复输出:

Fraction = 141421356237/100000000000

最终我想将i 迭代到 1000,所以我的分数会非常大。有什么帮助吗?

from fractions import *
i = 0
x = 1/2.0
x1 = 0
count = 0
while i < 20:
    (y) = (1.0 + (x))
    (x) = (1 / (2.0 + (x)))
    y1 = Fraction(str(y)).limit_denominator()
    print("\nFraction = " + str(y1))
    i += 1

【问题讨论】:

  • 我已经编辑将i += 1 放在while 循环中,否则你会有一个无限循环(我假设你不想要)。发布问题时请检查缩进。
  • 您不需要所有这些括号。写y = 1 + x,而不是(y) = (1.0 + (x)),其他行类似。
  • 也就是说,我无法使用您发布的代码重现该问题。最终,输出只是Fraction = 665857/470832

标签: python fractions


【解决方案1】:

这些值收敛到 sqrt(2.0),它为您提供了一个窄范围的分数,可以准确地表示 64 位浮点值。你的有理分数不能比你给它的float 更准确。

如果您想要更大的分母,那么您必须指定更大的分母限制。您仍然受到float 准确性的限制:一旦您在计算类型的准确性范围内收敛(可能是float64),您的理性表示将不会获得更高的准确性。如果您想要更高的准确性,请将整体转换为fraction 计算:

from fractions import *

x = Fraction(1,2)

for i in range(40):
    y = Fraction(1) + x
    x = Fraction(1) / (Fraction(2) + x)
    print("Fraction = " + str(y))

输出:

Fraction = 3/2
Fraction = 7/5
Fraction = 17/12
Fraction = 41/29
Fraction = 99/70
Fraction = 239/169
Fraction = 577/408
Fraction = 1393/985
Fraction = 3363/2378
Fraction = 8119/5741
Fraction = 19601/13860
Fraction = 47321/33461
Fraction = 114243/80782
Fraction = 275807/195025
Fraction = 665857/470832
Fraction = 1607521/1136689
Fraction = 3880899/2744210
Fraction = 9369319/6625109
Fraction = 22619537/15994428
Fraction = 54608393/38613965
Fraction = 131836323/93222358
Fraction = 318281039/225058681
Fraction = 768398401/543339720
Fraction = 1855077841/1311738121
Fraction = 4478554083/3166815962
Fraction = 10812186007/7645370045
Fraction = 26102926097/18457556052
Fraction = 63018038201/44560482149
Fraction = 152139002499/107578520350
Fraction = 367296043199/259717522849
Fraction = 886731088897/627013566048
Fraction = 2140758220993/1513744654945
Fraction = 5168247530883/3654502875938
Fraction = 12477253282759/8822750406821
Fraction = 30122754096401/21300003689580
Fraction = 72722761475561/51422757785981
Fraction = 175568277047523/124145519261542
Fraction = 423859315570607/299713796309065
Fraction = 1023286908188737/723573111879672
Fraction = 2470433131948081/1746860020068409

【讨论】:

    【解决方案2】:

    我重写了你的代码试图解决你的问题,因为我不明白limit_denominator 的必要性。结果如下:

    from fractions import *
    x = Fraction(1, 2)
    for i in range(1000):
        y = 1 + Fraction(x)
        print 'Y', y
        x = 1 / (2 + x)
        print 'X', x
    

    问题在于计算机并不真正理解数字,而是使用内存中数字的抽象表示形式 floating point(我假设是 float 的起源)。此表示具有给定的精度(限制),这取决于为数据类型保留的内存量。这就是为什么int32 接受的值比int64 少的原因。
    但是,python 有一种智能且高效的计算大数的方法。 此外,分数库为您提供了一种表示数字(分数)的方法,这些数字(分数)逃脱了(不是真的,毕竟它是一台计算机)floating point 数字约束。 如果你想深入了解floating point arithmetic,我推荐全能的Numerical Analysis by Burden &amp; FairesNumerical Methods by Dr David Ham

    【讨论】:

    • 我不确定你在这里想说什么。当然,现代 CPU 提供浮点支持,但它们也支持各种大小的整数;早期的 CPU 只有整数指令,系统通过软件提供浮点支持。
    • 不确定您的疑问是什么。我想说的是,在使用floats 时,如果您尝试表示大数,由于floating point 算术,数字将truncated 变为尾数的大小,从而导致1e100 + 1 = 1e100 之类的奇怪事情而0.8 * 3 == 0.3 * 8 是假的。对不起,如果我不能说清楚。
    • 我没有怀疑任何事情。您声称计算机“使用称为浮点数的内存中数字的抽象表示形式工作”。我只是简单地指出,并不是所有的计算机算术都是用浮点完成的,事实上很多早期的计算机都没有对浮点算术的硬件支持。
    • aaaah,好的,抱歉,我是在概括,我的错。感谢您指出这一点
    【解决方案3】:

    正如 Prune 所说,使用 Fraction 时最好避免浮动。如果你想在不损失任何准确性的情况下将分数转换为小数,你需要使用像 Decimal 这样具有足够精度的数字类型。另一种选择是只使用 Python 整数,并使用足够大的乘数放大分子。

    您的系列找到了 2 的平方根 continued fraction 的收敛值。如果你想遍历所有收敛,你可以使用 Prune 的答案中显示的算法。但是如果你想快速计算 sqrt(2) 到大量位数,还有一种更好的方法,称为 Hero 方法(或 Heron 方法)。这是牛顿计算代数方程根的方法的一个特例。我们不是在 Prune 的算法中逐一计算每个 i 的项,而是在每次迭代中将 i 加倍,因此分子和分母增长得非常快,每次循环迭代时答案的准确性加倍。

    这是一个简短的演示,它计算 sqrt(2) 精确到 100 位。我通常会使用纯 Python 整数(或 Python 2 中的长整数)来执行此操作,但使用分数也很容易。

    from __future__ import print_function
    from fractions import Fraction as F
    
    digits = 100
    m = 10 ** digits
    
    x = F(1, 1)
    while x.denominator < m:
        print(x)
        x = x / 2 + 1 / x
    
    print()
    print(m * x.numerator // x.denominator)
    

    输出

    1
    3/2
    17/12
    577/408
    665857/470832
    886731088897/627013566048
    1572584048032918633353217/1111984844349868137938112
    4946041176255201878775086487573351061418968498177/3497379255757941172020851852070562919437964212608
    48926646634423881954586808839856694558492182258668537145547700898547222910968507268117381704646657/34596363615919099765318545389014861517389860071988342648187104766246565694525469768325292176831232
    
    14142135623730950488016887242096980785696718753769480731766797379907324784621070388503875343276415727
    

    在 Python 2.6 和 3.6 上测试

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多