3

I am working on a project where we are calculating prices of items with 8 places of decimal points. But sometime calculation results are different.

I tried some samples but getting different calculation results:

    public static void main(String[] args) {
        double value1 =  0.999939f * 0.987792f;
        double value2 =  0.999939 * 0.987792;
        double value3 =  (double)0.999939f * 0.987792f;     
        System.out.println("value 1 : "+ value1);
        System.out.println("value 2: "+ value2);
        System.out.println("value 3 : "+ value3);
    }

Outputs are:

value 1 : 0.9877317547798157
value 2 : 0.9877317446880001
value 3 : 0.9877317839126931

These three are different results.

I am confused. Can anyone please clarify me what is happening here?
Thanks.

I went through some already answered, But I just want some ways where I can calculate with float and doubles only. otherwise I have to change many places. It will be painful.

Coding Enthusiast
  • 3,865
  • 1
  • 27
  • 50
Sonu Gupta
  • 347
  • 3
  • 16
  • 2
    don't use double or float type variables for money amount representation. You will get many issues related to rounding, etc. Use `BigDecimal` class instead. –  May 27 '15 at 18:21
  • Thanks @RafaelOsipov. I have some more doubts. Can we fix decimal point places? And will it affect the calculation and rounding? java provides any API which can be helpfull? – Sonu Gupta May 27 '15 at 18:25
  • @RealSkeptic this link is about why should we not use double or float to represent. Its really helpful, and next time I will not use float and doubles. But for now my question is "Can I do something with float and doubles which will not affect on results" – Sonu Gupta May 27 '15 at 18:47
  • @RafaelOsipov already answered that in his comment, and the link that I gave offers other possibilities, such as using `int` or `long` (`long` would be better in your case since you have so many places after the decimal). – RealSkeptic May 27 '15 at 18:49
  • [BigDecimal](https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html) with scale 8 is suitable for exact representation of decimal fractions with 8 digits after the decimal point. You can control the rounding mode, but one of the options is the same as for floating point. – Patricia Shanahan May 28 '15 at 01:51
  • I don't see how this is a duplicate of either of those (they might be related, but they don't answer this particular question). – Simon Byrne May 28 '15 at 08:35

2 Answers2

3

Because of how floats and decimals are represented, the casts could be causing different results.

For: double value1 = 0.999939f * 0.987792f you are multiplying two floats and then casting it to a double. The resulting float representation is the one being converted to a double.

For: double value2 = 0.999939 * 0.987792; you are multiply two doubles and saving it in a double. This is time there is no casting so the representation never changes (ie. no potential data loss from change in data representation).

For: double value3 = (double)0.999939f * 0.987792f; you are multiplying a double that is casted from a float, times a float. Because of how the Java math works, that second float is probably also being casted to a double, so now you are multiplying two doubles that were once floats causing a third set of representations.

Because float and doubles have different precisions each of these will get a different result. For more info about floating point arithmetic, see here.

Evan Frisch
  • 1,334
  • 5
  • 22
  • 40
  • Why do you say there is _no potential data loss_ when doubles are involved? That's simply not true. – Amit May 27 '15 at 18:52
  • @Amit You are correct, there is potential for a loss of data when the number is recorded in the representation as a Double and has a chance to lose data when multiplying and saving, but all within the definitions of how a double works. I meant there will be no data loss from a change of the representation. I will make an edit to say that. – Evan Frisch May 27 '15 at 18:59
1

When you write a number with the "f" character, it is taken as float, meaning it is encoded with 32bits, whereas without it, it is a double, encoded with 64bits.

The more bits, the more accurately you will represent decimal numbers. This does not make a difference for number with few decimals, but in your case it is significant.

In conclusion, use exclusively double variables in your code.

Eric Leibenguth
  • 4,167
  • 3
  • 24
  • 51
  • That's not accurate. The precision of floating point representation (single or double) is limited regardless of decimals. In fact a natural number can be inaccurate just as well. – Amit May 27 '15 at 18:50