R:如何在n-choose-k中计算大数?

时间:2016-11-10 11:54:45

标签: r factorial exponent

对于类赋值,我需要创建一个计算n选择k的函数。我做到了这一点,并且它适用于小数字(例如6选2),但我应该让它与200选择50,它自然不会。 答案太大,R输出NaN或Inf,说:

> q5(200, 50)
[1] "NaN"
Warning message:
In factorial(n) : value out of range in 'gammafn'

我尝试过使用日志和指数,但它没有削减它。

q5 <- function (n, k) {
  answer <- log(exp( factorial(n) / ( (factorial(k)) * (factorial(n - k)) )))
  paste0(answer)
}

4 个答案:

答案 0 :(得分:5)

实际问题的答案是R不能显示它无法表示的数字,并且等式中的某些项太大而无法表示。所以它失败了。然而,可以使用的是阶乘的近似值 - 它们使用的对数变得更慢。

最着名的一个,斯特林的近似,不够准确,但Ramanujan's approximation来救援:)

ramanujan <- function(n){
  n*log(n) - n + log(n*(1 + 4*n*(1+2*n)))/6 + log(pi)/2
}

nchoosek <- function(n,k){
  factorial(n)/(factorial(k)*factorial(n-k))
} 

bignchoosek <- function(n,k){
  exp(ramanujan(n) - ramanujan(k) - ramanujan(n-k))
}

nchoosek(20,5)
# [1] 15504

bignchoosek(20,5)
# [1] 15504.06


bignchoosek(200,50)
# [1] 4.538584e+47

答案 1 :(得分:2)

大号的包裹:

Brobdingnag包&#34; 非常大的数字在R&#34;:
https://cran.r-project.org/web/packages/Brobdingnag/index.html
论文:https://www.researchgate.net/publication/251996764_Very_large_numbers_in_R_Introducing_package_Brobdingnag

library(Brobdingnag)
googol <- as.brob(10)^100 # googol:=10^100
googol
# [1] +exp(230.26) # exponential notation is convenient for very large numbers
用于多个精确算术的

gmp包(大整数和有理数,素数测试,矩阵计算):
https://cran.r-project.org/web/packages/gmp/index.html

答案 2 :(得分:2)

你也可以试试这个:

q5 <- function (n, k) {
  # nchoosek = (n-k+1)(n-k+2)...n / (1.2...k)
  return(prod(sapply(1:k, function(i)(n-k+i)/(i))))
}

q5(200, 50)
#[1] 4.538584e+47

或在日志域中

q5 <- function (n, k) {
  # ln (nchoosek) = ln(n-k+1) + ln(n-k+2) + ...+ ln(n) - ln(1) -ln(2) - ...- ln(k)
  return(exp(sum(sapply(1:k, function(i)(log(n-k+i) - log(i))))))
}
q5(200, 50)
#[1] 4.538584e+47

答案 3 :(得分:1)

此解决方案计算Pascal三角形的完整行:

x <- 1
print(x)
for (i in 1:200) { x <- c(0, x) + c(x, 0); print(x) }
x[51]  ### 200 choose 50
## > x[51]
## [1] 4.538584e+47

(正如我建议的How would you program Pascal's triangle in R?
如果你想加速代码,那么不要print(x)(输出相对较慢的操作)。

要将代码放在我们可以做的函数中

nchoosek <- function(n,k) {
    x <- 1
    for (i in 1:n) x <- c(0, x) + c(x, 0)
    x[k+1]  ### n choose k
} 

nchoosek(200, 50)    ### testing the function
## [1] 4.538584e+47

这是我的功能的更精炼版本:

nchoosek <- function(n, k) {
  if (k==0) return(1)
  if (k+k > n) k <- n-k
  if (k==0) return(1)
  x <- 1
  for (i in 1:k)     x <- c(0, x) + c(x, 0)
  for (i in 1:(n-k)) x <- x + c(0, head(x, -1))
  tail(x, 1)
} 
nchoosek(200, 50)    ### testing the function
## [1] 4.538584e+47