5
public class SimplePrint {

public static void main(String[] args) {
    long i = System.currentTimeMillis();
    System.out.println(i);
    float h = 0.0f;
    i -= h;
    System.out.println(i);
  }
}

The output is:

1477904636902

1477904695296

but when i changed the data type of variable of h

public class SimplePrint {

public static void main(String[] args) {
    long i = System.currentTimeMillis();
    System.out.println(i);
    double h = 0.0f;
    i -= h;
    System.out.println(i);
  }
}

the output is changed:

1477904677513

1477904677513

why is this ???

Mohammod Hossain
  • 4,134
  • 2
  • 26
  • 37
wang ming
  • 199
  • 2
  • 9
  • Rounding error maybe. Float is not precise enough to handle number that large. โ€“ Niyoko Oct 31 '16 at 09:09
  • 3
    `i -= h;` will be expanded to `i = i - h;` and the calculation is done in float, then converted back to long and will lose it's precission. โ€“ Niyoko Oct 31 '16 at 09:10
  • @NiyokoYuliawan Hint: just one, two more sentences, and you would have had a nice answer to upvote. Before anybody else ... so, just in case reputation matters to you: you already had 80% of an answer ready ... and now it is too late, as I dup-closed the question ... โ€“ GhostCat Oct 31 '16 at 09:17

2 Answers2

5

As is documented in JLS Sec 15.26.2, the compound assignment operator E1 op= E2 is equivalent to

E1 = (T) ((E1) op (E2))

where T is the type of E1.

So, what you're doing in the first case is:

i = (long) (i - 0.0f)

In order to evaluate the -, i has to be cast to a float, as described in JLS Sec 15.18.2:

Binary numeric promotion is performed on the operands (ยง5.6.2).

and 5.6.2:

Otherwise, if either operand is of type float, the other is converted to float.

The problem is that the value of i cannot be exactly represented as a float: because float only has 24 bits of significand (see here), only values up to around 2^24 (=16777216) can be represented exactly; but the current millis time (on my machine, at least), is around 1477905410000, which is way bigger.

So, you lose precision in converting to float, and that precision can't be recovered when casting back to long.

Community
  • 1
  • 1
Andy Turner
  • 137,514
  • 11
  • 162
  • 243
4

Your code is basically:

i = (long) (float) i;

or

i = (long) (double) i;

Now, in Java a float has 23 bits of precision, whilst a double has 52. 1477904677513 has 40 bits in it - 10101100000011001111110111011101010001001, so when converting to a float you lose the bottom 17 bits, so you see the values change.

Ken Y-N
  • 14,644
  • 21
  • 71
  • 114