2014-10-21 105 views
0

我试图打印Fibonacci序列,并且在第600个术语后总是返回一个溢出错误。错误34,结果太大

def fib(): 

    import math 
    from math import sqrt 
    print "\nFibonacci Sequence up to the term of what?" 
    n=raw_input(prompt) 
    if n.isdigit(): 
     if int(n)==0: 
      return 0 
     elif int(n)==1: 
      return 1 
     else: 
      n_count=2 
      print "\n0\n1" 
      while n_count<int(n): 
       fib=int(((1+sqrt(5))**n_count-(1-sqrt(5))**n_count)/(2**n_count*sqrt(5))) 
       print fib 
       n_count+=1 
      fib() 
    else: 
     print "\nPlease enter a number." 
     fib() 
fib() 

当我运行此:

Traceback (most recent call last): 
    File "<pyshell#21>", line 1, in <module> 
    fib() 
    File "<pyshell#20>", line 15, in fib 
    fib=int(((1+sqrt(5))**n_count-(1-sqrt(5))**n_count)/(2**n_count*sqrt(5))) 
OverflowError: (34, 'Result too large') 
+0

请注意,这实际上不会打印斐波那契序列,它会打印出一个粗略的斐波那契序列的近似值 - 它会以打印实际序列效率较低的方式进行打印。那真的是你想要的吗? – abarnert 2014-10-21 22:33:00

+1

此外,由于您使用递归伪造了一个循环,而不是仅使用循环,所以一旦解决了这个问题,您将在第1000次尝试打印斐波那契数时发生'RecursionError'。 – abarnert 2014-10-21 22:33:28

回答

3

嗯,首先,我们来了拆分大的表达成小的,所以我们可以看到它是怎么回事错了。并使用调试器或一些print语句来查看哪些值使其出错。那样,我们不只是在黑暗中刺伤。

如果这样做,则可以看到(1+sqrt(5)**n_count)n_count遇到605时引发此异常。你可以很容易地验证:

>>> (1+sqrt(5))**604 
1.1237044275099689e+308 
>>> (1+sqrt(5))**605 
OverflowError: (34, 'Result too large') 

那么,为什么这是一个问题?

好,巨蟒float值,不像它的整数,不任意大小的,他们只能持有IEEE double还能持有什么:*

>>> 1e308 
1e308 
>>> 1e309 
inf 

那么,问题是,在条款之一你的等式大于最大可能的IEEE双倍。

这意味着你需要选择一个不同的算法,或者得到一个“大浮点”库。

碰巧,Python在decimal模块中有一个内置的大浮点库。当然顾名思义,它会处理十进制数浮点数,而不是二进制数浮点数,所以如果使用它,会得到不同的舍入误差。但你可能不太在意舍入错误,因为你的代码。

所以:

import decimal 
s5 = decimal.Decimal(5).sqrt() 

...然后...

fib=int(((1+s5)**n_count-(1-s5)**n_count)/(2**n_count*s5)) 

*实际上,限制是特定于平台的;实现不需要要求使用IEEE双打float。因此,请使用sys.float_info查看您平台的最大值。但它几乎总是1.7976931348623157e+308

**请注意,您使用的算法的唯一优点是可以直接逼近第N个斐波那奇数,而无需计算前面的N-1。但是既然你想把它们全部打印出来,你没有任何优势。你只是有缺点 - 这是一个近似值;它更复杂;它需要浮点数学,这是受到舍入误差;它比较慢;它需要更多的记忆;在大多数平台上,大多数语言的内置浮点类型不能包含F(605),...所有这些没有任何好处似乎不值得。

1

正如abarnert指出的那样,浮筏在蟒蛇中是有限的。您可以通过

>>> import sys 
>>> sys.float_info 
sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1) 

看到的极限,将进入一些方面,如果你养到电源之前除以2:

int((((1+sqrt(5))/2)**n_count - ((1-sqrt(5))/2)**n_count)/sqrt(5)) 

但由于斐波那契序列呈指数级增长,你会很快打出相同壁。尝试通过保留最后两项并添加它们来计算斐波那契。这样你将使用整数。