Java Forum / First Aid / January 2006
sorry .09 instead of .08
joshdalrymple2000@yahoo.com - 29 Jan 2006 22:29 GMT double totalCost = 3.91, amountPaid = 4.00; int totalChange;
totalChange = (int)((amountPaid - totalCost) * 100); System.out.println(totalChange);
it keeps saying the answer is 8... can any one help?
James Westby - 29 Jan 2006 22:46 GMT > double totalCost = 3.91, amountPaid = 4.00; > int totalChange; [quoted text clipped - 3 lines] > > it keeps saying the answer is 8... can any one help? Try looking at the output of this instead
double totalCost = 3.91, amountPaid = 4.00; double totalChange;
totalChange = ((amountPaid - totalCost) * 100); System.out.println(totalChange);
You'll see it isn't 9, and the cast to int truncates it to 8, as you were seeing originally.
The problem is that you can't use floating point arithmetic (doubles) to do precise arithmetic. If possible then you should try using fixed point arithmetic. e.g.
int totalCost = 391, amountPaid = 400; int totalChange;
totalChange = amountPaid - totalCost; System.out.println(totalChange);
James
Thomas Hawtin - 29 Jan 2006 23:00 GMT > The problem is that you can't use floating point arithmetic (doubles) to > do precise arithmetic. If possible then you should try using fixed point > arithmetic. e.g. It's probably better to use BigDecimal in most situations.
Tom Hawtin
 Signature Unemployed English Java programmer http://jroller.com/page/tackline/
zero - 29 Jan 2006 23:20 GMT >> The problem is that you can't use floating point arithmetic (doubles) >> to do precise arithmetic. If possible then you should try using fixed [quoted text clipped - 3 lines] > > Tom Hawtin BigDecimal will be slower though. If the values are all currency values, with only 2 numbers after the decimal point, ints are a good choice.
Tony Morris - 29 Jan 2006 23:39 GMT > >> The problem is that you can't use floating point arithmetic (doubles) > >> to do precise arithmetic. If possible then you should try using fixed [quoted text clipped - 6 lines] > BigDecimal will be slower though. If the values are all currency values, > with only 2 numbers after the decimal point, ints are a good choice. Are you saying that billionaires don't exist? My dream has been shattered!! Use a long - 9223 trillion dollars ought to be enough for anybody, right Bill?
 Signature Tony Morris http://tmorris.net/
zero - 30 Jan 2006 19:18 GMT >> BigDecimal will be slower though. If the values are all currency >> values, with only 2 numbers after the decimal point, ints are a good [quoted text clipped - 3 lines] > shattered!! Use a long - 9223 trillion dollars ought to be enough for > anybody, right Bill? Lol yes I was going to put that in my message - beware of over/underflow, and use long if you need larger amounts - but I left it out 'cause I was too lazy and wanted to keep the message short
Thomas Hawtin - 30 Jan 2006 00:09 GMT > BigDecimal will be slower though. If the values are all currency values, > with only 2 numbers after the decimal point, ints are a good choice. They are slower. However, is it going to make your program noticeably slower. Almost certainly not. Better to keep it safe than prematurely optimise.
Using ints is full of traps. No good for a billionaire companies, although longs should do for storage. Operations such as multiplication become tricky. Without treating it as a type in its own right, you can easily get into trouble.
Tom Hawtin
 Signature Unemployed English Java programmer http://jroller.com/page/tackline/
zero - 30 Jan 2006 19:22 GMT >> BigDecimal will be slower though. If the values are all currency >> values, with only 2 numbers after the decimal point, ints are a good [quoted text clipped - 10 lines] > > Tom Hawtin BigDecimal has its own problems, beside the speed. If you initialize a BigDecimal with a double constant, you're in the same boat as using a normal double when it comes to rounding errors.
I would suggest int or long for financial calculations, and BigDecimal if you're dealing with more numbers after the decimal point.
Thomas Hawtin - 30 Jan 2006 20:12 GMT > BigDecimal has its own problems, beside the speed. If you initialize a > BigDecimal with a double constant, you're in the same boat as using a > normal double when it comes to rounding errors. If you initialise an int or long with a double you'll get the same rounding errors (plus overflow errors for added fun). So, don't use doubles for financial calculations.
Tom Hawtin
 Signature Unemployed English Java programmer http://jroller.com/page/tackline/
