0

I am trying to write a simple function in R to calculate all divisors of a number. That is how I want to have my output:

> divisors(21)
[1] 1 3 7 21

I am a beginner and started with the code below. However I think it is completely wrong since it does not work at all.

divisors <- function(number) {
  x <- c(1:number)
  for(i in 1:number){
    if(number/i == c(x)) {
      paste(i)
    }
  }
  return(i)
}
divisors(10)
SWR
  • 507
  • 1
  • 8
  • 17
  • 1
    So you do _not_ want only the prime factorizaton, right? Really you should do more searching. – IRTFM Oct 19 '13 at 11:56

2 Answers2

11

How about this...

divisors <- function(x){
  #  Vector of numberes to test against
  y <- seq_len(x)
  #  Modulo division. If remainder is 0 that number is a divisor of x so return it
  y[ x%%y == 0 ]
}

divisors(21)
#[1]  1  3  7 21

divisors(4096)
#[1]    1    2    4    8   16   32   64  128  256  512 1024 2048

Of course, with larger numbers efficiency gets more important. You might want to replace seq_len(x) with something like...

seq_len( ceiling( x / 2 ) )

And this is only designed to work with positive natural numbers.

Update: An aside using Rcpp

#include <Rcpp.h>
using namespace Rcpp;
//[[Rcpp::export]]
IntegerVector divCpp( int x ){
  IntegerVector divs = seq_len( x / 2 );
  IntegerVector out(0);
  for( int i = 0 ; i < divs.size(); i++){
    if( x % divs[i] == 0 )
      out.push_back( divs[i] );
  }
  return out;
}

Gives the same results:

identical( divCpp( 1e6 ) , divisors( 1e6 ) )
#[1] TRUE

Run against the base R function...

require( microbenchmark )
bm <- microbenchmark( divisors(1e6) , divCpp(1e6) )
print( bm , unit = "relative" , digits = 3 , order = "median" )

#Unit: relative
#            expr  min   lq median   uq  max neval
#   divCpp(1e+06) 1.00 1.00   1.00 1.00  1.0   100
# divisors(1e+06) 8.53 8.73   8.55 8.41 11.3   100
Community
  • 1
  • 1
Simon O'Hanlon
  • 58,647
  • 14
  • 142
  • 184
1

Or gmp::factorize , among other existing tools.

I often find it handy to look at the source for released packages to get good ideas for doing similar tasks.

Carl Witthoft
  • 20,573
  • 9
  • 43
  • 73
  • *surely* more of a comment? – Simon O'Hanlon Oct 19 '13 at 12:34
  • 2
    @SimonO101 well, it was short, but it is an answer . It's a fine line.... – Carl Witthoft Oct 19 '13 at 13:21
  • Yeah true. I was taking a look at your website. There is interest!! nice set of pinball machines :-) – Simon O'Hanlon Oct 19 '13 at 13:22
  • This does not give the factors of a number, only the prime factorization. E.G. for n = 75600, factorize(n) returns 2 2 2 2 3 3 3 5 5 7, when there are over 100 factors/divisors. – Joseph Wood Oct 22 '15 at 20:25
  • @JosephWood OTOH, once you have the prime factorization it's just a matter of creating all combinations of same, which is trivially easy with standard R tools. – Carl Witthoft Oct 22 '15 at 23:22
  • @CarlWitthoft, trivial is all relative. Sure, given the prime factorization of a number *d*, I can brutishly write a one-liner that will get the job done like so (gmp and gtools): sort(unique(c(1,unlist(sapply(1:length(d), function(x) apply(combinations(length(d),x), 1, function(y) prod(d[y]))))))) However, I wouldn't want to call this more than a few times. I think many would agree that more elegant solutions such a the one provided by [Richie Cotton](http://stackoverflow.com/a/6425726/4408538) is non-trivial. – Joseph Wood Oct 23 '15 at 13:36
  • I just realized, I linked the wrong answer. Here is the correct [link](http://stackoverflow.com/a/6425597/4408538) to the answer provided by Richie Cotton. – Joseph Wood Oct 24 '15 at 13:19