2016-02-24 42 views
1

我有一個功能,有一個循環,其中我做分裂和乘法。最終答案很容易表達,正如正在運行的答案一樣。爲什麼我要控制計算?

def tie(total): 
    count = total/2 
    prob = 1.0 
    for i in xrange(1, count + 1): 
     i_f = float(i) 
     prob *= (count + i_f)/i_f/4 
    return prob 

-

tie(4962) == 0.01132634537589437 

tie(4964) == inf 

是編譯器試圖做一些優化,在做其他的順序算術運算比我似乎已經規定和秩序據推測等價但會導致溢出?

+0

將以下行添加到循環中:「print(」({} + {})/ {}/4「.format(prob,count,i,i))」您將看到發生了什麼 – MaxU

+1

我在我的答案中添加了第三個解決方案,可能比基於整數的解決方案或基於lgamma的解決方案更適合您。 –

回答

4

您正在運行到問題,因爲即使你的tie功能的最後的結果應該是數學在01之間,中間值循環中的值變得非常大:對於total = 4962,中途迭代的值爲prob約爲1.5e308,這是差不多但不是相當大到足以溢出Python float。對於total = 4964,價值中途真的確實溢出float,由於inf次有限東西仍然是inf,在inf從溢流傳播到最終值的所有道路。

如果您準備接受(相當小)的浮點錯誤數量,則不需要使用循環計算此數量:您可以使用math模塊中的lgamma函數來計算日誌的相關因子。 (您也可以直接使用gamma函數,但這可能也會導致溢出問題。)

以下是基於此功能的一個版本。

from math import lgamma, log, exp 

def tie(total): 
    count = total/2 
    return exp(lgamma(2*count + 1) - 2*lgamma(count + 1) - count*log(4)) 

或者,你可以使用純整數運算(這不會造成溢出)計算2N-選擇-N項,只在最後時刻產生浮(由4**count分割時)。這樣做效率會比上面的要低,但會給你(從某種意義上來說)完美的準確性,因爲它會給出最接近的可表示的浮點數。下面是該版本是這樣的:

from __future__ import division 

def tie(total): 
    count = total // 2 
    prod = 1 
    for i in xrange(1, count+1): 
     prod = prod * (count + i) // i 
    return prod/4**count 

注:prod * (count + i) // i地板師看起來可能不對,但它的實際工作:初等數論的一點點表明,在計算這一點上,prod * (count + i)必須除盡由i,所以它是安全的做一個整數除法。最後,爲了好玩,下面是第三種計算概率的方法,它與您的原始代碼在精神上相似,但是避免了溢出:值prob開始於1.0並穩步下降到最終值。

def tie(total): 
    count = total // 2 
    prob = 1.0 
    for i in xrange(1, count+1): 
     prob *= (i-0.5)/i 
    return prob 

除了是從溢出問題免疫,這種解決方案會更高效,基於整數的解決方案,而不是基於lgamma一個更準確。

1

prob增長得相當大並最終溢出。鑑於名稱,你打算prob總是在0和1之間?

+0

函數返回概率。對於4962,它返回一個介於0.01和0.02之間的數字。是的,這是一個概率。你爲什麼說它變得非常大? –

+1

啊,謝謝。我想如果我從後面開始,我會遇到下流。我想我需要從中間開始(3/4 *計數和1/4 *計數),並同時適用於0和1/2以及1/2和1(全部*計數)。或者動態地檢查數字是否變得太大或者變小,並且在另一個方向上有一段時間。 –

0

你變量的概率變得非常大和總等於4964溢出Python的最大浮動值sys.float_info

>>> import sys 
>>> print(sys.float_info.max) 
1.7976931348623157e+308 
+0

函數返回概率。對於4962,它返回一個介於0.01和0.02之間的數字。你爲什麼說它變得非常大? –

+1

顯然它不是。不要做數學運算:每次乘以(count + i)/ i/4。Count是2481,I是1,2,3,...在第一輪中乘以2482/4,2483/8,2484/12,2485/16 ...所以每輪增加概率。花費相當長的時間直到分數變得小於1,並且概率再次下降。 – Shubit

+1

@Shubit:正在計算的*是*概率:最終結果在'0'和'1'之間。問題是中間結果溢出。 –

0

你是什麼意思「受控計算」?造成溢出的原因是prob越來越大。

+0

我的意思是我反覆地分開和乘以(不足)的嘗試,以保持數字的可管理性。 這個計算的最簡單的表達式會對小得多的輸入(大約110)溢出。 –

相關問題