There's more than one way to do things PerlMonks

### Finding the greatest common divisor

by gornox_zx (Priest)
 on Sep 03, 2001 at 18:24 UTC Need Help??
gornox_zx has asked for the wisdom of the Perl Monks concerning the following question:

Hello monks (meant here in a unisex context)

I have several problem sets wherein I am needing to find the GCD (Greatest Common Divisor) between 2 large numbers. Now I wrote a program that took in the 2 numbers and printed out all the divisors of those numbers. The lists were very long however; so I thought to myself; self, you should make the program compare the 2 lists for the greatest common one, or at least for all the common ones. In this though I failed. The following is my code, and I was hoping one of the geniuses who oft roam the monestery could quickly see my problem and offer some suggestion. I am sure it is a very stupid mistake.

```#!/usr/bin/perl

use strict;

my @thing;
my @thing1;
my \$test=0;
my (\$i,\$j,\$k,\$arg1,\$arg2);

while(my \$argv=shift){
if(\$test==0){
\$arg1=\$argv;
}
if(\$test>0){
\$arg2=\$argv;
}

for(\$i=1;\$i<=\$argv;\$i++){
if(!(\$argv%\$i)){

if(\$test==0){
@thing[\$i]=\$i;
}
if(\$test>0){
@thing1[\$i]=\$i;
}

}
}
\$test++;
}
for(\$j=0;\$j<=\$arg1;\$j++){
for(\$k=0;\$k<=\$arg2;\$k++){
if(@thing[\$j] == @thing1[\$k]){
print "A common divisor of \$arg1 and \$arg2 is: ". @thing[\$j] . "\
+n";
}

}
}

~heise2k~

Replies are listed 'Best First'.
Re: Finding the greatest common divisor
by larsen (Parson) on Sep 03, 2001 at 19:01 UTC
I was hoping one of the geniuses who oft roam the monestery could quickly see my problem and offer some suggestion

Use the shoulders of an ancient genius :)
You could use Euclidean algorithm to find GCD. It's very simple: you can find info here. (http://www.nist.gov/dads/HTML/euclidalgo.html)

Re: Finding the greatest common divisor
by Dominus (Parson) on Sep 03, 2001 at 21:25 UTC

Great heavens, don't do all that. You don't have to find all the divisors just to find the greatest common divisor. Just use this:

```sub gcd {
my (\$a, \$b) = @_;
(\$a,\$b) = (\$b,\$a) if \$a > \$b;
while (\$a) {
(\$a, \$b) = (\$b % \$a, \$a);
}
return \$b;
}
This algorithm was invented by Euclid about 2200 years ago.
Actually Euclid's Elements were written about 2300 years ago. But we don't know whether or not he originated it. It is true that the first written record that we have of it is in Proposition VII.2. However we have no particular reason to believe that Euclid invented most of his results. All that we know is that he wrote the textbook.

And the algorithm was of practical use at the time for converting money from one currency to another. So for all we know it may have been in wide-spread use prior to Euclid. Or it might have been used by the Phoenicians from whom we have very few records, but who are known to have engaged in trade and were purportedly good with numbers. (But who were, of course, not on such good terms with Rome...)

The truth is that we simply don't know who came up with the results in Euclid's textbook.

An incidental piece of trivia. The Elements of Euclid is the single most often translated and published non-religious work in history. (The most often translated and published work is, of course, the Bible.)

Re: Finding the greatest common divisor
by tachyon (Chancellor) on Sep 03, 2001 at 20:13 UTC

This is an inelegant brute force approach:

```my \$num1 = 150;
my \$num2 = 1000;

# set which is biggest and which smallest
my \$max = (\$num1 > \$num2)? \$num1 : \$num2;
my \$min = (\$num1 < \$num2)? \$num1 : \$num2;

for \$divisor (reverse 0 .. \$min) {
# fail unless our divisor divides evenly into \$min
next if \$min % \$divisor;
# fail unless our divisor divides evenly into \$max
next if \$max % \$divisor;
print "Largest common divisor is \$divisor\n";
last;
}

This is O(n) in that the bigger the smaller number the longer this will take to run. For a more elegant approach use Euclid's recursive algorithm as suggested by larsen it is O(log \$a * log \$b) - ie so much more efficient it is not funny!:

```print euclid(15000,1260);

sub euclid {
my( \$a, \$b ) = @_;
return (\$b) ? euclid( \$b, \$a % \$b ) : \$a;
}

cheers

tachyon

s&&rsenoyhcatreve&&&s&n.+t&"\$'\$`\$\"\$\&"&ee&&y&srve&&d&&print

Re: Finding the greatest common divisor
by damian1301 (Curate) on Sep 03, 2001 at 21:56 UTC
This just goes to show that a search can always find what you want on PM. This is in the snippets -- greatest common factor.
```s&&q+\+blah+&oe&&s<hlab>}map{s}&&q+}}+;;s;\+;;g;y;ahlb;veaD;&&print;
Re: Finding the greatest common divisor
by George_Sherston (Vicar) on Sep 03, 2001 at 19:05 UTC
Sorry if I've got the wrong end of the stick, but I take it you already can come up with the 2 arrays full of the divisors, and you then want to find from those 2 arrays the highest number that is in both arrays? If that's what you want, I think this approach might fit the bill:
```# insert these 3 lines if arrays aren't sequential
sub numerical {\$a <=> \$b}
@array_1 = sort numerical @array_1;
@array_2 = sort numerical @array_2;

my \$array_1 = pop @array_1;
my \$array_2 = pop @array_2;
while (@array_1) {
if (\$array_1 > \$array_2) {
\$array_1 = pop @array_1;
}
elsif (\$array_2 > \$array_1) {
\$array_2 = pop @array_2;
}
else {
print "highest common divisor = \$array_2\n";
last;
}
}
.. i.e., just keep popping off the highest number in each array until the current pair match, and Bob's yer uncle.

§ George Sherston

Create A New User
Node Status?
node history
Node Type: perlquestion [id://109872]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (3)
As of 2019-04-23 05:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
I am most likely to install a new module from CPAN if:

Results (114 votes). Check out past polls.

Notices?