2

Possible Duplicate:
Why not use Double or Float to represent currency?

I'm learning Java so please bear with me for such a simple question. When given a calculation to calculate interest i have this code inputted:

 public double calculateTotal(double rate, int n)
 {
     amount = amount * Math.pow((1+rate), (n/12));
     return amount;
 }

This returns the answers I'm looking for but keeps adding 0.000000000001 onto the end. How would i solve this? A friend advised something called number formatting but i couldn't find a solution.

Community
  • 1
  • 1
cbatothinkofname
  • 93
  • 1
  • 1
  • 3
  • 8
    If this is for monetary purpose, use `BigDecimal` instead. – Swapnil Jan 11 '13 at 17:34
  • 3
    See [here](http://stackoverflow.com/questions/3730019/why-not-use-double-or-float-to-represent-currency) why it isn't a good idea to use a double for currency. – Jonathan Jan 11 '13 at 17:34
  • 1
    `n/12` is a integer operation, so for `n = 1` it will be zero, and not `1/12`. Otherwise, `double` can never be 100% precise. You can use `DecimalFormat` to have a nice string representation of your number. – jlordo Jan 11 '13 at 17:34

2 Answers2

1

This problem is related to widely known floating point calculation issue.

One of the solutions could be use of import java.math.BigDecimal

EDIT

Java does not allow to override operators so the only way to add BigDecimals together is by using add method e.g. (assuming your amount is BigDecimal. Bear in mind that BigDecimal is immutable so whatever is returned from calculateTotal needs to be assigned back to ammount

// you assign result to amount outside calculateTotal
amount.add(new BigDecimal(Math.pow((1+rate), (n/12))));

or

// you assign sum to amount inside calculateTotal
amount = amount.add(new BigDecimal(Math.pow((1+rate), (n/12))));
Community
  • 1
  • 1
Alexandar
  • 916
  • 2
  • 9
  • 22
  • I imported java.math.BigDecimal. no change. so i changed a couple of the data types to BigDecimal and now the compilers complaining of bad operator types not allowing BigDecimals to be added together. D= – cbatothinkofname Jan 11 '13 at 18:12
  • @cbatothinkofname You should take a look at this question on SO. [Addition for BigDecimal](http://stackoverflow.com/questions/1846900/addition-for-bigdecimal) – Smit Jan 11 '13 at 18:35
  • Inputted the latest feedback and now it's giving me a totally different answer which is wrong and still giving me long decimals afterwards. – cbatothinkofname Jan 11 '13 at 19:09
  • ah, sorted that problem out... back to the correct answer. only still with long decimal place once again – cbatothinkofname Jan 11 '13 at 19:18
1

As it was mentioned before BigDecimal is good option if you need better precision with doubles.

There is nice way to do rounding with BigDecimals. Basically you have to specify scale of the BigDecimal instance. Take a look at this sample code:

BigDecimal decimalOne = new BigDecimal(0.1950);
BigDecimal decimalTwo = decimalOne.setScale(2, BigDecimal.ROUND_HALF_DOWN);
BigDecimal decimalThree = decimalOne.setScale(4, BigDecimal.ROUND_HALF_DOWN);

System.out.println("decimalOne: " + decimalOne);
System.out.println("decimalTwo: " + decimalTwo);
System.out.println("decimalThree: " + decimalThree);

Java 7 would print something like this:

decimalOne: 0.195000000000000006661338147750939242541790008544921875
decimalTwo: 0.20
decimalThree: 0.1950

Please note that BigDecimal instances are immutable and that's why you have to assign result of setScale to new instance (decimalOne will not be changed).


In many financial system doubles are not used to store currency information; long type with specific precision is used instead e.g. for precision 2, value 100 would be 1.00, 122 would be 1.22 etc. That approach simplifies and seeds up calculations but it is not good for all the systems. However for simplicity of that question I won't dive into that subject too much.

Tom
  • 26,212
  • 21
  • 100
  • 111