Skip to content

Instantly share code, notes, and snippets.

@the-moog
Last active June 18, 2022 19:11
Show Gist options
  • Save the-moog/eee29531f3f6fd5853cf6e5188ed4cf0 to your computer and use it in GitHub Desktop.
Save the-moog/eee29531f3f6fd5853cf6e5188ed4cf0 to your computer and use it in GitHub Desktop.
Comparing Python round() vs math.floor()
import timeit
import sys
import platform
# Expected result values vs output values (we always expect rounded down)
du = {
1.231234: 1.23,
1.239876: 1.23,
1.999999: 1.99,
1.00000001: 1.00,
}
# Number of runs
runs = int(10e6)
# Functions to try
fns = {
"math.floor": "(v * 100) / 100",
"round": "(v - 0.005, 2)",
"np.round": "(v - 0.005, 2)",
"np.floor": "(v * 100) / 100"
}
# Override the existing code template to return a value from the code being run
template = """
def inner(_it, _timer{init}):
{setup}
_t0 = _timer()
for _i in _it:
ret = {stmt}
pass
_t1 = _timer()
return _t1 - _t0, ret
"""
timeit.template = template
results = {}
print(f"\nUsing timeit in Python {sys.version} under {platform.platform()}")
print(f"to run {runs:_d} iterations of each function in:")
print("\n".join(f" {n+1}: {fn}" for n, fn in enumerate(fns)))
print("")
for v, expect in du.items():
for fn, params in fns.items():
r = 0
globs = {"v": v}
params = params.replace('v', str(v))
t = timeit.Timer(fn+params, setup="import numpy as np\nimport math")
dur, ret = t.timeit(number=int(runs))
dur = (1e6 * dur) / runs # Turn s into microseconds
print(f"Testing {fn}: timeit({fn}{params}) - {runs:_d} iterations")
print(f" = {ret}, this took {dur:6.4f} (us/run) average \n")
results[(fn, v)] = params, dur, "PASS" if ret == expect else f"FAIL: Expected {expect} got {ret}"
print("Results:")
sorted_results = {k: results[k] for k in sorted(results, key=lambda x: results[x][1])}
for n, ((fn, result), (params, duration, ok)) in enumerate(sorted_results.items()):
fs = "(fastest) " if n == 0 else "(slowest) " if n == len(results) - 1 else ""
print(f"{(fs+fn):>25s} {result: 3.10f}: {duration: 3.10f}us {ok:>30s}")
fastest = list(sorted_results.keys())[0]
slowest = list(sorted_results.keys())[-1]
print("\nConclusion:")
print(f"The fastest is: {fastest[0]}({sorted_results[fastest][0]})")
fastest_time = sorted_results[fastest][1]
slowest_time = sorted_results[slowest][1]
print(f"The fastest is {slowest_time/fastest_time:.2f} x faster than the slowest")
@the-moog
Copy link
Author

the-moog commented Jun 18, 2022

As a result of this question on SO, I noticed that numpy was very slow compared to Python 3.10's math standard libray, and that was on an old laptop under WSL2. So I thought I'd post some code to emphasise the point. In the past I've always gone to numpy if I want fast maths, obviously I need to think twice about that now.....

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment