math - need divisors algorithm
Tim Peters
tim.peters at gmail.com
Thu Mar 31 00:22:20 EST 2005
[Philp Smith]
> Does anyone have suggested code for a compact, efficient, elegant, most of
> all pythonic routine to produce a list of all the proper divisors of an
> integer (given a list of prime factors/powers)
If the canonical factorization of N is the product of p_i**e_i, the
number of divisors is the product of e_i+1. This can be
astronomically large, so it's important to minimize the number of
multiplications performed, and to write a generator to produce the
divisors (it may, e.g., be impossible to materialize a list of all of
them).
This one's easy and efficient:
def gen_divisors(prime_list):
elts = sorted(set(prime_list))
numelts = len(elts)
# Split on the number of copies of elts[i].
def gen_inner(i):
if i >= numelts:
yield 1
return
thiselt = elts[i]
thismax = prime_list.count(thiselt)
# powers <- [thiselt**i for i in range(thismax+1)],
# but using only thismax multiplications.
powers = [1]
for j in xrange(thismax):
powers.append(powers[-1] * thiselt)
for d in gen_inner(i+1):
for prime_power in powers:
yield prime_power * d
for d in gen_inner(0):
yield d
For example, do:
for d in gen_divisors([2, 3, 2, 3, 2, 3, 5, 2, 3]):
print d
You're on your own for the "proper" business; try not to use more than
one line to do it <wink>.
I find recursion clearest here. An iterative version is easy enough
to do by incrementing from 0 thru product(e_i) (and just skipping the
endpoints if you really want "proper") in a mixed-radix system defined
by the e_i. Exercise for the reader.
Harder: generate divisors in increasing order.
More information about the Python-list
mailing list