math - need divisors algorithm

Philp Smith philipasmith at blueyonder.co.uk
Thu Mar 31 01:53:18 EST 2005


excellent - thanks
in the meantime I managed to write something myself which
a)    works
b)    looks reasonably elegant and pythonic
but
c)   is recursive
d)  requires a mainroutine and co-routine

I have a feeling if I analysed it it would prove to be relatively 
inefficient as I'm sure it creates a lot of temporary objects (partial 
lists)

So I will gratefully try your version - and for interest's sake post mine at 
some point (its on other computer) for comment.

Phil

"Tim Peters" <tim.peters at gmail.com> wrote in message 
news:mailman.1111.1112246542.1799.python-list at python.org...
> [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