我需要计算一个非常小的数字列表,例如
(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 :(得分: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)