I read an interesting DailyWTF post today, "Out of All The Possible Answers..." and it interested me enough to dig up the original forum post where it was submitted. This got me thinking how I would solve this interesting problem - the original question is posed on Project Euler as:
2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.
What is the smallest number that is evenly divisible by all of the numbers from 1 to 20?
To reform this as a programming question, how would you create a function that can find the Least Common Multiple for an arbitrary list of numbers?
I'm incredibly bad with pure math, despite my interest in programming, but I was able to solve this after a little Googling and some experimenting. I'm curious what other approaches SO users might take. If you're so inclined, post some code below, hopefully along with an explanation. Note that while I'm sure libraries exist to compute the GCD and LCM in various languages, I'm more interested in something that displays the logic more directly than calling a library function :-)
I'm most familiar with Python, C, C++, and Perl, but any language you prefer is welcome. Bonus points for explaining the logic for other mathematically-challenged folks out there like myself.
EDIT: After submitting I did find this similar question Least common multiple for 3 or more numbers but it was answered with the same basic code I already figured out and there's no real explanation, so I felt this was different enough to leave open.
The LCM of one or more numbers is the product of all of the distinct prime factors in all of the numbers, each prime to the power of the max of all the powers to which that prime appears in the numbers one is taking the LCM of.
Say 900 = 2^3 * 3^2 * 5^2, 26460 = 2^2 * 3^3 * 5^1 * 7^2. The max power of 2 is 3, the max power of 3 is 3, the max power of 5 is 1, the max power of 7 is 2, and the max power of any higher prime is 0. So the LCM is: 264600 = 2^3 * 3^3 * 5^2 * 7^2.
This problem is interesting because it doesn't require you to find the LCM of an arbitrary set of numbers, you're given a consecutive range. You can use a variation of the Sieve of Eratosthenes to find the answer.
Edit: A recent upvote made me re-examine this answer which is over 3 years old. My first observation is that I would have written it a little differently today, using
enumerate
for example. A couple of small changes were necessary to make it compatible with Python 3.The second observation is that this algorithm only works if the start of the range is 2 or less, because it doesn't try to sieve out the common factors below the start of the range. For example, RangeLCM(10, 12) returns 1320 instead of the correct 660.
The third observation is that nobody attempted to time this answer against any other answers. My gut said that this would improve over a brute force LCM solution as the range got larger. Testing proved my gut correct, at least this once.
Since the algorithm doesn't work for arbitrary ranges, I rewrote it to assume that the range starts at 1. I removed the call to
reduce
at the end, as it was easier to compute the result as the factors were generated. I believe the new version of the function is both more correct and easier to understand.Here are some timing comparisons against the original and the solution proposed by Joe Bebel which is called
RangeEuclid
in my tests.For the range of 1 to 20 given in the question, Euclid's algorithm beats out both my old and new answers. For the range of 1 to 100 you can see the sieve-based algorithm pull ahead, especially the optimized version.
Here is the solution using C Lang
One-liner in Haskell.
This is what I used for my own Project Euler Problem 5.
This is probably the cleanest, shortest answer (both in terms of lines of code) that I've seen so far.
source : http://www.s-anand.net/euler.html