Prime number function in R
A number a
is divisible by a number b
if the result of the division a / b
is equal to the result of the integer division a %/% b
. Any integer pn
can be divided by at least two numbers: 1
and pn
. Prime numbers are those than can only be divided by those two. Breaking out the code:
pn / 1:pn
are the results of the divisions by1
,2
, ...,pn
pn %/% 1:pn
are the results of the integer divisions by1
,2
, ...,pn
sum(pn / 1:pn == pn %/% 1:pn)
are how many of these are equal, i.e., the number of integer divisors ofpn
. If this number is2
, you have a prime.
What was wrong with your code: if
needs to test if something is TRUE
or FALSE
but you were passing it a whole vector. Also, your logic was wrong. It should have been:
is.prime <- function(num) {
if (num == 2) {
TRUE
} else if (any(num %% 2:(num-1) == 0)) {
FALSE
} else {
TRUE
}
}
And once you've settled on returning a logical, you can make your code a lot shorter:
is.prime <- function(n) n == 2L || all(n %% 2L:max(2,floor(sqrt(n))) != 0)
(which incorporates @Carl's comment about not checking all numbers.)
You may also use the isprime()
function in the matlab package. It works also with vector arguments:
library(matlab)
as.logical(isprime(7))
as.logical(isprime(42))
#> as.logical(isprime(7))
#[1] TRUE
#> as.logical(isprime(42))
#[1] FALSE
A regular expression to find prime numbers
is.prime <- function(x) {
x <- abs(as.integer(x))
!grepl('^1?$|^(11+?)\\1+$', strrep('1', x))
}
(-100:100)[is.prime(-100:100)]
# [1] -97 -89 -83 -79 -73 -71 -67 -61 -59 -53 -47 -43 -41 -37 -31 -29 -23 -19 -17 -13 -11 -7 -5 -3 -2
# [26] 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
http://diswww.mit.edu/bloom-picayune.mit.edu/perl/10138
Or if you take all the integers from 1 to x
, the number which divide with no remainder should be 2: 1 and x
is.prime <- function(x)
vapply(x, function(y) sum(y / 1:y == y %/% 1:y), integer(1L)) == 2L
(1:100)[is.prime(1:100)]
# [1] 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
I knew the regex would be slowest, but it's still my favorite
is.prime <- function(x)
vapply(x, function(y) sum(y / 1:y == y %/% 1:y), integer(1L)) == 2L
is.prime_regex <- function(x) {
x <- abs(as.integer(x))
!grepl('^1?$|^(11+?)\\1+$', strrep('1', x))
}
is.prime_Seily <- function(n)
vapply(n, function(y)
y == 2L || all(y %% 2L:ceiling(sqrt(y)) != 0), logical(1L))
is.prime_flodel <- function(n)
vapply(n, function(y)
y == 2L || all(y %% 2L:max(2,floor(sqrt(y))) != 0), logical(1L))
x <- 1:1000
library('microbenchmark')
microbenchmark(
is.prime(x),
is.prime_regex(x),
is.prime_Seily(x),
is.prime_flodel(x),
unit = 'relative'
)
# Unit: relative
# expr min lq mean median uq max neval cld
# is.prime(x) 8.593971 8.606353 8.805690 8.892905 9.724452 21.9886734 100 b
# is.prime_regex(x) 84.572928 86.200415 76.413036 86.895956 85.117796 25.7106323 100 c
# is.prime_Seily(x) 1.000000 1.000000 1.000000 1.000000 1.000000 1.0000000 100 a
# is.prime_flodel(x) 1.146212 1.147971 1.144839 1.146119 1.163302 0.9085948 100 a
I just tried the is.prime
code example. But with this 3 is not prime ;o)
The improved version uses ceiling instead of the floor operation.
is.prime <- function(n) n == 2L || all(n %% 2L:ceiling(sqrt(n)) != 0)
Best!