在 R 中处理非常精确的数字

Handling very precise numbers in R

提问人:spencergw 提问时间:10/6/2022 更新时间:10/6/2022 访问量:126

问:

我正在使用 R 尝试求解公式enter image description here,其中 enter image description hereenter image description here 是标准正态分布函数。我遇到的问题是 g 的某些值非常小或在 R 中编码为 0,因此给定的解决方案是 Inf。下面的代码行给出了 g 在应该为正数时被编码为 0 的示例。

pnorm(29.1,0,1) - pnorm(29,0,1) #this returns a value of 0

鉴于这个问题,我有两个问题。首先,有没有一个数学技巧可以用来从上面的代码中得到一个正数?我知道有一个参数返回概率的日志。也许这会派上用场?pnormlog.p=TRUE

我的第二个问题是,如果我有一个正但非常小的 g,是否有数学技巧可以确保 fg 之比的对数是有限的?

R 数学 精度

评论

0赞 GuedesBF 10/6/2022
这可能是浮点精度问题
0赞 Onyambu 10/6/2022
无能为力。该值实际上为 0。请注意,这实际上是 1。请注意,无论您的 or 或任何其他大于您的数字,您都会得到 1pnorm(29.1)P(X<=8.2924) = 129.1198.2824
2赞 Alex 10/6/2022
你为什么不直接把它除以f'(29)dnorm(29, 0 , 1)
2赞 Alex 10/6/2022
我还建议您始终在 R 中反转函数以缓解此舍入问题:.由于函数是对称的,因此没关系。pnorm()pnorm(-29,0,1) - pnorm(-29.1,0,1)
1赞 Gregor Thomas 10/6/2022
@Alex,当你发表评论时,我正在写我的衍生答案。但是,由于数值精度更接近 0,因此您的第二条评论可能就足够了。

答:

2赞 Gregor Thomas 10/6/2022 #1

log(f / g) = log(f) - log(g),所以你需要计算.log(g)

你有。g = pnorm(x + d) - pnorm(x)

密度函数 ( 在 R 中)是 CDF () 的导数。这意味着当接近 0.因此,对于小,我们可以近似.因此(大约)和 .dnorm()pnorm()dnorm(x) = (pnorm(x + delta) - pnorm(x)) / deltadeltadeltadnorm(x) * delta = pnorm(x + delta) - pnorm(x)g(x) = dnorm(x) * dlog(g(x)) = log(dnorm(x)) + log(d)

在计算中使用为 .dnorm(29, log = TRUE) + log(0.1)log(g)

2赞 Ben Bolker 10/6/2022 #2

正如在回答和评论中指出的那样,您实际上只需要计算 .log(g)

一种解决方案是使用对数空间加法/减法,它使用一个很好的技巧来准确计算。log(exp(x) ± exp(y))

DPQ::logspace.sub(pnorm(29.1, log.p = TRUE), pnorm(29, log.p = TRUE))
## [1] -424.8435

@Alex指出,如果我们通过反转符号来观察(对称的)相反的尾巴,以便我们从另一个非常小的数字中减去一个非常小的数字,那么四舍五入误差就不是问题:

log(pnorm(-29,0,1) - pnorm(-29.1,0,1))
##  -424.8435

比较@GregorThomas的基于导数的估计值:

dnorm(29, log = TRUE) + log(0.1)
## [1] -423.7215

使用软件包检查这些解决方案:Rmpfr

library(Rmpfr)
x1 <- mpfr(29.1, 1000)  ### 1000-bit precision
x2 <- mpfr(29.0, 1000)
log(pnorm(x1) - pnorm(x2))
## 1 'mpfr' number of precision  1000   bits 
## [1] -424.843525917118620331088762368642820931865149932737039093516330881321230653835360169156688142607902967369067320263733953321675429119215305576014352760866238194504221709021981332048618426550583180796866417925580695487036011142823944123174363138216647098415472494704193913895461975221571930136768807682871

所以看起来@GregorThomas的解决方案非常接近,但其他两个解决方案更好。

评论

0赞 Gregor Thomas 10/6/2022
很酷!我以前从未见过 DPQ 或 Rmpfr。
1赞 Ben Bolker 10/6/2022
logspace_add,,github.com/wch/r-source/blob/......logspace_sublogspace_sum