@Pierre Lafortune 的代码简洁且不会太慢,但我想提出另一种更快的方法。
从另一个角度解决问题,在R中找到第一个n复合数可以翻译为“获取第一个n+k整数并删除素数”。这很快,因为生成序列1:(n+k) 几乎不需要时间,并且有非常复杂的算法可以找到可用的素数,其中一种实现是numbers::Primes()。
序列需要以n+k 结尾,因为在第一个n 整数中会有一些(k1) 素数需要替换。请注意,(n+1):(n+k1) 范围可能还包含 k2 素数,它们也需要被替换。等等等等……这将需要一个递归结构。
皮埃尔的回答基本上做了类似的事情:他反复检查整数是否是合数(非素数)并继续直到找到足够的复合数。然而,这有一个缺点:寻找(非)素数的算法相当幼稚(与其他寻找素数的算法相比;无意冒犯)。另一方面,该解决方案不涉及上述任何整数范围内可能素数的递归问题。
我想建议的递归解决方案如下:
library(numbers)
n_composite2 <- function(n, from = 2) {
endRange <- from + n - 1
numbers <- seq(from = from, to = endRange)
primes <- Primes(n1 = from, n2 = endRange)
composites <- numbers[!(numbers %in% primes)]
nPrimes <- length(primes)
if (nPrimes >= 1) return(c(composites, n_composite2(nPrimes, from = endRange + 1)))
return(composites)
}
这会生成一个整数序列(可能的复合),然后使用numbers::Primes() 查找该范围内的素数并将它们从序列中删除。如果某些数字已被删除,则该函数会再次调用自身,这次计算[number of primes in previous step] 组合并从上一步停止的位置开始序列。
如果怀疑这是否真的有效,请在此处检查 Pierre 的解决方案 (n_composite()):
> all(n_composite(1e4) == n_composite2(1e4))
[1] TRUE
比较这两个函数,n_composite2() 大约快 19 倍:
library(microbenchmark)
microbenchmark(
"n_composite2" = n_composite2(1e4),
"n_composite" = n_composite(1e4),
times=5
)
Unit: milliseconds
expr min lq mean median uq max neval
n_composite2 34.44039 34.51352 35.10659 34.71281 35.21145 36.65476 5
n_composite 642.34106 661.15725 666.02819 662.99657 671.52093 692.12512 5
最后一句话:在 Pierre 的方法和此处介绍的解决方案之间有许多解决方案。可以在while 循环中使用numbers::Primes(),这与n_composite() 中发生的情况非常相似。也可以从“足够长”的整数序列开始,删除素数,然后取第一个 n 剩余数字。为了提高效率,这种方法需要在给定范围内很好地近似素数,这也不是微不足道的(对于小数)。