[Tutor] Need help speeding up algorithm.
Kent Johnson
kent37 at tds.net
Tue Sep 25 18:06:36 CEST 2007
Terry Carroll wrote:
> On Tue, 25 Sep 2007, Ian Witham wrote:
>
>> As I was using a list comprehension I wasn't sure how to make the
>> calculations stop when the result of integer division == 0.
>
> I don't see how to do that, either. Someone on this list (sorry, I forget
> who) once suggested that the list comprehension should support a "while"
> predicate, similar to the "if" filter. Such a predicate would not just
> filter the generated list, but actually stop its computation.
Take a look at itertools.takewhile()
> Now that you've solved your code, here's the function I came up with. As
> I said, it resists implimentation as a list comprehension:
>
> def numfaczeroes(n):
> """
> return the count of trailing zeroes from n!
> e.g., 10! = 3628800; count of trailing zeros = 2
> """
> exponent = 1
> fivecount = 0
> while (n//(5**exponent)) > 0:
> fivecount += n//(5**exponent)
> exponent += 1
> return fivecount
Here is a version using takewhile() and a generator expression:
from itertools import count, takewhile
def numfaczeroes2(n):
def while_(e):
return n//(5**e) > 0
return sum(n//(5**exponent) for exponent in takewhile(while_,
count(1)))
It is quite a bit slower, though; probably because of the extra function
call introduced for while_():
from timeit import Timer
print min(Timer('for i in range(1, 101): numfaczeroes(i)',
setup='from __main__ import numfaczeroes').repeat(number=1000))
print min(Timer('for i in range(1, 101): numfaczeroes2(i)',
setup='from __main__ import numfaczeroes2').repeat(number=1000))
prints:
0.14363694191
0.412271022797
You could also encapsulate the condition in a generator function:
def numfaczeroes3(n):
def gen(n):
e = 1
while (n//(5**e)) > 0:
yield e
e += 1
return sum(n//(5**exponent) for exponent in gen(n))
This is faster than numfaczeroes2 but still not as fast as the original.
Kent
More information about the Tutor
mailing list