Take the 2-minute tour ×

I've been trying to find out the reason, but I couldn't. Can anybody help me?

Look at the following example.

    float f;

    f = 125.32f;
    System.out.println("value of f = " + f);
    double d = (double) 125.32f; 
    System.out.println("value of d = " + d);

This is the output:

value of f = 125.32

value of d = 125.31999969482422

share|improve this question
Can you provide the specific example(s) that you are seeing this behavior in? It would be better to show a SSCCE: sscce.org –  Shafik Yaghmour Jul 6 '13 at 16:30
Example please. –  Devolus Jul 6 '13 at 16:30
One word: precision. Technically ... the values aren't "changing" ;) –  Brian Roach Jul 6 '13 at 16:32
Afaik, that's impossible. Doubles have both more precision and more range, so you lose neither when casting in that direction. It may print differently, though. –  harold Jul 6 '13 at 16:32
add comment

7 Answers

  1. When you convert a float into a double, there is no loss of information. Every float can be represented exactly as a double.
  2. On the other hand, neither decimal representation printed by System.out.println is the exact value for the number. An exact decimal representation could require up to about 760 decimal digits. Instead, System.out.println prints exactly the number of decimal digits that allow to parse the decimal representation back into the original float or double. There are more doubles, so when printing one, System.out.println needs to print more digits before the representation becomes unambiguous.
