Reputation: 18513
I was naive to use float field for currency in my django project. I just learned about this rounding problem with python float:
>>> 0.1 + 0.2 - 0.3
5.551115123125783e-17
Now I have 2 options:
My question is, is option 2 OK if all I am dealing with is adding and subtracting numbers like 100.0 and 1.2? Is there anything else to worry about aside from the rounding errors?
Upvotes: 0
Views: 647
Reputation: 395
To be clear, the problem isn't with Python's float, but with a binary representation of floating point numbers -- it often isn't exact for numbers that are easy to represent in decimal.
In general, I'd agree with the other answers that you should use the Decimal class, as that is designed for exact representation of floating point numbers (at the cost of space + efficiency of mathematical operations). The other option, if you know exactly what your precision will be (as you said, once decimal point) would be to use integers as fixed point numbers. You'd store 1.3 as 13 and just know you need to shift it by one decimal place before displaying. But using Decimal is cleaner and the code is likely to be more readable.
Upvotes: 1
Reputation: 7893
Use decimal
fields, which use decimal.Decimal
, for handling currency accurately in Python:
>>> from decimal import Decimal as D
>>> D('0.1') + D('0.2') - D('0.3')
Decimal('0.0')
>>> assert _ == 0
Upvotes: 1
Reputation: 174624
Be careful with round()
; round(0.1+0.2-0.3+1.2)
will give you 1.0, not 1.2. You need to use Decimal, then convert it correctly to float:
>>> r = Decimal('0.1') + Decimal('0.2') - Decimal('0.3')
>>> r
Decimal('0.0')
>>> float(r)
0.0
>>> round(0.1+0.2-0.3+1.2)
1.0
>>> r = Decimal('0.1') + Decimal('0.2') - Decimal('0.3') + Decimal('1.2')
>>> r
Decimal('1.2')
>>> float(r)
1.2
This will also take care of your edge cases which you will have to deal with manually should go with the float() + round() approach.
Finally, do not confuse how the value is printed with how its stored. "only allows 1 decimal place" - this is a presentation detail.
Upvotes: 1