Hi all of you!

Many thanks for your remarks, ideas and experiments.

When I posted my input yesterday:

[x for x in range(2,100) if not [y for y in range(2,x) if x%y==0]]

my intention was indeed to find a "shortest" a program, disregarding
efficiency. Thus range instead of xrange etc.

(About one year ago I was involved in a "coding contest" at Linux-Tag
in Karlsruhe, where the goal was to achive a certain output with a
shortest program ;-) Strange. I used Python, but I didn't win :-(  )

Clearly there are several criteria concerning the quality of programs
as e. g. conciseness, clarity, efficiency, beauty(!) etc. which may not
be achieved optimally all together ...

I definitely intend to sum up your contibutions (for me) later, but for
now (because of lack of time) I'll only present one more idea,
induced by Danny's (unfortunately buggy - because of recursion overflow) contribution:


Thought it would be nice to use Python's new generator-expressions
instead of itertool module. First idea:

##################################################################
# infinite prime generator
# induced by ideas of Danny Yoo,
# which themselves were induced by material of SICP

import math

def prime(n):
    return [x for x in range(2,1+int(math.sqrt(n))) if n%x==0]==[]

def infrange(n):
    while True:
        yield n
        n+=1

primes = (p for p in infrange(2) if prime(p))

###############  The generator primes works like this:

>>> primes.next()
2
>>> primes.next()
3
>>> primes.next()
5
>>> [primes.next() for i in range(10)]
[7, 11, 13, 17, 19, 23, 29, 31, 37, 41]
>>> [primes.next() for i in range(100)]
[43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617]
>>>
>>> ### You may also use it this way:
>>> for p in primes:
if p > 1000: break
print p,



619 631 641 643 647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997



With a fresh generator

[primes.next() for p in xrange(10000)]

produces (on my machine) a list of the first 10000 primes (upto 104729)
within 4.68 secs.

Now for a bit of optimization: instead of building a list of
all divisors use a loop and get out as soon as possible:

So I replace prime by:

def prime(n):
    for d in range(2,1+int(math.sqrt(n))):
        if n%d == 0: return  False
    return True

This makes the generator nearly 4 times as fast. I get my list in
1.33 secs.

Lets optimize a bit more: test only 2 and odd numbers:

def infrange(n):
    yield 2
    n=3
    while True:
        yield n
        n+=2

and do a similar thing for searching for divisors:

def prime(n):
    if n==2: return True
    for d in [2]+ range(3,1+int(math.sqrt(n)),2):
        if n%d == 0: return  False
    return True

Now the first 10000  primes get computed in 0.67 secs.
Again double speed. Together seven times as fast as
first version. But IMO at the cost of clarity
and conciseness.

Maybe you have amendments (of course a matter of taste)
to this code. I'd be interested in them ..

Maybe sombody likes to compare these algorithms to the
ones mentioned before in this thread. I would be
interested in the results.

Regards,
Gregor



Danny Yoo schrieb:

On Thu, 17 Mar 2005, Gregor Lingl wrote:


Hi!
Who knows a more concise or equally concise but more efficient
expression, which returns the same result as
...
######

from itertools import ifilter, count

def notDivisibleBy(n):

... def f(x): ... return x % n != 0 ... return f ...

def sieve(iterable):

... nextPrime = iterable.next() ... yield nextPrime ... restOfPrimes = sieve(ifilter(notDivisibleBy(nextPrime), iterable)) ... for prime in restOfPrimes: ... yield prime ...

primes = sieve(count(2))
primes.next()

2

primes.next()
...
primes.next()

23 ######

The neat thing about this code is that it produces an infinite iterator of
prime numbers.  The original code in Scheme is itself quite concise and
quite nice.  It is described here:

http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-24.html#call_footnote_Temp_455


Best of wishes to you!




-- Gregor Lingl Reisnerstrasse 3/19 A-1030 Wien

Telefon: +43 1 713 33 98
Mobil:   +43 664 140 35 27

Autor von "Python für Kids"
Website: python4kids.net
_______________________________________________
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor

Reply via email to