7

I write the following code in java and check the values stored in the variables. when I store 1.2 in a double variable 'y' it becomes 1.200000025443 something. Why it is not 1.200000000000 ?

public class DataTypes

{
    static public void main(String[] args)
    {
        float a=1;
        float b=1.2f;
        float c=12e-1f;
        float x=1.2f;
        double y=x;

        System.out.println("float a=1 shows a= "+a+"\nfloat b=1.2f shows b= "+b+"\nfloat c=12e-1f shows c= "+c+"\nfloat x=1.2f shows x= "+x+"\ndouble y=x shows y= "+y);
    }
}

You can see the output here:

float a=1 shows a= 1.0
float b=1.2f shows b= 1.2
float c=12e-1f shows c= 1.2
float x=1.2f shows x= 1.2
double y=x shows y= 1.2000000476837158
arshajii
  • 127,459
  • 24
  • 238
  • 287
Gaurish Gangwar
  • 395
  • 4
  • 14

2 Answers2

3

This is a question of formatting above anything else.

Take a look at the Float.toString documentation (Float.toString is what's called to produce the decimal representations you see for the floats, and Double.toString for the double):

How many digits must be printed for the fractional part of m or a? There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type float. That is, suppose that x is the exact mathematical value represented by the decimal representation produced by this method for a finite nonzero argument f. Then f must be the float value nearest to x; or, if two float values are equally close to x, then f must be one of them and the least significant bit of the significand of f must be 0.

(emphasis mine)

The situation is the same for Double.toString. But, you need more digits to "uniquely distinguish the argument value from adjacent values of type double" than you do for float (recall that double is 64-bits while float is 32), that's why you're seeing the extra digits for double and not for float.

Note that anything that can be represented by float can also be represented by double, so you're not actually losing any precision in the conversion.

Of course, not all numbers can be exactly representable by float or double, which is why you see those seemingly random extra digits in the decimal representation in the first place. See "What Every Computer Scientist Should Know About Floating-Point Arithmetic".

arshajii
  • 127,459
  • 24
  • 238
  • 287
  • Downvoter, kindly leave a comment. – arshajii Mar 08 '15 at 15:25
  • because this is not an issue of truncation, this is definitely a IEEE754 approximation! ok, removed the downvote because you're making a case for the float truncating the last bits of the double IEEE754 value. – zmo Mar 08 '15 at 15:27
  • @zmo The question is why the output for the `double` is different than the output for `float`. The original `float` is an approximation of `1.2`, yes, but that's not (as) relevant here. In any case I'll add it to my answer for completion. – arshajii Mar 08 '15 at 15:29
  • well, the in-memory representation of 1.2 is not round because of the power of 2 exponent. But the smaller mantissa of the float shadows that reality. It is very important to understand how data is represented in memory to not create errors in algorithms. – zmo Mar 08 '15 at 15:31
  • now you deserves a +1 because of your last update ;-) – zmo Mar 08 '15 at 15:35
1

The reason why there's such issue is because a computer works only in discrete mathematics, because the microprocessor can only represent internally full numbers, but no decimals. Because we cannot only work with such numbers, but also with decimals, to circumvent that, decades ago very smart engineers have invented the floating point representation, normalized as IEEE754.

The IEEE754 norm that defines how floats and doubles are interpreted in memory. Basically, unlike the int which represent an exact value, the floats and doubles are a calculation from:

floating point representation

  • sign
  • exponent
  • fraction

So the issue here is that when you're storing 1.2 as a double, you actually store a binary approximation to it:

00111111100110011001100110011010

which gives you the closest representation of 1.2 that can be stored using a binary fraction, but not exactly that fraction. In decimal fraction, 12*10^-1 gives an exact value, but as a binary fraction, it cannot give an exact value.

(cf http://www.h-schmidt.net/FloatConverter/IEEE754.html as I'm too lazy to do it myself)

when I store 1.2 in a double variable 'y' it becomes 1.200000025443 something

well actually in both the float and the double versions of y, the value actually is 1.2000000476837158, but because of the smaller mantissa of the float, the value represented is truncated before the approximation, making you believe it's an exact value, whereas in the memory it's not.

zmo
  • 24,463
  • 4
  • 54
  • 90