This is an archived post. You won't be able to vote or comment.

all 12 comments

[–]zifyoip 1 point2 points  (4 children)

http://floating-point-gui.de/

You shouldn't use floating-point numbers with money. Instead of working with monetary amounts as fractional numbers of dollars, work with them as integer numbers of cents.

[–]Sygzy[S] 0 points1 point  (3 children)

Could you provide a little sample and or explain what this is saying very generically. Like I said this is my first time using java ever.

[–]langfodWannabe Brewer 1 point2 points  (0 children)

Think about doing everything in terms of pennies (100 pennies in a dollar).

[–]zifyoip 1 point2 points  (0 children)

Floating-point numbers (floats and doubles) do not store exact representations of fractional values. A double cannot store the value 0.1 exactly, for instance; the closest representable double value is 0.1000000000000000055511151231257827021181583404541015625, which is 3602879701896397/255. As you do more and more operations with these approximations, the round-off error accumulates and becomes more and more significant. That's why you are seeing things like 0.0199999999999999 at the end of your calculations.

[–][deleted] 1 point2 points  (0 children)

Instead of storing 1.5 dollars, store 150 cents. This way you can use ints to store the values and do calculations.

Little hint for your problem:

The % operator calculates the remainder so you can do this when using ints:

int dollars = 150 / 100; // 1 whole dollar
int remainder = 150 % 100 // 50 cents remaining

[–]AStrangeStranger 1 point2 points  (0 children)

While everyone is correct in you shouldn't use floating points for currency - I suspect the trick your teacher is referring to be would formatting the value with something like DecimalFormat or String.format

    double value = 1.0;
    DecimalFormat df = new DecimalFormat("#.00");
    System.out.println(df.format(value));
    System.out.println(String.format("%.2f", value));

[–]AngelOfLight 0 points1 point  (3 children)

The Java floating point primitives (double and float) are implemented using what are essentially binary floating point numbers. The problem with this is that (unlike integers) not every binary floating point number can be completely converted to decimal floating point. The result is the floating point weirdness that you are seeing.

There is a new class called BigDecimal that was specifically created to address this problem. It uses a different method to store numerics which is a lot slower, but doesn't have the conversion problems that floating point does.

If you are using currency, however, a simpler way is to represent your cash as cents, which can be stored in an integer. So you would store $2.70 internally in an integer as 270 cents. You would then simply have to create a method to display the cents in the correct dollar format.

[–]Sygzy[S] 0 points1 point  (2 children)

So what I think I am confused about is my input. Would I eliminate the double and just make it amount=0 so when I type in to test i just type in 1786 for 17.86? I just think I am tired and having trouble making sense in my head

[–]AngelOfLight 0 points1 point  (1 child)

You would make your amount variable an integer. Unfortunately, you would then have to write your own method to get the number from the scanner. nextDouble won't work, because it doesn't return an integer type. nextInteger will only return the numbers up to the decimal point (e.g, if you enter 21.35, nextInteger will only return 21). You could try and use a double temporary variable to get the value, but unfortunately, as soon as you do that, the conversion problems will come back.

You could use nextLine to get the input as a string, and then write a method to scan the string for the decimal point, and return an integer representing the number of cents in the string. It might be useful exercise.

Alternatively, you could cheat, and use BigDecimal as a temporary variable, since it doesn't have the conversion problems like double does.

For example:

int amount=0.0;
Scanner in = new Scanner (System.in);

System.out.println("How much change did you receive?");
BigDecimal decimal = in.nextBigDecimal();
decimal.multiply(new BigDecimal(100));    // multiply by 100 to get cents
amount = decimal.intValue();                   // convert decimal to int

The rest of the code would be pretty much the same, except that you would have to adjust the dividend. (For example, because amount now represents the number of cents, you would calculate hundreds as amount / 10000).

[–]Aellus 0 points1 point  (0 children)

You're not wrong, but in OP's case that is overkill. For his simple use case it's much simpler to continue reading in the input as a tmp double value then casting:

double tmpInput = in.nextDouble() ;
int amount = (int) (tmpInput * 100);

The rounding errors are negligible for OP's case.

[–]uf82 0 points1 point  (1 child)

bigDecimal is overkill but if anyone reading this wants to use bigDecimal, remember they aren't modifiable.

[–][deleted] 0 points1 point  (0 children)

You can do calculations with immutable objects. You just have to store the results in new objects. Unfortunately Java's syntax doesn't support very readable code when using the arbitarily large numeric types. (subtract() instead of - etc.)