Ceil and Floor
Backstory
Some time ago, I was thinking about coding experiments that would be easy to do, expand on, and also interesting. One popped into my head then, and so now I’m doing it. Basically, not knowing exactly what magic built-ins do in various languages to be fast and accurate has always interested me, and since I’ve been doing some coding prep I’ve been using Python a lot, ans specifically I find myself using ceil and floor a lot.
So I thought to myself, why not try to reproduce whatever is happening behind the scenes? I’ll be doing so without any research or looking at the source code, of course. I’m just going to try and figure it out by intuition and past experience.
Intro/setup code
python1# base imports
2from timeit import default_timer as timer
3import math
4from matplotlib import pyplot as plt
5import numpy as np 1# define some test cases
2test_cases = [2, 2.0, 2.1, 2.4, 2.5, 2.55, 2.7, 3, 3.0]
3test_case_ceil_answers = [2, 2, 3, 3, 3, 3, 3, 3, 3]
4test_case_floor_answers = [2, 2, 2, 2, 2, 2, 2, 3, 3]
5
6# test just to test the expediency of running a function once
7def run_single_test(test_func):
8 start = timer()
9 test_func(test_cases[0])
10 end = timer()
11 return end - start
12
13# test runner function
14def run_tests_cases(test_func, answers):
15 start = timer()
16 for i, t in enumerate(test_cases):
17 ans = test_func(test_cases[i])
18 if ans != answers[i]:
19 raise Exception(f"Incorrect answer. Test case {i + 1}: (ans: {ans}, actual: {answers[i]})")
20 end = timer()
21 return end - startBaseline
Let's first compare the time it takes to run the native ceil and
floor functions. These will be our baseline.
1# baseline tests
2ceil_base_time = run_single_test(ceil)
3floor_base_time = run_single_test(floor)
4ceil_tests_time = run_tests_cases(ceil, test_case_ceil_answers)
5floor_tests_time = run_tests_cases(floor, test_case_floor_answers)
6
7ceil_base_time, floor_base_time, ceil_tests_time, floor_tests_time(2.916996891144663e-06,
1.2089949450455606e-06,
6.707996362820268e-06,
2.4170003598555923e-06)
First experiment: int
My first thought for floor is just to run int(). Let's see how that
compares.
1int_func = lambda x: int(x)
2int_time = run_single_test(int_func)
3int_tests_time = run_tests_cases(int_func, test_case_floor_answers)
4
5int_time, int_tests_time(1.2079981388524175e-06, 4.6670029405504465e-06)
python1%matplotlib inline
2x=np.array(["floor single", "int single", "floor tests", "int tests"])
3y=np.array([floor_base_time, int_time, floor_tests_time, int_tests_time])
4fig=plt.bar(x,y)
5plt.title("Test Runtime")
6plt.ylabel("Time")
On a single run's basis, int can be as fast or even a bit faster than
floor, but if used many times in a row it appears it doesn't hold up
to floor at all, and can be at least twice as slow in this small test
case.
More coming soon…