2011-04-27 55 views
15

與非常小的數字處理我需要計算非常小的數如中的R

(0.1)的列表^ 1000,0.2 ^(1200),

,然後歸一化,以便它們將總結長達一 即

A1 = 0.1^1000, A2 = 0.2^1200

我想要計算 A1' = A1 /(A1 + A2), A2' = A2(A1 + a2)。

我遇到了下溢問題,因爲我得到a1 = 0。我怎樣才能解決這個問題?理論上我可以處理日誌,然後log(a1)= 1000 * log(0.l)將代表a1沒有下溢問題的一種方法 - 但爲了正常化,我需要得到 log(a1 + a2 ) - 我無法計算,因爲我無法直接表示a1。

我使用R進行編程 - 據我所知,在c#中沒有數據類型,例如Decimal,其中 允許您獲得比雙精度值更好的數據類型。

任何建議將讚賞,感謝

+0

鑑於你正在做一個部門,你可以先用數字分解手數嗎? – James 2011-04-27 10:33:17

回答

14

數學上說,這些數字的人會APPX。零,另一個。你的數字之間的差異是巨大的,所以我甚至想知道這是否有道理。

但要做到這在一般情況下,你可以使用來自logspace_add C函數這是R.之一引擎蓋下方的想法可以定義logxpy (=log(x+y))lx = log(x)ly = log(y)爲:

logxpy <- function(lx,ly) max(lx,ly) + log1p(exp(-abs(lx-ly))) 

這意味着我們可以使用:

> la1 <- 1000*log(0.1) 
> la2 <- 1200*log(0.2) 

> exp(la1 - logxpy(la1,la2)) 
[1] 5.807714e-162 

> exp(la2 - logxpy(la1,la2)) 
[1] 1 

這個功能可以遞歸調用,以及如果你有更多的數字。請注意,1仍然是1,而不是1減去5.807...e-162。如果您確實需要更高的精度並且您的平臺支持長雙精度類型,那麼您可以用C或C++編碼所有內容,並稍後返回結果。但是如果我是對的,R可以 - 目前只能處理正常的雙打,所以最終當結果顯示時你會再次失去精度。


編輯:

做數學題給你:

log(x+y) = log(exp(lx)+exp(ly)) 
     = log(exp(lx) * (1 + exp(ly-lx)) 
     = lx + log (1 + exp(ly - lx) ) 

現在,你把最大的爲LX,然後你在logxpy()來的表情。

編輯2:爲什麼採取最大呢?很簡單,以確保您在exp(lx-ly)中使用負數。如果lx-ly變得太大,那麼exp(lx-ly)會返回Inf。這不是一個正確的結果。 EXP(LY-60)將返回0,允許一個更好的結果:

說LX = 1和LY = 1000,則:

> 1+log1p(exp(1000-1)) 
[1] Inf 
> 1000+log1p(exp(1-1000)) 
[1] 1000 
+0

感謝您的回覆。關於我的例子中的差異 - 這只是一個例子,實際上我認爲至少有一些數字是相同的數量。關於你的解決方案 - 你可能會擴展更多爲什麼它的數學運作?我不確定自己...... – dan12345 2011-04-27 11:54:48

+0

@ user206903:我很想說「我把練習留給讀者」。這是來自高中的基本數學,但很好。 – 2011-04-27 12:14:24

+0

@Joris Meys爲什麼不考慮直接使用以前的表達式而將lx取爲最大值? – James 2011-04-27 12:46:29

1

也許你可以把a1和a2爲分數。在你的榜樣,與

a1 = (a1num/a1denom)^1000 # 1/10 
a2 = (a2num/a2denom)^1200 # 1/5 

你會到達

a1' = (a1num^1000 * a2denom^1200)/(a1num^1000 * a2denom^1200 + a1denom^1000 * a2num^1200) 
a2' = (a1denom^1000 * a2num^1200)/(a1num^1000 * a2denom^1200 + a1denom^1000 * a2num^1200) 

可以使用GMP包來計算:

library(gmp) 
a1 <- as.double(pow.bigz(5,1200)/(pow.bigz(5,1200)+ pow.bigz(10,1000))) 
1

嘗試任意精度包mpfr

Ryacas也可以做任意精度。

7

Brobdingnag包處理非常大或很小的數字,基本上包裝喬里斯的答案到一個方便的形式。

a1 <- as.brob(0.1)^1000 
a2 <- as.brob(0.2)^1200 
a1_dash <- a1/(a1 + a2) 
a2_dash <- a2/(a1 + a2) 
as.numeric(a1_dash) 
as.numeric(a2_dash) 
+0

+1 thx的指針 – 2011-04-27 13:06:40

+0

嗨,我遇到了有關使用Brobdingnag包的問題 - 設置a2 < - as.brob(0.1)^ 1000,a1 < - as.brob( 0.1)^ 800,我使用sum(a1,a2)和sum(a2,a1)得到了不同的結果 - 每次結果等於賦給sum函數的第一個參數。看起來,儘管它可能會達到Brobdingang包的總和,或者,也許我做錯了什麼 – dan12345 2011-04-28 09:43:10

+0

我爲這個問題創建了一個新問題,請參閱 – dan12345 2011-04-29 15:23:16