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:

  1. pn / 1:pn are the results of the divisions by 1, 2, ..., pn
  2. pn %/% 1:pn are the results of the integer divisions by 1, 2, ..., pn
  3. sum(pn / 1:pn == pn %/% 1:pn) are how many of these are equal, i.e., the number of integer divisors of pn. If this number is 2, 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!

Tags:

Primes

R