15

So I'm trying to learn R and using a number of resources including a book called "Discovering Statistics using R" and a bunch of other cool eBooks.

I understand a great method in programming is the Euclid's Algorithm.

Implementing it in a loop can be achieved like this:

 gcd(x,y) //assuming x is the largest value
 //do
 r = x%y;
 x = y;
 y = r;
 //while r != 0;
 return x;

After several searches on Google, SO and Youtube refreshing my memory of gcd algorithms, I wasn't able to find one that doesn't use a loop. Even recursive methods seem to use loops.

How can this be achieved in R without the use of loops or if statements?

Thanks in advance.

Reanimation
  • 3,151
  • 10
  • 50
  • 88

4 Answers4

26

Using the statement "without loops or the if statement" literally, here is a recursive version that uses ifelse:

gcd <- function(x,y) {
  r <- x%%y;
  return(ifelse(r, gcd(y, r), y))
}

One might not expect it, but this is actually vectorized:

gcd(c(1000, 10), c(15, 10))
[1]  5 10

A solution using if would not handle vectors of length greater than 1.

Matthew Lundberg
  • 42,009
  • 6
  • 90
  • 112
  • Oh, nice :D So I guess it can be done. I've been curious about this all day. Thanks for taking the time to post. I'm going to have a play with it now. Thanks. – Reanimation Feb 01 '14 at 22:00
  • 1
    This is pretty ingenius – David Arenburg Aug 14 '16 at 14:46
  • 1
    A minor tweak: the assignment is unnecessary, and it is safer not to recurse on the explicit name of the function. Thus: `gcd <- function(x, y) ifelse(y, Recall(y, x %% y), x)`. – egnha Aug 04 '18 at 11:23
  • And `Recall()` works in anonymous functions too, so for a multi argument gcd we could do `gcd <- function(...) Reduce(function(x,y) ifelse(y, Recall(y, x %% y), x), list(...))` – moodymudskipper Aug 13 '20 at 22:28
  • `Recall` is of course preferred for production code. This is academic. – Matthew Lundberg Aug 15 '20 at 13:17
  • Ingenious and beautiful. Has this function been implemented in some package since 2014? – pglpm Mar 04 '23 at 19:28
4

Reducing GCD for two integers enables you to compute GCD for any sequence of integers (sorted or not):

gcd2 <- function(a, b) {
  if (b == 0) a else Recall(b, a %% b)
}

gcd <- function(...) Reduce(gcd2, c(...))
egnha
  • 1,157
  • 14
  • 22
2

You can solve it recursively.

euclids <- function(x,y){
        theMax = max(x,y)
        theMin = min(x,y)

        if (theMax == theMin) return (theMax)
        else return (euclids(theMin, theMax-theMin))
}
skklogw7
  • 41
  • 3
  • This sounds like a repeat of this existing answer. Read this [how-to-answer](http://stackoverflow.com/help/how-to-answer) for providing a quality answer. – thewaywewere May 26 '17 at 02:29
  • Oops - just getting started here. Thanks! – skklogw7 May 26 '17 at 02:47
  • This also uses recursion, but without the clever use of ``ifelse`` shown by @Matthew Lundberg. Easier to read, but doesn't have the Wow effect of Matthew's answer. – PatrickT Dec 19 '17 at 09:27
  • @skklogw7 This answer provides another aspect or way of doing things, therefore I disagree with the comment by thewaywewere. We welcome diverse answers, otherwise StackExchange would not support them, nor would it support voting. – Jonathan Komar May 28 '18 at 10:06
0

It's easy to do with a couple modulo operations. Sadly, I left my personal gcd code on a different machine (in a galaxy far away) - but you can find the source in either the numbers or pracma packages.

BTW, here's a good way to find existing code: library(sos); ???gcd

Carl Witthoft
  • 20,573
  • 9
  • 43
  • 73