zero - 30 Jan 2006 20:17 GMT Thomas Hawtin <usenet@tackline.plus.com> wrote in news:43de71ad$0$1458 $ed2619ec@ptn-nntp-reader01.plus.net:
> So, don't use > doubles for financial calculations. that's really the bottom line isn't it :-) Use whatever works for you, as long as it isn't double (or worse, float).
Ernie Wright - 30 Jan 2006 23:31 GMT >> So, don't use doubles for financial calculations. > > that's really the bottom line isn't it :-) Use whatever works for > you, as long as it isn't double (or worse, float). I'd strongly disagree. The problem is failure to understand roundoff, not any particular number representation. You'll eventually get bitten if you decide that avoiding floating-point primitives is all you need to do. Conversely, if you want to do anything more than adding and subtracting, you'll find the floating-point primitives very hard to avoid.
- Ernie http://home.comcast.net/~erniew
Fabien Bergeret - 30 Jan 2006 10:36 GMT > double totalCost = 3.91, amountPaid = 4.00; > int totalChange; [quoted text clipped - 3 lines] > > it keeps saying the answer is 8... can any one help? Never ever perform money calculation using floating point. First solution : use BigDecimal and BigInteger (which are slower, as mentioned before). Second solution (used in all our banking applications) : specify the amounts in "smallest currency unit" (cents for $, pence for pounds), and associate a "small unit number" with each currency (if you need to manage several currencies), which specifies the number of small units needed for GUI. For instance, for $, calculations are made in cents, and display is done with amount/100 $ and amount%100 cents (small unit number = 2)
Thomas Hawtin - 30 Jan 2006 16:35 GMT > For instance, for $, calculations are made in cents, and display is done > with amount/100 $ and amount%100 cents (small unit number = 2) That's not going to work for negative quantities.
IIRC, various legal requirements for calculations will also require a couple more significant figures.
Tom Hawtin
 Signature Unemployed English Java programmer http://jroller.com/page/tackline/
Ernie Wright - 30 Jan 2006 19:18 GMT > double totalCost = 3.91, amountPaid = 4.00; > int totalChange; [quoted text clipped - 3 lines] > > it keeps saying the answer is 8... can any one help? As has been said, this is due to roundoff error.
If you want to know *why* roundoff error occurs, it helps to know how primitive floating-point numbers are stored internally. Skipping over the details, the numbers in your example are stored with the following bit patterns (shown in hex):
s exp mantissa 3.91 0 400 F47AE147AE148 4.0 0 401 0000000000000
Notice that 3.91 can't be represented exactly. The mantissa is a repeating fraction, with repeating part 47AE1 that's rounded up at the end to 48. The internal version of the number is slightly larger than 3.91.
There is no infallible way to deal with this error, since numbers must always be stored with a finite number of bits. How you deal with it depends on what you're trying to do.
Financial programs usually adhere to a set of conventions that ensure that a calculation is *fair*, in the sense that it's always done in the same way. But this isn't always the same as *accurate*. Credit card companies and gas stations will always round up, for example.
Storing money amounts in smaller units (e.g. cents or mils instead of dollars) hides the problem for addition and subtraction, but not for anything more complicated (compound interest or statistical analysis).
BigDecimal is overkill unless you need more than 15 decimal digits of precision. It's also extremely limited. There's no pow() method, for example, so no interest calculations. And the scaling and rounding of BigDecimals isn't really any easier or less error-prone than the correct use of primitive floating-point types.
- Ernie http://home.comcast.net/~erniew
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|