Opened 11 years ago
Closed 11 years ago
#23399 closed Cleanup/optimization (fixed)
Update int_to_base36
| Reported by: | None | Owned by: | None |
|---|---|---|---|
| Component: | Utilities | Version: | dev |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Unreviewed | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
I propose change function int_to_base36:
def int_to_base36(n):
assert isinstance(n, (int, long))
c = '0123456789abcdefghijklmnopqrstuvwxyz'
sign = ''
if n < 0:
sign, n = '-', -n
if 0 <= n < 36:
return sign + c[n]
b36 = ''
while n != 0:
n, i = divmod(n, 36)
b36 = c[i] + b36
return sign + b36
I think that it's better and faster.
Change History (5)
comment:1 by , 11 years ago
comment:2 by , 11 years ago
It's an interesting idea. For the purposes of demonstration, here's some back-of-the-napkin unscientific benchmarks, from Python 2.7.6, with sys.maxint = 9223372036854775807:
time python baseline.py
import sys
print("sys.maxint is: %s" % sys.maxint)
for x in xrange(0, 1000000):
continue
print("Complete")
Consistently yields something about the range:
real 0m0.080s
user 0m0.066s
sys 0m0.012s
the version in django:
time python original.py
import sys
from django.utils.http import int_to_base36
print("sys.maxint is: %s" % sys.maxint)
for x in xrange(0, 1000000):
int_to_base36(i=x)
print("Complete")
yields:
real 0m3.337s
user 0m3.314s
sys 0m0.020s
The version proposed by liminspace, adjusted to raise the same TypeErrors as Django's existing one:
import sys
from django.utils import six
print("sys.maxint is: %s" % sys.maxint)
def int_to_base36(n):
if n < 0:
raise ValueError("Negative base36 conversion input.")
if six.PY2:
if not isinstance(n, six.integer_types):
raise TypeError("Non-integer base36 conversion input.")
if n > sys.maxint:
raise ValueError("Base36 conversion input too large.")
c = '0123456789abcdefghijklmnopqrstuvwxyz'
sign = ''
if n < 0:
sign, n = '-', -n
if 0 <= n < 36:
return sign + c[n]
b36 = ''
while n != 0:
n, i = divmod(n, 36)
b36 = c[i] + b36
return sign + b36
for x in xrange(0, 1000000):
int_to_base36(n=x)
print("Complete")
yields around:
real 0m2.859s
user 0m2.847s
sys 0m0.010s
So, over the first million smallest integers, there is some small speed-up (takes about 85% of the time), by the look of those numbers.
For the top million (changed to xrange(maxint - 1000000, 100000), the times seem a little more pronounced (the new version is about 60% of the original's time):
time python baseline.py
real 0m0.069s
user 0m0.060s
sys 0m0.008s
Django's original:
time python original.py
real 0m11.840s
user 0m11.805s
sys 0m0.029s
The new version I pasted above:
time python new.py
real 0m6.897s
user 0m6.877s
sys 0m0.017s
comment:3 by , 11 years ago
kezabelle, try this:
def int_to_base36(n):
if n < 0:
raise ValueError("Negative base36 conversion input.")
if six.PY2:
if not isinstance(n, six.integer_types):
raise TypeError("Non-integer base36 conversion input.")
if n > sys.maxint:
raise ValueError("Base36 conversion input too large.")
c = '0123456789abcdefghijklmnopqrstuvwxyz'
if n < 36:
return c[n]
b36 = ''
while n != 0:
n, i = divmod(n, 36)
b36 = c[i] + b36
return b36
comment:4 by , 11 years ago
First million:
time python new2.py
real 0m2.682s
user 0m2.667s
sys 0m0.012s
last million:
time python new2a.py
real 0m6.539s
user 0m6.520s
sys 0m0.015s
Also did a quick test of assert new_int_to_base36(n=x) == original_int_to_base36(i=x) for both the first and last million, which raised no errors.
comment:5 by , 11 years ago
| Resolution: | → fixed |
|---|---|
| Status: | new → closed |
This implementation isn't backwards compatible with respect to the errors it raises on invalid inputs.
Some benchmarks would be helpful as far as speed goes.