-1

What is the best way to convert Dollar which is a double value to cents which is an int value in Java. Currently I use the following approach:

Double cents = new Double(dollar*100);
int amount = cents.intValue();

How accurate is this approach? Is there any better way to do this.

Geo Thomas
  • 1,139
  • 3
  • 26
  • 59
  • `int amount = (int) (double*100)` ? – geisterfurz007 Oct 11 '17 at 07:44
  • 3
    You're better off not having a `double` value to start with. – khelwood Oct 11 '17 at 07:48
  • @khelwood, I cannot change the dayatypes now – Geo Thomas Oct 11 '17 at 07:48
  • 6
    [Why not use Double or Float to represent currency?](https://stackoverflow.com/questions/3730019/why-not-use-double-or-float-to-represent-currency) – AxelH Oct 11 '17 at 07:49
  • @khelwood oops my bad :) typo. Should have been dollar instead of double there – geisterfurz007 Oct 11 '17 at 07:50
  • 1
    Well given that you might already have some imprecision, I suggest `int cents = (int) Math.round(100*dollars);` – khelwood Oct 11 '17 at 07:50
  • At least, round the double into a BigDecimal, the precision will be enough to have a correct 2decimal value. Then stick with the BigDecimal – AxelH Oct 11 '17 at 07:50
  • @khelwood I was part way through writing an answer with the same suggestion. Do you want to answer, or should I? – Patricia Shanahan Oct 11 '17 at 07:53
  • @PatriciaShanahan Thanks for asking. I'll write one. – khelwood Oct 11 '17 at 07:55
  • @AxelH You may be right. I don't understand your question. – khelwood Oct 11 '17 at 07:56
  • @AxelH There are ways of getting quite large rounding error, but it would take a perverse program to get more than half a cent of error on a reasonable sum of money. – Patricia Shanahan Oct 11 '17 at 08:02
  • @AxelH Anything that rounds down will get it wrong for even a tiny error, provided the error makes the result of the multiplication less than the real number result. Try the code in the question with `double dollar = 0.29;` immediately above it. – Patricia Shanahan Oct 11 '17 at 12:15
  • @PatriciaShanahan I never mention a `FLOOR` rounding. I mention BigDecimal to do the rounding, so one of `RoundingMode.HALF_*` rounding and a precision of 2. (I didn't though I had to precise...) – AxelH Oct 11 '17 at 12:26
  • @AxelH Yes, you can do the equivalent of the rounded solution using BigDecimal, if you convert the double using a MathContext that specifies the scale and rounding mode. It is much less direct than using Math.round, so I don't see the point, but it would work. – Patricia Shanahan Oct 11 '17 at 12:35

3 Answers3

9

Since you've put your value in a double, you have already introduced some imprecision: the number you have stored might not have exactly the value you intended to store. To cope with this, I suggest rounding it to the nearest cent. You can do this with Math.round:

int cents = (int) Math.round(100*dollars);
khelwood
  • 55,782
  • 14
  • 81
  • 108
0

As with most everything, "it depends." It depends on your exact situation and the problem space your program is solving. Your method of doubles and floats for your contrived case looks just fine. However, in the case of money, many people and libraries opt to use integer math only. This nominally minimizes the rounding errors in cases where high precision and high accuracy are paramount. Evaluate for yourself and for your use case what works.

Meanwhile, applying that thought process to your case, you might just use cents and convert only for presentation. Or, better yet, encapsulate the logic in a Currency class and perhaps USD class:

int amountInCents = ....
int amountInDollars = round(amountInCents / 100.0);

Note the use of the explicit decimal to tell the compiler to avoid integer division. The astute will accordingly see the hidden floating point math in this code.

hunteke
  • 3,648
  • 1
  • 7
  • 17
0

This is in support of the answer recommending rounding. This program compares the results of rounding and the truncating code in the question for a series of values. It uses BigDecimal arithmetic to generate the values, avoiding cumulative rounding error in the loop. If the results of rounding and truncation are different it prints the numbers.

import java.math.BigDecimal;

public class Test {
  public static void main(String[] args) {
    BigDecimal rawDollar = BigDecimal.ZERO;
    BigDecimal increment = new BigDecimal("0.01");
    for (int i = 0; i < 300; i++) {
      rawDollar = rawDollar.add(increment);
      double dollar = rawDollar.doubleValue();
      Double cents = new Double(dollar * 100);
      int amount = cents.intValue();
      int roundedAmount = (int) Math.round(dollar * 100);
      if (amount != roundedAmount) {
        System.out.println("dollar = " + dollar + " amount = " + amount
            + " rounded = " + roundedAmount);
      }
    }
  }
}

Here is the output. In each printed case, the rounded amount is correct and the truncated amount is one cent smaller than it should be.

dollar = 0.29 amount = 28 rounded = 29
dollar = 0.57 amount = 56 rounded = 57
dollar = 0.58 amount = 57 rounded = 58
dollar = 1.13 amount = 112 rounded = 113
dollar = 1.14 amount = 113 rounded = 114
dollar = 1.15 amount = 114 rounded = 115
dollar = 1.16 amount = 115 rounded = 116
dollar = 2.01 amount = 200 rounded = 201
dollar = 2.03 amount = 202 rounded = 203
dollar = 2.05 amount = 204 rounded = 205
dollar = 2.07 amount = 206 rounded = 207
dollar = 2.26 amount = 225 rounded = 226
dollar = 2.28 amount = 227 rounded = 228
dollar = 2.3 amount = 229 rounded = 230
dollar = 2.32 amount = 231 rounded = 232
dollar = 2.51 amount = 250 rounded = 251
dollar = 2.53 amount = 252 rounded = 253
dollar = 2.55 amount = 254 rounded = 255
Patricia Shanahan
  • 25,849
  • 4
  • 38
  • 75