share|improve this answer
There isn't really any double equivalent to the best float representation of 3.5E+38. Comparing such a value to the best float representation of any other value above 3.5E+38 will indicate the values are indistinguishable--not necessarily very informative, but correct. Converting that value to double, on the other hand, will cause it to erroneously compare greater than the best double representation of all values below 1.798E+308--an error of hundreds of orders of magnitude. –  supercat Sep 4 '13 at 8:02
@supercat This answer is about converting a float to a double. The “best float representation of 3.5E+38” is +inf and the float +inf converts to the double +inf without loss of precision (it's the same inf!). How you interpret that infinity is your problem, not the problem of the conversion. A floating-point value (here, +inf) represents one value only (here, infinity). You could have made the same argument with 1-ulp intervals around 1.0f and the double 1.0, and the argument would be similarly irrelevant. It is a float, i.e. a single value, that is converted to double. –  Pascal Cuoq Sep 4 '13 at 8:21
@supercat See “Some common misconceptions (2)” in lipforge.ens-lyon.fr/www/crlibm/documents/cern.pdf . De Dinerchin is only talking about finite floating-point values there but the same applies to inf. The floating-point value inf is not “a range of values comprising 3.5E+38”, it is a single value, infinity. The approximation in translating 3.5E38 to +inf has already happened before the conversion to double, and does not prevent the conversion to double from being exact. –  Pascal Cuoq Sep 4 '13 at 8:25
A floating-point value effectively encapsulates two concepts: what can be said about the computations that produced it, and what should be fed into computations going forward. Given an expression like float2=float1/0.625f, if float1 was 62.5f, then the value of float2 indicates that the arithmetic result of the last operation was between 13421772.5/134217728 and 13421773.5/134217728, and that future uses of float2 will use the exact value 13421773/134217728. If float1 was 3.4E38, the value of float2 will indicate that... –  supercat Sep 4 '13 at 15:10
...an arithmetic result exceeded 3.4028E38 by an unknown amount, and that future uses of float2 will regard it as infinite. If one wanted to know whether the arithmetic result of a computations that yielded float2 could be definitively regarded as larger than 0.11 or 1.7E+308, casting the second operand of each comparison to float would correctly report that they can't. Casting the float2 to double would suggest that they could. –  supercat Sep 4 '13 at 15:24
show 9 more comments

The value of a float does not change when converted to a double. There is a difference in the displayed numerals because more digits are required to distinguish a double value from its neighbors, which is required by the Java documentation. That is the documentation for toString, which is referred (through several links) from the documentation for println.

The exact value for 125.32f is 125.31999969482421875. The two neighboring float values are 125.3199920654296875 and 125.32000732421875. Observe that 125.32 is closer to 125.31999969482421875 than to either of the neighbors. Therefore, by displaying “125.32”, Java has displayed enough digits so that conversion back from the decimal numeral to float reproduces the value of the float passed to println.

The two neighboring double values of 125.31999969482421875 are 125.3199996948242045391452847979962825775146484375 and 125.3199996948242329608547152020037174224853515625. Observe that 125.32 is closer to the latter neighbor than to the original value. Therefore, printing “125.32” does not contain enough digits to distinguish the original value. Java must print more digits in order to ensure that a conversion from the displayed numeral back to double reproduces the value of the double passed to println.

share|improve this answer
in single-precision, the sequence of numbers exactly representable around that number are: 0x42faa3d6, 0x42faa3d7, 0x42faa3d8 (in hex notation, with one bit increments). Anything in-between gets rounded to the closest number. Same can be said for double-precision. btw correct me if I'm wrong but single-precision allows about 9 significant decimal digits precision, so all those extra digits you showed are dropped and ignored –  Amro Jul 7 '13 at 4:17
@Amro: Extra digits are not dropped or ignored. The arithmetic performed on floating-point objects behaves as if they have exactly the full values, include the values I showed. That is because they do have those full values; the IEEE 754 specification states that they have exactly those values and no others. They are not used by the computer as decimal approximations with a few digits. The computer calculates with them in binary, and they have exactly the values specified. –  Eric Postpischil Jul 7 '13 at 11:51
hmm I guess this detail always confused me, can you comment on this please: stackoverflow.com/questions/4227145/… ? –  Amro Jul 7 '13 at 15:42
@Amro: The IEEE 754 standard defines what values are represented by floating-point objects. The standard does not define any notion of significant decimal digits for a binary floating-point format. There simply is no basis for stating that an IEEE-754 binary floating-point object has some number of significant decimal digits. The object has exactly one value that is precisely specified, and it carries no information about significance. It is an exact value. The standard does permit implementations to limit the number of digits they produce when converting the value to a decimal numeral… –  Eric Postpischil Jul 8 '13 at 3:10
… This is a quality-of-implementation issue. In my view, an implementation that “gives up” after displaying some number of digits and produces zeroes instead of continuing the conversion is low quality. The floating-point object represents a specific number, and the conversion of the object to decimal ought to produce the exact value that is represented, if the user requested or permitted enough digits for that. (If the user requested fewer digits, then a correctly rounded result should be provided.) –  Eric Postpischil Jul 8 '13 at 3:12
show 15 more comments

The conversion from float to double is a widening conversion, as specified by the JLS. A widening conversion is defined as an injective mapping of a smaller set into its superset. Therefore the number being represented does not change after a conversion from float to double.

share|improve this answer
This answer is correct as far as it goes, but it only states that the value does not change when converted. This answer does not explain why a different numeral is displayed. –  Eric Postpischil Jul 7 '13 at 2:11
add comment

The 32bit IEEE-754 floating point number closest to 125.32 is in fact 125.31999969482421875. Pretty close, but not quite there (that's because 0.32 is repeating in binary).

When you cast that to a double, it's the value 125.31999969482421875 that will be made into a double (125.32 is nowhere to be found at this point, the information that it should really end in .32 is completely lost) and of course can be represented exactly by a double. When you print that double, the print routine thinks it has more significant digits than it really has (but of course it can't know that), so it prints to 125.31999969482422, which is the shortest decimal that rounds to that exact double (and of all decimals of that length, it is the closest).

share|improve this answer
So, I made a mistake? What was it? –  harold Jul 7 '13 at 7:28
add comment

The issue of the precision of floating-point numbers is really language-agnostic, so I'll be using MATLAB in my explanation.

The reason you see a difference is that certain numbers are not exactly representable in fixed number of bits. Take 0.1 for example:

>> format hex

>> double(0.1)
ans =

>> double(single(0.1))
ans =

So the error in the approximation of 0.1 in single-precision gets bigger when you cast it as double-precision floating-point number. The result is different from its approximation if you started directly in double-precision.

>> double(single(0.1)) - double(0.1)
ans =
share|improve this answer
these approximations can creep up on you in unexpected ways. For example 0.1*3 == 0.3 evaluates to false. If you need extra accuracy, use arbitrary-precision libraries –  Amro Jul 6 '13 at 17:26
Really cogent explanation. Thanks. –  Curt Jul 6 '13 at 18:13
@Curt: you can find a much better explanation here: mathworks.com/company/newsletters/news_notes/pdf/… (by Cleve Moler, inventor of MATLAB). This page also has some nice examples –  Amro Jul 6 '13 at 18:31
This answer does not explain why printing a float shows a different numeral than printing a double converted from the same value (and which in fact has the same value, because conversion from float to double does not change the value). –  Eric Postpischil Jul 7 '13 at 2:10
you are correct, I did not address how println chooses the number of decimal digits to display. The point I was making is that the mathematical value 123.32 cannot be exactly represented in single nor double precision, and that the approximation stored in float when upcasted to double type will not be the same as if the literal number was entered as double to begin with. So everybody is absolutely right in saying that float->double conversion does not loose any precision whatsoever, but the approximation we get for non-exactly-representable numbers are worse if you do the upcasting.. –  Amro Jul 7 '13 at 3:51
show 3 more comments

Both are what Microsoft refers to as "approximate number data types."

There's a reason. A float has a precision of 7 digits, and a double 15. But I have seen it happen many times that 8.0 - 1.0 - 6.999999999. This is because they are not guaranteed to represent a decimal number fraction exactly.

If you need absolute, invariable precision, go with a decimal, or integral type.

share|improve this answer
"approximate" is quite an awkward way to describe what an IEEE floating point number is, since it exactly represents a very precisely defined set of numbers. –  Marko Topolnik Jul 6 '13 at 16:38
This doesn't address the question at all. –  Zong Zheng Li Jul 6 '13 at 16:39
"Approximate-number data type" is precisely what Microsoft calls float and real: msdn.microsoft.com/en-us/library/ms173773.aspx –  Curt Jul 6 '13 at 16:43
@Curt If one starts calling a floating-point type “real”, then the first thing one needs to mention is that it is approximate: as a datatype to store real numbers in, it certainly is. I don't think that documentation from Microsoft about floating-point types in SQL should be considered appropriate reference material for discussion of floating-point either in itself or in Java. –  Pascal Cuoq Jul 7 '13 at 12:06
@MarkoTopolnik: From the standpoint of the code which performs low-level computations, IEEE floats are precisely-defined types. From the standpoint of consumer code, however, if a program reads two float values (say x=1.0 and y=10.0) and computes float z=x/y;, it is far more likely that the programmer regards z as holding an imperfect representation of value of the entered fraction, than a precise representation of the fraction 13421773/134217728. –  supercat Sep 4 '13 at 7:54
show 1 more comment

As already explained, all floats can be exactly represented as a double and the reason for your issue is that System.out.println performs some rounding when displaying the value of a float or double but the rounding methodology is not the same in both cases.

To see the exact value of the float, you can use a BigDecimal:

float f = 125.32f;
System.out.println("value of f = " + new BigDecimal(f));
double d = (double) 125.32f;
System.out.println("value of d = " + new BigDecimal(d));

which outputs:

value of f = 125.31999969482421875
value of d = 125.31999969482421875
share|improve this answer
add comment

Your Answer


