Django's floatformat
is a good way to format a number if you require a specific amount of decimals. It is, however, very slow. In testing each floatformat
call took 200–250 us, which means it'll take a second to render a page that floatformats 4000 numbers.
Much of the time comes from using Decimals
. I looked at using the cdecimal
module, and while it improved the speed, each call still clocked in at between 80 and 100 us.
fast_floatformat
is not locale aware, and doesn't look at Django settings for USE_THOUSAND_SEPARATOR, but it'll take between 1.2 and 3 us per call for ints, floats and strings, and about 12 us per call for Decimals, giving you up to 800000 floatformatted numbers per second.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | def fast_floatformat(number, places=-1, use_thousand_separator=False):
"""simple_floatformat(number:object, places:int) -> str
Like django.template.defaultfilters.floatformat but not locale aware
and between 40 and 200 times faster
"""
try:
number = float(number)
except (ValueError, TypeError):
return ''
# floatformat makes -0.0 == 0.0
if number == 0:
number = 0
neg_places = False
if places < 0:
places = abs(places)
neg_places = True
if places == 0:
# %.0f will truncate rather than round
number = round(number, places)
# .format is noticably slower than %-formatting, use it only if necessary
if use_thousand_separator:
format_str = "{:,.%sf}" % places
formatted_number = format_str.format(number)
else:
format_str = "%%.%sf" % places
formatted_number = format_str % number
# -places means formatting to places, unless they're all 0 after places
if neg_places:
str_number = str(number)
if not "." in str_number:
return str_number
if len(str_number) > len(formatted_number):
return formatted_number
int_part, _, _ = formatted_number.partition(".")
if str_number.rstrip("0")[-1] == ".":
return int_part
return formatted_number
# TEST AND VALIDATION
from django.template.defaultfilters import floatformat, special_floats
from decimal import Decimal as Decimal
vals = [
None,
'',
1,
1.9,
2.0,
0.1385798798,
0.2,
-0.5,
-0.0,
-5.0038,
18343.3582828389,
Decimal("-0.0"),
Decimal("5.000083387"),
Decimal("0E-7"),
Decimal("780000.388"),
"-0.5",
"3.80",
"foo",
]
vals.extend(special_floats)
def test_floatformat():
for val in vals:
yield check_equal, val, floatformat(val), fast_floatformat(val)
yield check_equal, val, floatformat(val, 7), fast_floatformat(val, 7)
yield check_equal, val, floatformat(val, -7), fast_floatformat(val, -7)
yield check_equal, val, floatformat(val, 0), fast_floatformat(val, 0)
def check_equal(orig, a, b):
assert a == b, '(%s) %s not equal with %s' % (orig, a, b)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Please login first before commenting.