9

I was referring this Oracle documentation. While trying to execute the following,

 public static void main(String args[]){

    float f = 1.1f;
    double df = 1.1f;

    System.out.println("f=" + f);
    System.out.println("df=" + df);

    f = 1.5f;
    df = 1.5f;
    System.out.println("f=" + f);
    System.out.println("df=" + df);
 }

Output is

f  = 1.1
df = 1.100000023841858
f  = 1.5
df = 1.5

Why the second line of output is showing an approximate value. But not for fourth line. How the value is getting calculated?

Abimaran Kugathasan
  • 31,165
  • 11
  • 75
  • 105
Nidheesh
  • 4,390
  • 29
  • 87
  • 150
  • BTW `1.1f` is a `float` literal, assigning it to double can be misleading. – Eel Lee Feb 19 '14 at 09:23
  • The first one just does not show you that it has the same approximate value http://floating-point-gui.de/ – zapl Feb 19 '14 at 09:23
  • 2
    `df` is this `1.500000000000000` actually, zeros are skipped – mangusta Feb 19 '14 at 09:23
  • for more info about floating point representation, refer to ieee 754 standard – mangusta Feb 19 '14 at 09:27
  • @mangusta: Thanks for ieee 754 hint. http://babbage.cs.qc.cuny.edu/IEEE-754/ – Nidheesh Feb 19 '14 at 10:03
  • 1
    Your question is really about **printing** a single-precision value as a double-precision value. In a nutshell, Java prints just enough digits in order to determine the single- or double-precision value exactly. When you print `1.1f` as a `double`, the type has more precision so more digits are necessary to make it unambiguous which `double` exactly is meant. See http://stackoverflow.com/questions/916081/convert-float-to-double-without-losing-precision – Pascal Cuoq Feb 19 '14 at 10:35

3 Answers3

4

The difference is that 1.5 can be represented exactly in double - whereas 1.1 can't be represented exactly.

It's because of periodical digits, any (irreducible) fraction where the denominator has a prime factor that does not occur in the base requires an infinite number of digits that repeat periodically after a certain point. For example, in decimal 1/4, 3/5 and 8/20 are finite, because 2 and 5 are the prime factors of 10. But 1/3 is not finite, nor is 2/3 or 1/7 or 5/6, because 3 and 7 are not factors of 10. Fractions with a prime factor of 5 in the denominator can be finite in base 10, but not in base 2 - the biggest source of confusion for most novice users of floating-point numbers.

Squeezing infinitely many real numbers into a finite number of bits requires an approximate representation. Although there are infinitely many integers, in most programs the result of integer computations can be stored in 32 bits. In contrast, given any fixed number of bits, most calculations with real numbers will produce quantities that cannot be exactly represented using that many bits. Therefore the result of a floating-point calculation must often be rounded in order to fit back into its finite representation. This rounding error is the characteristic feature of floating-point computation.

Check here for more details

Abimaran Kugathasan
  • 31,165
  • 11
  • 75
  • 105
  • How that approximate value is calculated? – Nidheesh Feb 19 '14 at 09:25
  • But he assigns 1.1f (not 1.1) both times. Should it not be the same constant? – starmole Feb 19 '14 at 09:29
  • @starmole assigning `1.1f` to a `double` results in a less accurate than possible number which is, when printed as double precision number, so inaccurate that it prints the 000023.. part whereas printing it as `float` directly skips printing that inaccuracy because it knows that there is no more value in printing numbers beyond some point. If you were to assign `1.1` as double you would be closer to 1.1 by magnitudes because there are many more bits you could use. That would print as "1.1" then. – zapl Feb 19 '14 at 10:02
  • 3
    @starmole: The Java default for printing floating-point is to print just enough digits to uniquely identify the value in its type. In `float`, “1.1” is enough because `1.1f` (exactly 1.10000002384185791015625) is closer to 1.1 than any other `float` is. In `double`, “1.1” is not enough, because the `double` 1.100000000000000088817841970012523233890533447265625 is closer to 1.1 than 1.10000002384185791015625 is, so you need more digits to get closer to the value of 1.10000002384185791015625. – Eric Postpischil Feb 19 '14 at 14:48
3

Example

Think about binary, and more importantly, binary when dealing with a decimal place.

4    2    1  .  1/2    1/4    1/8
0    0    1  .  1      0      0

So, as you can see, the computer can represent this without a problem. Now let's look at 1.1.

4    2   1   .  1/2    1/4    1/8    1/16
0    0   1   .  0      0      0      1

At the moment, we have 1.0625. As you can imagine, it's somewhat difficult to get 0.0475 exactly, but we can keep trying for sake of example:

4    2   1   .  1/2    1/4    1/8    1/16    1/32     1/64     1/128
0    0   1   .  0      0      0      1       1        0        0

Now we're up to 1.8, so let's keep going..

4    2   1   .  1/2    1/4    1/8    1/16    1/32     1/64     1/128
0    0   1   .  0      0      0      1       1        1        0

And we've got to 0.915625..

4    2   1   .  1/2    1/4    1/8    1/16    1/32     1/64     1/128
0    0   1   .  0      0      0      1       1        1        1

and we're at 0.9234375.

Explanation

I'm sure you can see where I'm going with this. There is always going to be an error between the number you want to represent, and the number that binary can represent. Sometimes, you get lucky, like 1.5, and binary has no problem representing that. Other times, you have an issue, like 1.1, and binary just gets as close as possible.

christopher
  • 26,815
  • 5
  • 55
  • 89
1

Yeah, as we know, the representation of a number in double is more accurate than that of the same one in float. And a float is represented in 32 bits while a double is in 64 bits. So, when a float is assigned to a double, the number is expanded from 32 bits to 64 bits. Then the inaccurate number is represented in an accurate way. So, do you understand this a bit more?