no sign() function ?

Steven D'Aprano steven at
Tue Dec 23 02:48:28 CET 2008

On Mon, 22 Dec 2008 14:51:32 +0100, Pierre-Alain Dorange wrote:

> I'm new to python and here i discover at least 4 methods, i just make a
> small script for timing those methods (100 000 times each on a set of 10
> values).
> I do not use timeit, i can't make it work easyly as it need a standalone
> env for each test.

But that's just what timeit does: it creates a standalone environment for 
each test.

> ---- the test script -------------------- #!/usr/bin/env python
> from math import atan2
> import time
> def sign_0(x):
>         if x==0.0:
>                 return 0.0
>         elif x>0.0:
>                 return 1.0
>         else:
>                 return -1.0
> def sign_1(x):
>     if x > 0 or (x == 0 and atan2(x, -1.) > 0.):
>         return 1
>     else:
>         return -1
> def sign_2(x):
>         return cmp(x, 0)
> sign_3 = lambda x:+(x > 0) or -(x < 0)
> def main():
>         candidates=[1.1,0.0,-0.0,-1.2,2.4,5.6,-8.2,74.1,-23.4,7945.481]
>         startTime = time.clock()

time.clock() is low resolution on non-Windows systems. If you are using 
Windows, this is okay, if you are not, you are shooting yourself in the 

>         for i in range(100000):
>                 for value in candidates:

Horribly inaccurate, because you are including the time to build a range 
of 100,000 integers. In Python 3, that will only be a little bit 
inaccurate, but in Python 2.x that will have a MAJOR effect -- possibly 
swamping the actual function you are calling.

>                         s=sign_0(value)
>         print "sign_0 : ",time.clock() - startTime

You are (possibly) including the time taken to print to std out in your 

>         startTime = time.clock()
>         for i in range(100000):
>                 for value in candidates:
>                         s=sign_1(value)
>         print "sign_1 : ",time.clock() - startTime

Repeated code is poor coding practice. Write a function that takes a 
function as argument, and call that:

def timer(function, candidates, count=100000):
    loop = [None]*count
    startTime = time.clock()
    for i in loop:
        for value in candidates:
            s = function(value)
    return time.clock() - startTime

But this is just duplicating what timeit already does. Trust me, learn to 
use it, you won't be sorry. Here's a trick that took me a long time to 
learn: instead of copying your functions into the setup code of timeit, 
you can just import them.

This is what I would do (untested):

setup = "from __main__ import sign_%d, candidates"
from timeit import Timer
template = "for x in candidates: s = sign_%d(x)"
for i in range(4):
    t = min( Timer(template % i, setup % i).repeat() )
    print "Testing sign_%d:" % i, t, "seconds"

> ---- conclusions -------------------------------

None of your conclusions are safe until you have re-tested with a better 
timing method. That doesn't mean you are wrong, only that your reasons 
for believing them are weak.


More information about the Python-list mailing list