【问题标题】:Python prevent overflow errors while handling large floating point numbers and integersPython 在处理大浮点数和整数时防止溢出错误
【发布时间】:2014-06-28 13:39:45
【问题描述】:

我正在开发一个 python 程序来计算斐波那契数列中的数字。这是我的代码:

import math
def F(n):
    return ((1+math.sqrt(5))**n-(1-math.sqrt(5))**n)/(2**n*math.sqrt(5))
def fib(n):
    for i in range(n):
        print F(i)

我的代码使用这个公式来查找斐波那契数列中的第 N 个数字:

这可以计算斐波那契数列中的许多数字,但我确实遇到了溢出错误。

如何改进此代码并防止溢出错误?

注意:我使用的是 python 2.7。

【问题讨论】:

  • 您可以访问numpy 吗?该库具有 64 位浮点类型 (numpy.float64)。它不会防止溢出,但会增加到达那里的上限。我了解一些编译器支持numpy.float128
  • @SethMMorton:Python floats 已经是 64 位的了。

标签: python optimization sequence fibonacci integer-overflow


【解决方案1】:

Python 的整数是任意精度的,因此如果您使用交互算法计算斐波那契数列,则可以计算出精确的结果。

>>> def fib(n):
...   a = 0
...   b = 1
...   while n > 0:
...     a, b = b, a + b
...     n = n - 1
...   return a
... 
>>> fib(100)
354224848179261915075L

有几个可用于 Python 的多精度浮点库。 decimal 模块包含在 Python 中,最初用于财务计算。它确实支持sqrt(),因此您可以执行以下操作:

>>> import decimal
>>> decimal.setcontext(decimal.Context(prec=40))
>>> a=decimal.Decimal(5).sqrt()
>>> a
Decimal('2.236067977499789696409173668731276235441')
>>> ((1+a)**100 - (1-a)**100)/(a*(2**100))
Decimal('354224848179261915075.0000000000000000041')

其他库是mpmathgmpy2

>>> import gmpy2
>>> gmpy2.set_context(gmpy2.context(precision=150))
>>> a=gmpy2.sqrt(5)
>>> a
mpfr('2.2360679774997896964091736687312762354406183598',150)
>>> ((1+a)**100 - (1-a)**100)/(a*(2**100))
mpfr('354224848179261915075.00000000000000000000000248',150)
>>> gmpy2.fib(100)
mpz(354224848179261915075L)

gmpy2也可以直接计算斐波那契数(如上图)。

免责声明:我维护gmpy2

【讨论】:

    【解决方案2】:

    python double 的值是有限的。但是 int 不会:

    a,b,c=0,1,0
    
    untill=int(raw_input("> "))
    
    for i in range(0,untill):
        c=a+b
        print b
        a=b
        b=c
    

    可以永远持续下去,但如果不找到之前的所有数字,就找不到 N。

    【讨论】:

    • 它不必在N之前找到所有个数字,它只需要知道前两个数字。
    【解决方案3】:

    我不知道您是否可以接受,但您可以使用整数算术来使用递归关系计算 fib 数(例如,F3 = F2 + F1)。

    从 Python 2.5 开始,您可以进行任意精度的整数运算 -- 几乎可以消除溢出问题 -- 如果您尝试计算 F(10000),它无疑会变得非常慢。

    另外,检查十进制模块——IIRC 正确,你可以在 Python 2.7 中使用,你可以指定十进制算法的精度——这将允许你继续使用相同的算法——除了使用十进制输入。

    添加

    您很容易忽略十进制类包含平方根方法。您需要使用此方法而不是 math.sqrt(),因为您需要保留小数类的完整精度。

    sqrt(5) 也是一个相对昂贵的操作。只计算一次

    【讨论】:

    • 是的……我用过这个方法。该项目的部分重点是使用替代方法计算数字。你的回答很好。
    • 这有帮助吗?或者你还在寻找别的东西。很难从您的评论中看出。
    【解决方案4】:

    您对如何改进此代码... 的陈述有点含糊,因此我将其理解为缩短您的代码:

    import math
    def fib(j):
        for i in [int(((1+math.sqrt(5))**n-(1-math.sqrt(5))**n)/(2**n*math.sqrt(5))) for n in range(j)]: print i
    

    您可以将两个函数组合成一个函数,并且使用列表解析,您可以使该函数在一行中运行。

    如果您正在处理非常大的数字,则无法防止溢出错误,而是尝试捕获它们然后中断:

    import math
    def fib(j):
            try:
                    for i in [int(((1+math.sqrt(5))**n-(1-math.sqrt(5))**n)/(2**n*math.sqrt(5))) for n in range(j)]: print i
            except Exception as e:
                    print 'There was an error, your number was too large!'
    

    第二个将首先循环遍历所有内容并确保没有错误,如果没有,它将继续打印。

    【讨论】:

    • 对不起,如果我的问题含糊不清。是否有任何大型数字库可以让我的代码计算更多数字?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-01
    • 2021-06-15
    • 1970-01-01
    • 1970-01-01
    • 2018-06-16
    • 1970-01-01
    • 2018-06-19
    相关资源
    最近更新 更多