Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert float to double without losing precision

I have a primitive float and I need as a primitive double. Simply casting the float to double gives me weird extra precision. For example:

float temp = 14009.35F; System.out.println(Float.toString(temp)); // Prints 14009.35 System.out.println(Double.toString((double)temp)); // Prints 14009.349609375 

However, if instead of casting, I output the float as a string, and parse the string as a double, I get what I want:

System.out.println(Double.toString(Double.parseDouble(Float.toString(temp)))); // Prints 14009.35 

Is there a better way than to go to String and back?

like image 811
Steve Armstrong Avatar asked May 27 '09 14:05

Steve Armstrong


People also ask

How accurate is double float?

Double precision numbers are accurate up to sixteen decimal places but after calculations have been done there may be some rounding errors to account for. In theory this should affect no more than the last significant digit but in practice it is safer to rely upon fewer decimal places.

Can you convert a float to a double?

The doubleValue() method of Java Float class returns a double value corresponding to this Float Object by widening the primitive values or in simple words by directly converting it to double via doubleValue() method .

Are Doubles more precise than float?

double has 2x more precision than float. float is a 32-bit IEEE 754 single precision Floating Point Number – 1 bit for the sign, 8 bits for the exponent, and 23* for the value. float has 7 decimal digits of precision.

How do you float a double in Java?

Remember, by default floating-point numbers are double in Java, if you want to store them into float variables, you need to either cast them explicitly or suffixed them using the 'f' or 'F' characters.


2 Answers

It's not that you're actually getting extra precision - it's that the float didn't accurately represent the number you were aiming for originally. The double is representing the original float accurately; toString is showing the "extra" data which was already present.

For example (and these numbers aren't right, I'm just making things up) suppose you had:

float f = 0.1F; double d = f; 

Then the value of f might be exactly 0.100000234523. d will have exactly the same value, but when you convert it to a string it will "trust" that it's accurate to a higher precision, so won't round off as early, and you'll see the "extra digits" which were already there, but hidden from you.

When you convert to a string and back, you're ending up with a double value which is closer to the string value than the original float was - but that's only good if you really believe that the string value is what you really wanted.

Are you sure that float/double are the appropriate types to use here instead of BigDecimal? If you're trying to use numbers which have precise decimal values (e.g. money), then BigDecimal is a more appropriate type IMO.

like image 160
Jon Skeet Avatar answered Oct 05 '22 13:10

Jon Skeet


I find converting to the binary representation easier to grasp this problem.

float f = 0.27f; double d2 = (double) f; double d3 = 0.27d;  System.out.println(Integer.toBinaryString(Float.floatToRawIntBits(f))); System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d2))); System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d3))); 

You can see the float is expanded to the double by adding 0s to the end, but that the double representation of 0.27 is 'more accurate', hence the problem.

   111110100010100011110101110001 11111111010001010001111010111000100000000000000000000000000000 11111111010001010001111010111000010100011110101110000101001000 
like image 24
Brecht Yperman Avatar answered Oct 05 '22 14:10

Brecht Yperman