正在探索避免for循环的方法,而是利用any()函数来实现一个函数,该函数在传递的参数为质数时为true,在其他情况下为false。
这是我所拥有的:
prime2 <- function(n) {
rangeOfNumbers <- range(2:(n-1))
if(any(n%%rangeOfNumbers == 0)){
return(FALSE)
}
else return(TRUE)
}
向前看,但prime(55)
给出TRUE
而不是false。
我在做什么错了?
答案 0 :(得分:5)
正如您所说,我们可以轻松地从许多软件包中调用isprime
函数来快速获得您的答案,但这并不是您的目标。您正在学习并尝试理解R
和一般编程中的基本原理。许多荣誉!
正如许多人指出的那样,在这种情况下在此处使用range
是不合适的。此函数仅返回给定向量的最小值和最大值(有关更多信息,请参见?range
)。因此,以您的55为例,由于range(2:54)
返回2
和54
,所以55不能被这两个数字整除,因此返回TRUE
。
如@LAP所述,您需要冒号:
运算符。因此,如果将range(2:(n-1))
更改为简单的2:(n-1)
,您的算法将起作用(在大多数情况下……不适用于n <= 2
)。
由于您声明自己正在学习中,因此,您还应该考虑一种更有效,更周到的编码方式。为了检查数字是否为质数,我们只需要检查n的平方根即可。这样可以减少很多检查。
让我们更加努力地思考如何避免进一步的检查。我们知道在检查素数时,我们只需要考虑素数。由于2是唯一的偶数质数,因此我们可以首先检查输入是否为偶数,如果不是,则仅检查可除数是否为奇数。我们可以通过调用函数seq
或seq.int
生成具有固定步长的序列来获得最后一位。
让我们看看这一点:
## Pseudo-Corrected OP function (2 should return TRUE, 1 should return FALSE, etc.)
prime2 <- function(n) {
rangeOfNumbers <- 2:(n-1)
if(any(n%%rangeOfNumbers == 0)){
return(FALSE)
}
else return(TRUE)
}
prime2Enhanced <- function(n) {
if (n < 2)
return(FALSE)
else if (n %in% c(2, 3, 5, 7))
return(TRUE)
else if (n %% 2 == 0)
return(FALSE)
else if (any(n %% seq.int(3, sqrt(n), 2) == 0))
return(FALSE)
else
return(TRUE)
}
all.equal(sapply(3:1000, prime2), as.logical(gmp::isprime(3:1000)))
[1] TRUE
all.equal(sapply(3:1000, prime2Enhanced), as.logical(gmp::isprime(3:1000)))
[1] TRUE
通过将编程概念扩展到矢量化,我们可以做得更好。这是我们可以一次传递一个向量并一次获得所有结果而不是使用循环的时候。这是R
中非常重要的概念,我强烈建议您对其进行学习。 The R Inferno是针对此类主题的绝佳资源(请参阅圈子3)。
prime2Vectorized <- function(v) {
result <- rep(TRUE, length(v))
testVec <- as.integer(c(2, seq(3, sqrt(max(v)), 2)))
## Although we are using a loop here, we are taking
## advantage of vectorization concepts with each x
for (x in testVec) {
s <- which(v >= x^2)
result[s[v[s] %% x == 0]] <- FALSE
}
result
}
all.equal(prime2Vectorized(3:1000), as.logical(gmp::isprime(3:1000)))
[1] TRUE
我将其保存为练习来处理极端情况和进一步优化。
现在,让我们看看使用库microbenchmark
在效率上有多少改进:
library(microbenchmark)
microbenchmark(orig = sapply(3:1000, prime2),
improved = sapply(3:1000, prime2Enhanced),
vectorize = prime2Vectorized(3:1000))
Unit: microseconds
expr min lq mean median uq max neval
orig 3863.279 4198.5595 5470.2178 4403.5050 4723.485 15775.377 100
improved 1670.418 1740.1240 1937.2396 1809.6680 1935.365 9912.629 100
vectorize 202.006 218.5505 306.4068 233.9045 249.696 6243.121 100
希望您能看到许多基本概念可以从此简单练习中删除。如果您真的想了解素数测试,则应该查看Miller-Rabin primality test,它在gmp
,numbers
和其他软件包中实现。