float -> double

W

wx

float f = 9.876543;
double d = f;
System.out.println(f + ", " + d);
---->
9.876543, 9.876543045043945

I can do:

double d = Double.parseDouble(Float.toString(f));

to get it to print the same thing:

9.876543, 9.876543

Is there a better way to cut the digits then going through string
representation? I don't want to lose any digits in the process.
 
J

Joshua Cranmer

wx said:
Is there a better way to cut the digits then going through string
representation? I don't want to lose any digits in the process.

When you cut the digits, you're losing digits. A direct float-to-double
does not change the value.

Here's what's happening. Let us take a float with the hexadecimal
representation 0x3f800001 (the smallest float greater than one). In
decimal, that will be 1 + 2^-23. Logically speaking, this number will
have an approximation error of 2^-23: it represents any number in the
range (1 + 2^-24, 1 + 3 * 2^-24].

When converting to double, we get another 29 bits of precision, which
means we can theoretically convert this number to any one of 536,870,912
possible representable numbers in the range. Which number should we
choose? The most logical number is 1 + 2^-23--the same number we put in,
just with another 29 bits of precision--so that it should now be
represented as 1 + 2^-23 ± 2^-53.

That number is the same (modulo precision) as your original float.

Here's the catch. 1 + 2^-23 is exactly 1.00000011920928955078125.
The low end of our range is exactly 1.000000059604644775390625.
The upper end of our range is exactly 1.000000178813934326171875.

The exact value could be printed if you really wanted to, but there's no
real point since the implicit error in the number dwarfs most of the
latter digits. It's like saying I'm 72.166865346776554356456678 inches
tall: it misleads you as to the precision of the answer (72 inches is
the precise way of formatting).

Similarly, a float has a 23-bit mantissa, so its decimal representation
is correct to a little more than 7 significant digits, 1.0000001 in this
case (the low end rounds up). So Java will print 1.0000001, the number
with the correct precision.

When I convert to a double, I get 29 more bits of precision, so the
number becomes accurate to a little less than 16 significant digits.
Java outputs accordingly: 1.0000001192092896.

When you did the string conversion, Java does the most precise possible
representation of the number, which is now in decimal. 1/10 is a
repeating decimal in binary, so converting the approximate value of 1.1
to binary, you get:

Float precision [*]
+-----------------------+
1.0011001100110011001100110011001100110011001100110011....
+----------------------------------------------------+
Double precision

What you just did was make an assumption about the original number, and
in a bad way. Imagine if the conversion to decimal caused a round
up--you've just now invalidated a few of your precious low-order bits.
Indeed, the rounding makes the conversion slightly lossy: if the
original number was ..86.., where the output truncates to ..9, it will
be treated as ..900000000 instead of the "correct" ..86...

In short: float-to-double is always exact conversion.
float-to-double-via-String will cause imprecision in later digits. Note
that you've been comparing equality based on the not-fully-accurate
String representation.

[*] Pedantic: it's going to be ...10 because of rounding.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,431
Messages
2,571,679
Members
48,796
Latest member
Greg L.

Latest Threads

Top