处理R中的非常小的数字

时间:2011-04-27 10:26:52

标签: r underflow

我需要计算一个非常小的数字列表,例如

(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 允许你比双精度值更好。

任何建议都将不胜感激,谢谢

4 个答案:

答案 0 :(得分:14)

从数学上讲,其中一个数字将是appx。零,另一个。你的数字之间的差异是巨大的,所以我甚至想知道这是否有意义。

但是为了做到这一点,你可以使用来自R的引擎底下的logspace_add C函数的想法。当logxpy ( =log(x+y) )和{{1}时,可以定义lx = log(x) as:

ly = log(y)

这意味着我们可以使用:

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

如果您有更多数字,也可以递归调用此函数。请注意,1仍然是1,而不是1减去> 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 。如果您真的需要更高的精度并且您的平台支持长双精度类型,您可以使用例如C或C ++编写所有代码,并在以后返回结果。但如果我是对的,R可以 - 暂时 - 只处理正常的双打,所以最终你会在显示结果时再次失去精度。


编辑:

为你做数学运算:

5.807...e-162

现在你只取最大值为lx,然后你来到log(x+y) = log(exp(lx)+exp(ly)) = log( exp(lx) * (1 + exp(ly-lx) ) = lx + log ( 1 + exp(ly - lx) ) 中的表达式。

编辑2:为什么要取最大值呢?很容易,以确保您在exp(lx-ly)中使用负数。如果lx-ly变得太大,则exp(lx-ly)将返回Inf。那不是正确的结果。 exp(ly-lx)将返回0,这样可以获得更好的结果:

说lx = 1且ly = 1000,然后:

logxpy()

答案 1 :(得分:7)

Brobdingnag包处理大小不一的数字,基本上将Joris的答案包含在一个方便的形式中。

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)

答案 2 :(得分: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)))

答案 3 :(得分:1)

尝试使用任意精度包mpfr

Ryacas也可以做任意精度。