0

See this below simple code:

public static void main(String[] args) {
    Long value = 91000L;
    System.out.println(value * 0.1);
    System.out.println(value * 0.2);
    System.out.println(value * 0.3);
    System.out.println(value * 0.4);
    System.out.println(value * 0.5);
    System.out.println(value * 0.6);
    System.out.println(value * 0.7);
    System.out.println(value * 0.8);
    System.out.println(value * 0.9);
}

the result is this:

9100.0
18200.0
27300.0
36400.0
45500.0
54600.0
63699.99999999999 //incorrect!
72800.0
81900.0
Rasool Ghafari
  • 4,128
  • 7
  • 44
  • 71

1 Answers1

3

This is a correct result because working with double is not precise as working with integer types.

This is why in case you compare two double numbers, you have to do smth. like this:

public static boolean isEqual(double one, double two) {
    return one >= two - 1E6 && one <= two + 1E6;
}

P.S. 4.2.3. Floating-Point Types, Formats, and Values

In case you want to print correct value, you have to use BigDecimal:

BigDecimal val = BigDecimal.valueOf(91000);
BigDecimal res = val.multiply(BigDecimal.valueOf(0.7));
System.out.println(res); // 63000.0

In some cases, you could increase precision:

long value = 91000L;
System.out.println(value * 0.7);    // 63699.99999999999
System.out.println((value * 7) / 10);   // 63700
Oleg Cherednik
  • 17,377
  • 4
  • 21
  • 35
  • could you explain why 63699.99999999999 is equal to 63700 in double? – Rasool Ghafari May 31 '19 at 07:21
  • It is a matter of rounding. The numbers 0.1, 0.2, ... do not have a precise representation when expressed a a sum a powers of two (only 0.5=2^-1 has). When multiplied by anything the result will be imprecise. Then it is rounded. Depending on it this may lead to the expected result or not. In the same way as 3/3=1, while 3*(1/3)=3*0.333...333 will be different of 1 in decimal. – Alain Merigot May 31 '19 at 07:52
  • 1
    Please do not recommend that people compare floating-point numbers with a tolerance. [There is no general solution for comparing floating-point numbers for equality.](https://stackoverflow.com/a/21261885/298225) Using a tolerance decreases false negatives (reports that numbers are not equal when the ideal results of real-number mathematics would be equal) at the expense of increasing false positives (reports that numbers are equal that are in fact not equal). That is okay in some applications but will break some applications. It should not be recommended for general use. – Eric Postpischil May 31 '19 at 11:00
  • 1
    Also “working with double is not precise as working with integer types” is not a correct statement. At modest magnitudes, `double` is of course more **precise** than integer types because it has fraction bits, and integer does not. For example, `7/3` has a 14% error in integer arithmetic but the error in `double` arithmetic is tiny. – Eric Postpischil May 31 '19 at 11:04