views:

316

answers:

6

I'm creating a financial app and it seems my floats in sqlite are floating around. Sometimes a 4.0 will be a 4.000009, and a 6.0 will be a 6.00006, things like that. How can I make these more exact and not affect my financial calculations?

Values are coming from Python if that matters. Not sure which area the messed up numbers are coming from.

+6  A: 

Please use Decimal

http://docs.python.org/library/decimal.html

S.Mark
Wow, I didn't know about that module, but that's awesome! I'll have to remember that.
Mongoose
+2  A: 

Seeing as this is a financial application, if you only have calculations up to 2 or 3 decimal places, you can store all the data internally as integers, and only convert them to float for presentation purposes.

E.g.

6.00 -> 600
4.35 -> 435
Alex B
I think this is terrible advice, with *floats* $600 will be rounded up to $600.01. *double* buys you a few more significant figures but it's still not the right thing to do - what if this code ends up in financial software is used for billion dollar transactions?
gnibbler
That's why I said you can use integer arithmetic instead (e.g. 4003, which is actually 4.003, will have precise representation in integer arithmetic), unless you mean something else? E.g. Please, elaborate.
Alex B
Not really a good idea since international conversion rate have more that two digits after the dot. Like 1 euros was 6,55956 francs.
e-satis
Obviously you can do calculations like that by temporarily converting to floating point numbers, because they are not precise anyway. But when an actual transaction takes place, you can't get paid in fractions of a cent, can you?
Alex B
A: 

You have to use decimal numbers. Decimal numbers can be represented exactly.

In decimal floating point, 0.1 + 0.1 + 0.1 - 0.3 is exactly equal to zero. In binary floating point, the result is 5.5511151231257827e-017.

So, just try decimal:

import decimal
psihodelia
+2  A: 

This is a common problem using SQLite as it does not have a Currency type.
As S.Mark said you can use the Decimal representation library. However SQLite 3 only supports binary floating point numbers (sqlite type REAL) so you would have to store the Decimal encoded float as either TEXT or a BLOB or convert to REAL(but then you'd be back to a 64bit binary float)
So consider the range of numbers that you need to represent and whether you need to be able to perform calculations from within the Database.

You may be better off using a different DB which supports NUMERIC types e.g. MYSql, PostgreSQL, Firebird

10ToedSloth
yeah you may be right but sqlite is so easy and flexible
Recursion
+1  A: 

Most people would probably use Decimal for this, however if this doesn't map onto a database type you may take a performance hit.

If performance is important you might want to consider using Integers to represent an appropriate currency unit - often cents or tenths of cents is ok.

There should be business rules about how amounts are to be rounded in various situations and you should have tests covering each scenario.

gnibbler
A: 

Use Decimal to manipulate your figures, then use pickle to save it and load it from SQLite as text, since it doesn't handle numeric types.

Finaly, use unitest and doctest, for financial operations, you want to ensure all the code does what it is suppose to do in any circonstances. You can't fix bugs on the way like with, let's say, a social network...

e-satis