2014-10-21 112 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)) 

但由於斐波那契序列呈指數級增長,你會很快打出相同壁。嘗試通過保留最後兩項並添加它們來計算斐波那契。這樣你將使用整數。