Opened 10 years ago
Closed 10 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 , 10 years ago
comment:2 by , 10 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 , 10 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 , 10 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 , 10 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.