Opened 11 years ago
Closed 5 years ago
#20648 closed Bug (duplicate)
Template variable and loss of precision
Reported by: | Owned by: | nobody | |
---|---|---|---|
Component: | Template system | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | bmispelon@… | Triage Stage: | Accepted |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I use BigIntegerField in model. When i try use it as template variable I get different value. It's becouse all values are initially resolved as float (django/template/base.py:700) and then back to int if float not detected. Based on IEEE 754 it will work only for any integer with absolute value less than or equal to 253:
from django.template import Variable Variable(str(2**53)).resolve(None) == 2**53
but not for greater than 253:
Variable(str(2**53+1)).resolve(None) == 2**53+1
Change History (5)
comment:1 by , 11 years ago
Cc: | added |
---|---|
Triage Stage: | Unreviewed → Accepted |
Version: | → master |
comment:2 by , 11 years ago
Like i said I use BigIntegerField and use its values in custom template tag which is combination of few smaller tags. All internal tags are rendered programmatically. I pass all args as Variable object to be able resolve them.
It's not big problem for me. I bypass the issue by overriding Variable.literal after making init.
comment:3 by , 11 years ago
Note that the issue is only present for number literals. Something like Variable('foo').resolve({'foo': 2**53+1})
incurs not precision loss.
I'm not sure what you mean by "rendering programmatically" but I think you might be better off by not converting your variables to literals (maybe you could construct names dynamically and resolve on those?).
I made some quick benchmarks with timeit
and it seems that converting an int
from a str
is 50% slower than from a float
:
$ python -m timeit -s "x=float(2**53)" "int(x)" 1000000 loops, best of 3: 0.211 usec per loop $ python -m timeit -s "x=str(2**53)" "int(x)" 1000000 loops, best of 3: 0.328 usec per loop
This would need to be confirmed in a more realistic scenario, but if it holds, it seems like a high price to pay for a corner case like this.
Maybe there's a more efficient way to go about this though (and if not, this limitation should be documented).
comment:4 by , 5 years ago
This issue seemed to be resolved already (at least master and 2.2.4).
I don't see any difference from the initial example code.
>>> from django.template import Variable >>> Variable(str(2**53)).resolve(None) == 2**53 True >>> Variable(str(2**53+1)).resolve(None) == 2**53+1 True
comment:5 by , 5 years ago
Resolution: | → duplicate |
---|---|
Status: | new → closed |
Duplicate of #28730.
Fixed in 9ec7d8e514e09636b0ab4bcac74b5f7a5be335a3.
Hi,
I agree that the issue exist, but how much of a problem is this in practice?
Can you describe a concrete case where you ran into this problem.
From what I can tell, it'd be fairly easy to fix this: replace
int(self.literal)
byint(var)
inVariable.__init__
[1]I wonder however if there'd be performance costs to this.
I'm accepting this on the basis that this behavior should at least be documented, if not fixed.
Thanks.
[1] https://github.com/django/django/blob/master/django/template/base.py#L705