This question is a problem of computing the least common multiple (LCM). Several standard methods for solving it are by using the greatest common divisor (GCD), prime factorization and reduction.
GCD comes into play since, for two integers a and b,
GCD(a,b)*LCM(a,b) = a*b
and computation of GCD is well known using the Euclidian algorithm, although maybe not by that name, but which can be expressed as
def gcd(x,y):
while y:
x,y = y,x%y
return abs(x)
GCD and LCM for two numbers in themselves does not solve the problem for more than two, however they both share the property of associativity, which is a setup for reduction over more than two numbers. What that means is:
GCD(a,b,c,d)=GCD(GCD(GCD(a,b),c),d) # associativity
LCM(a,b,c,d)=LCM(LCM(LCM(a,b),c),d) # associativity
and for some function fun
reduce(fun,[a,b,c,d])
is equivalent to
fun(fun(fun(a,b),c),d) # expanded reductive form
which implies that
GCD(a,b,c,d) = reduce(GCD,[a,b,c,d])
LCM associativity also implies that just a two argument LCM function is necessary for reduction over more than two and GCD is not needed. That's good because it decreases overhead, since computing LCM directly requires fewer operations than with GCD.
In case you're wondering, GCD and LCM are both also commutative. That simply means the order of elements in their argument lists does not affect the results.
Based on this information, review of over 150 LCM implementations and some testing, the following Python LCM function appears best in performance and simplicity:
def lcm(*args):
def lcm2(x,y):
tmp=x
while (tmp%y)!=0:
tmp+=x
return tmp
return reduce(lcm2,args)
This function is from the answer by Eratosthenes on Least common multiple for 3 or more numbers.
Let's see how it performs using Python 3.4.3 x64
from functools import reduce
a = [2, 3, 4, 5, 6, 7, 8, 9, 10]
lcm(*a)
Out[9]: 2520
timeit lcm(*a)
100000 loops, best of 3: 5.95 µs per loop
timeit lcm(2, 3, 4, 5, 6, 7, 8, 9, 10)
100000 loops, best of 3: 5.9 µs per loop
For Python 2.7.10 x64
lcm(*a)
Out[60]: 2520
timeit lcm(*a)
100000 loops, best of 3: 4.36 µs per loop
timeit lcm(2, 3, 4, 5, 6, 7, 8, 9, 10)
100000 loops, best of 3: 4.33 µs per loop
LCM can also be computed using prime factorization. The fundamental theorem of arithmetic, also called the unique factorizaton theorem, says that "every integer greater than 1 either is prime itself or is the product of prime numbers, and this product is unique, up to the order of the factors." This means that each divisor in a list of divisors has a prime factorization and each prime in all these factorizations occurs a maximum number of times for at least one divisor. Therefore, the minimum natural number which can be evenly divided by all the divisors, AKA their LCM, is the product of all the occurring primes each raised to the power of its maximum number of times. Here is implementation code for this method:
from collections import defaultdict
from operator import mul
try:
reduce
except:
from functools import reduce
def findmnn(a):
def prime_factors(n):
factors = defaultdict(int)
d = 2
step = 1
while d*d <= n:
while n>1:
while n%d == 0:
factors[d] += 1
n = n/d
d += step
step = 2
return factors
d = defaultdict(int)
for i in a:
p = prime_factors(i)
for j in p:
if p[j] > d[j]:
d[j] = p[j]
return reduce(mul, map(lambda x: x**d[x], d))
Given the list of divisors as
a = [2, 3, 4, 5, 6, 7, 8, 9, 10]
findmnn(a)
Out[3]: 2520
Testing with timeit using Python 2.7.10 x64
timeit findmnn(a)
10000 loops, best of 3: 23.1 µs per loop
Testing with timeit using Python 3.4.3 x64 on the same platform:
timeit findmnn(a)
10000 loops, best of 3: 49.4 µs per loop
For comparison and on the same platform:
def mpmnn():
n = 0
while True:
n += 10
if all(n % i == 0 for i in (6, 7, 8, 9)):
return n
Using Python 2.7.10 x64
timeit mpmnn()
1000 loops, best of 3: 245 µs per loop
And with Python 3.4.3 x64
timeit mpmnn()
1000 loops, best of 3: 244 µs per loop
Here are some references
- Least Common Multiple (Wolfram World)
- Least Common Multiple Code Examples (Rosetta Code)
- Greatest Common Divisor (Wolfram World)
- Euclidean Algorithm (Wolfram World)
- Fundamental theorem of arithmetic (WikepediA)