0

I'm doing a very simple operation. Here's the code:

float expectedTotal = 32.97;
float firstPrice = 7.99;
expectedTotal -= firstPrice;

When I assert that, expectedTotal should be 24.98, but I end up with an error saying:

expected [24.980001] but found [24.98]

So the first question would be: Where is this 0.000001 comes from?

I have read in other stackoverflow that dealing with currencies is not ideal with float and I should use the DecimalFormat. I tried with the following code:

DecimalFormat df = new DecimalFormat("#.##");
String s = String.valueOf(expectedTotal);
String newString = df.format(s);
expectedTotal = Float.valueOf(newString);

But receive the error:

java.lang.IllegalArgumentException: Cannot format given Object as a Number

I also tried with a parse:

DecimalFormat df = new DecimalFormat("#.##");
String s = df.format(expectedTotal);
        try {
            expectedTotal = (float) df.parse(s);
        } catch (ParseException e) {
            e.printStackTrace();
        }

Basically, all I want is expectedTotal as a float with only 2 decimals. Anyone can help me please ?

NicolasM
  • 77
  • 6
  • 4
    Does this answer your question? [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – Masterhaend Feb 24 '21 at 15:46
  • @Masterhaend: I don't see how that answers the formatting question, though. – Robert Harvey Feb 24 '21 at 15:47
  • Do you want to store it, or just print it? `System.out.printf("%.2f", myNumber)`. For what it's worth, you probably shouldn't be storing money as a `float`. – Robert Harvey Feb 24 '21 at 15:48
  • Gonna say that this is likely a duplicate of the floating point math issue. Floats have a specific amount of precision; "two decimals" is a convenience for your presentation. – Makoto Feb 24 '21 at 15:50
  • 3
    Use an `int` or `long`, and store pennies. You won't have these problems. – Robert Harvey Feb 24 '21 at 15:50
  • I don't want to print it no. I need this variable in an Assert later in my code. That's why I need it to be precise. – NicolasM Feb 24 '21 at 15:53
  • Pass the double value to `format`, not a string version of it. `String newString = df.format(expectedTotal );` – 001 Feb 24 '21 at 15:54
  • I can't use an int. I need the decimals behind the commas :/ – NicolasM Feb 24 '21 at 15:54
  • 1
    Java Use EEE standard for double so when you add 0.1+0.1+0.1 the result is 0.30000000000000004 ``` System.out.println((0.1+0.1+0.1)); 0.30000000000000004 ``` if you need more accuracy you should work with java.lang.BigDecimal – Abderrazzak Nejeoui Feb 24 '21 at 15:55
  • 1
    BigDecimal expectedTotal = new BigDecimal( 32.97); BigDecimal firstPrice = new BigDecimal( 7.99); expectedTotal.subtract(firstPrice); – Abderrazzak Nejeoui Feb 24 '21 at 16:00
  • 1
    To summarize the comments: (A) Floating point technology used in the `float`/`Float` & `double`/`Double` types [**trades away accuracy**](https://en.m.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems) for speed of execution. (B) Never use floating-point where accuracy matters. So, **never use floating-point for money**. Either use the [`BigDecimal`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/math/BigDecimal.html) class, or use integers representing a count of whole pennies, fractional pennies, or whatever granularity is appropriate in your situation. – Basil Bourque Feb 24 '21 at 16:51

0 Answers0