I’m trying to figure out a fast way to compare the speed of different implementations of a single python algorithm. One option is the timeit module.

I’m not sure the best way to setup these comparisons, so I made a function for each implementation: divceil1divceil6. Then, I made a function to run each and check its output: test1test6. Finally, I’m running the test functions with timeit, e.g.: timeit.timeit(test6, number=5000). The output goes to STDOUT, which I’m redirecting to a CSV file, for processing in a spreadsheet tool. (I know, I know).

Here’s the implementation.

#!/usr/bin/python
""" testing various divceil algorithms """
import timeit
    
    
def divceil1(numerator, denominator):
    """ Returns a division operation rounded up to the next whole number """
    # E.G.: 45/20 -> 3 and 40/20 -> 2
    quotient, remainder = divmod(numerator, denominator)
    return quotient + (1 if remainder > 0 else 0)
    
    
def divceil2(numerator, denominator):
    """ Returns a division operation rounded up to the next whole number """
    # E.G.: 45/20 -> 3 and 40/20 -> 2
    quotient, remainder = divmod(numerator, denominator)
    return quotient + int(remainder > 0)
    
    
def divceil3(numerator, denominator):
    """ Returns a division operation rounded up to the next whole number """
    # E.G.: 45/20 -> 3 and 40/20 -> 2
    quotient, remainder = divmod(numerator, denominator)
    return quotient + (remainder > 0)
    
    
def divceil4(numerator, denominator):
    """ Returns a division operation rounded up to the next whole number """
    # E.G.: 45/20 -> 3 and 40/20 -> 2
    quotient, remainder = divmod(numerator, denominator)
    return quotient + (1 if remainder else 0)
    
    
def divceil5(numerator, denominator):
    """ Returns a division operation rounded up to the next whole number """
    # E.G.: 45/20 -> 3 and 40/20 -> 2
    quotient, remainder = divmod(numerator, denominator)
    if remainder:
        return quotient + 1
    return quotient
    
    
def divceil6(numerator, denominator):
    """ Returns a division operation rounded up to the next whole number """
    # E.G.: 45/20 -> 3 and 40/20 -> 2
    quotient, remainder = divmod(numerator, denominator)
    if remainder:
        return quotient + 1
    else:
        return quotient
    
    
def test1():
    """ Run divceil1, checking output """
    if not (divceil1(45, 20) == 3 and divceil1(40, 20) == 2):
        raise ArithmeticError("Something went awry")
    return
    
    
def test2():
    """ Run divceil2, checking output """
    if not (divceil2(45, 20) == 3 and divceil2(40, 20) == 2):
        raise ArithmeticError("Something went awry")
    return
    
    
def test3():
    """ Run divceil3, checking output """
    if not (divceil3(45, 20) == 3 and divceil3(40, 20) == 2):
        raise ArithmeticError("Something went awry")
    return
    
    
def test4():
    """ Run divceil4, checking output """
    if not (divceil4(45, 20) == 3 and divceil4(40, 20) == 2):
        raise ArithmeticError("Something went awry")
    return
    
    
def test5():
    """ Run divceil5, checking output """
    if not (divceil5(45, 20) == 3 and divceil5(40, 20) == 2):
        raise ArithmeticError("Something went awry")
    return
    
    
def test6():
    """ Run divceil6, checking output """
    if not (divceil6(45, 20) == 3 and divceil6(40, 20) == 2):
        raise ArithmeticError("Something went awry")
    return
    
    
REPEAT = 5000
# note ironic use of .format
for _ in xrange(1000):
    print "6,{}".format(timeit.timeit(test6, number=REPEAT))
    print "5,{}".format(timeit.timeit(test5, number=REPEAT))
    print "4,{}".format(timeit.timeit(test4, number=REPEAT))
    print "3,{}".format(timeit.timeit(test3, number=REPEAT))
    print "2,{}".format(timeit.timeit(test2, number=REPEAT))
    print "1,{}".format(timeit.timeit(test1, number=REPEAT))
    
for _ in xrange(1000):
    print "1,{}".format(timeit.timeit(test1, number=REPEAT))
    print "2,{}".format(timeit.timeit(test2, number=REPEAT))
    print "3,{}".format(timeit.timeit(test3, number=REPEAT))
    print "4,{}".format(timeit.timeit(test4, number=REPEAT))
    print "5,{}".format(timeit.timeit(test5, number=REPEAT))
    print "6,{}".format(timeit.timeit(test6, number=REPEAT))

So obviously it would be between divceil5 or divceil6 here. Here are the results:

Algorithm Total Time Average Time
5 19.5343523026 0.0097671762
6 19.7862572670 0.0098931286
4 20.1976833344 0.0100988417
1 20.4852132797 0.0102426066
3 20.5143792629 0.0102571896
2 26.9490272999 0.0134745136

Unsurprisingly, #5 was the fastest. Tomorrow I’ll look at the difference between it and #6, and so better, more reusable ways to do this kinda thing.