Wesley
Wesley

Reputation: 1237

How to resolve the accuracy error with floating point arithmetic

I am trying to make a program that calculates the equivalent amount of change for a given amount of money. Everything in the program works well until I get to pennies. When I get to pennies, I've done so much floating point arithmetic that the value becomes inaccurate. Here is the output:

enter image description here

As we can see, rather than have 0.2 (which I would divide by 0.1 to get 2, the correct answer), we have 019999999999959064 (which when divided by 0.01 to get the amount of pennies, we get 1 not 2). How can I resolve this issue so that I can get the correct amount of pennies?

Upvotes: 2

Views: 615

Answers (4)

Peter Lawrey
Peter Lawrey

Reputation: 533930

You need to use appropriate rounding. Even if you use long or BigDecimal rounding issues don't go away, though in this case it would be much simpler.

A good place to start is rounding to a long number of cents.

double value = 586.67;
long v = Math.round(value * 100.0); // the fact you used a double is fine.
long hundreds = v / 100;
v -= hundreds * 100;
long fifties = v / 50;
v -= fifties * 50;
long twenties = v / 20;
v -= twenties * 20;
long tens = v / 10;
v -= tens * 10;

You could do this with double, however you would need to round each step of the way, which is more complicated in this example.

Upvotes: 1

DwB
DwB

Reputation: 38348

Diatribe

Stop using floating point to represent currency. BigDecimal is just as bad, but will have fewer precision (perhaps none) issues.

If you use BigDecimal, I suggest that you include the following comment in your code:

// Danger, this code written by a goofball (insert your name here).

The Real Solution

Use longs and represent values starting at a meaningful (to your situation) fraction of a penny; perhaps 1000th of a penny. Even if you represent 1,000,000th of a penny, a long still provides plenty of room to significantly more than $9,223,372,036.99 which is likely to be larger than any transaction you need to process.

Upvotes: 2

Ronan
Ronan

Reputation: 613

Math.round is one way to solve this but I would not recommend it.

another way is to use BigDeciaml which is a lot a more accurate especially when dealing with currency

Another way in which I read about recently is to work in whole numbers until the end eg work in cents instead of dollars so $1 would be 100 instead and work from there instead.

I hope these ideas help

very intereesting video on floating points in general

math api

Upvotes: 0

Bathsheba
Bathsheba

Reputation: 234885

You can't. Floating point is not a good choice for modelling exact monetary values.

Either (i), use a long type and work in pence, or (ii) use a class designed to model money.

Upvotes: 7

Related Questions