File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
Win a copy of Clojure in Action this week in the Clojure forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Float and Double use in currency

 
Greg Ferguson
Ranch Hand
Posts: 34
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I apologize in advance if this has already been addressed.

I am currently working on a project that involves the use of numbers as currency. It seems a lot of people discourage using the float or double data types to represent money. Instead they suggest using int, long, or BigDecimal. Now, I'm familiar with int and long, but I never knew BigDecimal even existed ... until today.

So my questions are:
What is the general consensus about using float or decimal to represent money?
How can I use Integer or Long to represent money?
Should I even attempt to use BigDecimal as a beginner?

Thanks.
 
Greg Charles
Sheriff
Posts: 2984
12
Firefox Browser IntelliJ IDE Java Mac Ruby
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Probably, Integer, Long, or BigInteger, right? The idea is that instead of representing, say, US dollars in a floating point, you represent US cents in an integer. Integer arithmetic is faster and not subject to rounding errors ... except with division. You have to understand your requirements though. Sometimes a float or double may be what you want.

Also, you're working with amounts too high to fit in a Long, let me know. I want to work there.
 
fred rosenberger
lowercase baba
Bartender
Pie
Posts: 12017
24
Chrome Java Linux
  • 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
money only exists in discrete amounts. Sure, we say you can have 1.47 dollars...but that is really 147 pennies - an integer amount. Every currency has some base unit that you can't have a fraction of...Therefore, it makes sense to use something that handles discrete amounts.

And as Greg said, using floating point variables will lead to rounding error. if you add 0.01 together enough times, eventually you'll start seeing extra pennies added in, because 0.01 is actually stored as something like "0.0100000000000324"
 
Campbell Ritchie
Sheriff
Pie
Posts: 47244
52
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It is not that hard to learn to use BigDecimal; even I managed to do it. (Scroll to the bottom of that discussion for a bit more information). You can find out the exact value of 0.1, and a warning not to use it, here.

Once you know how to use BigDecimal, you will never feel the temptation to use floating‑point arithmetic for money again.
 
Winston Gutkowski
Bartender
Pie
Posts: 9472
50
Eclipse IDE Hibernate Ubuntu
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
fred rosenberger wrote:money only exists in discrete amounts.

That's one of the best and most succinct explanations I've ever come across, Fred. And of course, absolutely right. Well done. Gold star from me.

'Course, then you get accountants; and bosses...and of course governments have to stick their oar in....

Winston
 
Paul Clapham
Sheriff
Pie
Posts: 20177
25
MySQL Database
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yes, money exists in discrete amounts -- but often the real world has particular rounding rules which must be used when a calculation results in a number which isn't one of those discrete amounts. These typically apply after you calculate a certain percentage of a money amount and tell you what to do with the fractional cents which result. Sometimes it's plain old half-up rounding and sometimes there are other rules. For example I've worked with a government-mandated rule which says that you truncate the result (in cents) to 1 decimal place, then round up everything which isn't an exact number of cents to the next higher cent.

So it's quite likely you will have to deal with this sort of thing in your application.
 
Winston Gutkowski
Bartender
Pie
Posts: 9472
50
Eclipse IDE Hibernate Ubuntu
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paul Clapham wrote:Yes, money exists in discrete amounts -- but often the real world has particular rounding rules which must be used when a calculation results in a number which isn't one of those discrete amounts.

Yes, but unless you understand the basic premise, you'll never get the rest.

For example I've worked with a government-mandated rule which says that you truncate the result (in cents) to 1 decimal place, then round up everything which isn't an exact number of cents to the next higher cent.

And has anybody challenged this? Sometimes I think they bring in these rules just to see if we're still awake. Either that, or it's jobs for the boys. What about penny shaving? I've actually come across a rule that would theoretically make it legal, but was the gov interested? Nah: these are them, until someone much higher up than you tells us otherwise.

Our taxes, my friend. And in most cases KISS works best.

Winston
 
Greg Ferguson
Ranch Hand
Posts: 34
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for all of your replies and suggestions. I decided to look more into the use of BigDecimal and realized that it wasn't as confusing as I first thought. I decided to use it in my project and the results are just what I hoped. Since I'm so far ahead in the class, I'm not going to post the working code for the hardest parts of this project. I have posted the code for the easier part though just to show one of the ways I'm using BigDecimal. The part I'm not posting involves breaking down the displayed amount into $1 bills, quarters, dimes, nickels, and pennies to get the least amount of change.

I would like some suggestions on whether or not I could have coded this with less lines or if you see anything redundant or useless; I appreciate your feedback. Thanks.

 
Paul Clapham
Sheriff
Pie
Posts: 20177
25
MySQL Database
  • 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
These three lines:



Read the API documentation for the BigDecimal constructor "BigDecimal(double)", and then rewrite them with code which works better and has one fewer line.
 
Greg Ferguson
Ranch Hand
Posts: 34
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for pointing that out Paul. I think I understand what you were saying. I rewrote the code and eliminated two lines from the previous code I posted, here's the revision.

I guess I didn't need to use double at all.

 
Winston Gutkowski
Bartender
Pie
Posts: 9472
50
Eclipse IDE Hibernate Ubuntu
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Buenny Fry wrote:I rewrote the code and eliminated two lines from the previous code I posted, here's the revision.

