Currency calculations

R

Rick DeBay

I'm doing some simple currency calculations (US, non-fractional pennies) and the
code I inherited is using floats. It turns out the rounding is all messed up and
accounting is noticing that pennies are getting dropped.
This is actually two questions, as I notice floating point results go wild for
simple addition/subtraction if parentheses are moved (for addition/subtraction
this shouldn't matter if the sign is commuted).
How should I refactor this code? It's pretty simple, trying to split a cash
value between two accounts and rounding to the nearest cent.
I tried a float calculation with add/subtract multiple values, and then
multiplied the result (with the percentage one party was to receive),
constructed a BigDecimal, and scaled it. But when I subtracted the BigDecimal
from the total (to find what the other party was to get) the JVM used the
underlying value (with the really long decimal) instead of the scaled version.
So I still can't do a simple "you get x%, and you get the rest" and have it come
out to whole cents, without pennies left over or missing. Any tips?

Rick DeBay
 
S

Sudsy

Rick said:
I'm doing some simple currency calculations (US, non-fractional pennies) and the
code I inherited is using floats. It turns out the rounding is all messed up and
accounting is noticing that pennies are getting dropped.
<snip>

That's because whoever wrote the code originally broke one of the
cardinal rules of dealing with currencies. You can't use float or
even double. Use long and store the value as the number of cents.
Format for display/report puposes only.
 
R

Rick DeBay

<snip>

That's because whoever wrote the code originally broke one of the
cardinal rules of dealing with currencies. You can't use float or
even double. Use long and store the value as the number of cents.
Format for display/report puposes only.

Do you have any suggestions for working around this? I can't change the
database types. The only thing I haven't tried yet is starting with all values
as BigDecimal and continuing from there, converting back to float just before
storing in the database.

Rick DeBay
 
S

Sudsy

Rick DeBay wrote:
Do you have any suggestions for working around this? I can't change the
database types. The only thing I haven't tried yet is starting with all values
as BigDecimal and continuing from there, converting back to float just before
storing in the database.

If you're using ResultSet.getBigDecimal() to pull the numbers from the
database then just multiply by 100 and store in a long. Perform all
calculations with the long and then save it back to the database in
the appropriate format, after dividing by 100 first.
 
T

Tim Slattery

Sudsy said:
<snip>

That's because whoever wrote the code originally broke one of the
cardinal rules of dealing with currencies. You can't use float or
even double. Use long and store the value as the number of cents.
Format for display/report puposes only.

Or use the BigDecimal class.
 
R

Roedy Green

I'm doing some simple currency calculations (US, non-fractional pennies) and the
code I inherited is using floats. It turns out the rounding is all messed up and
accounting is noticing that pennies are getting dropped.
This is actually two questions, as I notice floating point results go wild for
simple addition/subtraction if parentheses are moved (for addition/subtraction
this shouldn't matter if the sign is commuted).
How should I refactor this code? It's pretty simple, trying to split a cash
value between two accounts and rounding to the nearest cent.

First try double. That gives you considerable more precision than
float. If you are doing US currency, try long and keep the results in
pennies. You can then precisely control the rounding.

For more hints see http://mindprod.com/jgloss/currency.html#CURRENCY
 
R

Roedy Green

You can't use float or
even double. Use long and store the value as the number of cents.
Format for display/report puposes only.

When you start dealing with international currencies and if you are
simply doing currency conversion, the double should suffice. That's
what I do in currcon. See
http://mindprod.com/jgloss/currencyconverter.html.

What gets you in trouble is adding up columns of figures. Then you
want longs or BigIntegers to make sure the humans are not freaked by
an off by penny error from roundoff.
 
R

Roedy Green

Do you have any suggestions for working around this? I can't change the
database types. The only thing I haven't tried yet is starting with all values
as BigDecimal and continuing from there, converting back to float just before
storing in the database.

the problem is the inherent inaccuracy of you database figures.
 
D

Dave Monroe

Rick DeBay said:
I'm doing some simple currency calculations (US, non-fractional pennies) and the
code I inherited is using floats. It turns out the rounding is all messed up and
accounting is noticing that pennies are getting dropped.
This is actually two questions, as I notice floating point results go wild for
simple addition/subtraction if parentheses are moved (for addition/subtraction
this shouldn't matter if the sign is commuted).
How should I refactor this code? It's pretty simple, trying to split a cash
value between two accounts and rounding to the nearest cent.
I tried a float calculation with add/subtract multiple values, and then
multiplied the result (with the percentage one party was to receive),
constructed a BigDecimal, and scaled it. But when I subtracted the BigDecimal
from the total (to find what the other party was to get) the JVM used the
underlying value (with the really long decimal) instead of the scaled version.
So I still can't do a simple "you get x%, and you get the rest" and have it come
out to whole cents, without pennies left over or missing. Any tips?

Rick DeBay

Take a look at the DecimalFormat class. That cleans up a lot of
floating point transgressions.

Dave Monroe
 
J

Jim Cobban

Rick DeBay said:
I'm doing some simple currency calculations (US, non-fractional pennies) and the
code I inherited is using floats. It turns out the rounding is all messed up and
accounting is noticing that pennies are getting dropped.
This is actually two questions, as I notice floating point results go wild for
simple addition/subtraction if parentheses are moved (for addition/subtraction
this shouldn't matter if the sign is commuted).

Floating point is OK to use as long as the value is manipulated in cents,
that is because a double can represent any integer value precisely up to 56
bits. That is a double can represent a currency amount to about
$700-trillion in magnitude. So if you just multiply all values by 100 (and
round to the nearest cent) as you load them from the database, do all your
arithmetic in cents, and then divide by 100 as you store them back in the
database, you should be OK.

Of course the idiot who implemented the database in floating point dollars
should be fired, retroactively if necessary.
 
M

Mark Thornton

Sudsy said:
<snip>

That's because whoever wrote the code originally broke one of the
cardinal rules of dealing with currencies. You can't use float or
even double. Use long and store the value as the number of cents.
Format for display/report puposes only.

Of course you can use float or double for currency calculations. It is
really only in accounting applications that it may be necessary to use
other types such as long or BigDecimal. BigDecimal may well be a better
choice then long as it directly represents the required values (scaling
is internal) and provides a selection of rounding modes.
My currency calculations use float or doubles, but as the calculations
involve predictions based on values which are only estimates, the use of
floating point types is appropriate. Also remember that doubles can
represent integers up to 2^53 exactly.

Mark Thornton
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top