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 - start
Baseline
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…