I guess I didn't need to use double at all.

Nope. And well done. A good lesson learned.

You may be interested in reading this page now. It's often just called 'Goldberg', because it's linked to so often .

Winston
 
Campbell Ritchie
Sheriff
Pie
Posts: 47244
52
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If you are using a Scanner, you don’t need the text, nor the valueOf method. You can use nextBigDecimal().

And well done sorting out the rest of the arithmetic
 
Greg Ferguson
Ranch Hand
Posts: 34
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Campbell Ritchie wrote:If you are using a Scanner, you don’t need the text, nor the valueOf method. You can use nextBigDecimal().

And well done sorting out the rest of the arithmetic


I realized that in my quest to see if I could write less code, and thanks.

I have really revised and added to the code. I was trying to find a way to catch input errors. For the most part, I get the desired results but the small issue I'm having is whenever input for the second Scanner isn't a number, the error is caught but instead of being able to reenter a value it just restarts. Is there a way I can loop back to the second Scanner instead of the beginning? I hope that makes sense.

 
Winston Gutkowski
Bartender
Pie
Posts: 9472
50
Eclipse IDE Hibernate Ubuntu
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Buenny Fry wrote:I have really revised and added to the code....

Buenny,

I've split up the very long lines in your code. Please re-read the UseCodeTags page, as it explains why not to use them.

Thanks.

Winston
 
Greg Ferguson
Ranch Hand
Posts: 34
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Winston Gutkowski wrote:
Buenny Fry wrote:I have really revised and added to the code....

Buenny,

I've split up the very long lines in your code. Please re-read the UseCodeTags page, as it explains why not to use them.

Thanks.

Winston


Thank you. I didn't mean to get carried away like that. I cut it way down to make my issue more relevant.
 
Winston Gutkowski
Bartender
Pie
Posts: 9472
50
Eclipse IDE Hibernate Ubuntu
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Buenny Fry wrote:Is there a way I can loop back to the second Scanner instead of the beginning? I hope that makes sense.

Very much so. Personally, I find Scanner quite tricky (and often counter-intuitive), despite the fact that it was supposed to "make things easier".

My "lazy man's" tip:
1. Use nextLine() to get the user's input, as this requires them to hit the ENTER key.
2. Once you have the String (the input line), use your 2nd Scanner (see new Scanner(String)) to validate the input (or alternatively, new BigInteger(String), inside a try...catch block).
NOTE: You may want to trim() the string before you parse it.

The nice thing about this approach is that it lends itself to most forms of streamed input, including passing the input in via a text file.

Also: try to avoid things like while(true) if you can (which is essentially what your outer loop is). One possibility is:
HIH

Winston
 
Greg Ferguson
Ranch Hand
Posts: 34
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Winston Gutkowski wrote:

Also: try to avoid things like while(true) if you can (which is essentially what your outer loop is). One possibility is:
HIH

Winston


Thanks for the suggestions. I was able to make it work, but now I don't know how to terminate the loop since the use of "break" is discouraged. How can I make getAmtTend.hasNextLine false?
 
Winston Gutkowski
Bartender
Pie
Posts: 9472
50
Eclipse IDE Hibernate Ubuntu
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Buenny Fry wrote:but now I don't know how to terminate the loop since the use of "break" is discouraged.

Who said that? Send 'em here and I'll shoot 'em for you.

How can I make getAmtTend.hasNextLine false?

Well, if you've already got a line and you're using:
getAmtTend = new Scanner(line);
as I suggested, you should be able to get the value with:
BigInteger amtTend = getAmtTend.nextBigInteger();
Just be aware that it can throw an Exception if the value entered is invalid (or you can use hasNextBigInteger()).

And BTW, it is true that you can avoid a break by adding extra conditions to the loop; but it's often more bother than it's worth.

You may also want to consider a separate loop for each value to enter.

Winston "Shoot first and ask questions later"
 
Junilu Lacar
Bartender
Pie
Posts: 6529
21
Java Linux Mac Scala Spring
  • 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Making your code more composed will help you work out the logic better.

Once you have the overall solution story "told" like this, it's easier to wrap your head around the solution for the smaller problems.

Edit: the above code can be made even less wordy if you can establish that you're dealing with amounts in general:


With the surrounding code providing enough context, you can drop the "amount" prefix on variables to remove redundancy, in line with the DRY principle (Don't Repeat Yourself), which I also take to the conceptual level.

 
fred rosenberger
lowercase baba
Bartender
Pie
Posts: 12017
24
Chrome Java Linux
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Paul Clapham wrote:Yes, money exists in discrete amounts -- but often the real world has particular rounding rules which must be used when a calculation results in a number which isn't one of those discrete amounts.

I would argue that no matter what the rules for 'figuring out the amount', you would want to store it as an integer type.

But that is just my opinion...
 
Paul Clapham
Sheriff
Pie
Posts: 20177
25
MySQL Database
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
fred rosenberger wrote:
Paul Clapham wrote:Yes, money exists in discrete amounts -- but often the real world has particular rounding rules which must be used when a calculation results in a number which isn't one of those discrete amounts.

I would argue that no matter what the rules for 'figuring out the amount', you would want to store it as an integer type.


Yes, I agree. I was just trying to point out that the intermediate calculations could involve non-integer values.
 
Consider Paul's rocket mass heater.
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic