Converting from float to double, why the extra decimal points? [duplicate] - java

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?

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.

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

This is due the contract of Float.toString(float), which says in part:
How many digits must be printed for
the fractional part […]? 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.

I've encountered this issue today and could not use refactor to BigDecimal, because the project is really huge. However I found solution using
Float result = new Float(5623.23)
Double doubleResult = new FloatingDecimal(result.floatValue()).doubleValue()
And this works.
Note that calling result.doubleValue() returns 5623.22998046875
But calling doubleResult.doubleValue() returns correctly 5623.23
But I am not entirely sure if its a correct solution.

I found the following solution:
public static Double getFloatAsDouble(Float fValue) {
return Double.valueOf(fValue.toString());
}
If you use float and double instead of Float and Double use the following:
public static double getFloatAsDouble(float value) {
return Double.valueOf(Float.valueOf(value).toString()).doubleValue();
}

Use a BigDecimal instead of float/double. There are a lot of numbers which can't be represented as binary floating point (for example, 0.1). So you either must always round the result to a known precision or use BigDecimal.
See http://en.wikipedia.org/wiki/Floating_point for more information.

Floats, by nature, are imprecise and always have neat rounding "issues". If precision is important then you might consider refactoring your application to use Decimal or BigDecimal.
Yes, floats are computationally faster than decimals because of the on processor support. However, do you want fast or accurate?

A simple solution that works well, is to parse the double from the string representation of the float:
double val = Double.valueOf(String.valueOf(yourFloat));
Not super efficient, but it works!

For information this comes under Item 48 - Avoid float and double when exact values are required, of Effective Java 2nd edition by Joshua Bloch. This book is jam packed with good stuff and definitely worth a look.

Does this work?
float flt = 145.664454;
Double dbl = 0.0;
dbl += flt;

There is a way to convert Float value into Double without adding the extra precision
Float aFloat= new Float(0.11);
String s = aFloat.toString();
Double aDouble = Double.parseDouble(s);
This Approach will not add an extra precisions to your Float value while converting. The only Problem with this approach is memory usage of the JVM by creating an extra tamp String object.
When calling an toString() (aDouble.toString()) on Double will never add an extra precisions. The precisions will be added while type conversion.

Related

Java initialize doubles from floats [duplicate]

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?
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.
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
This is due the contract of Float.toString(float), which says in part:
How many digits must be printed for
the fractional part […]? 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.
I've encountered this issue today and could not use refactor to BigDecimal, because the project is really huge. However I found solution using
Float result = new Float(5623.23)
Double doubleResult = new FloatingDecimal(result.floatValue()).doubleValue()
And this works.
Note that calling result.doubleValue() returns 5623.22998046875
But calling doubleResult.doubleValue() returns correctly 5623.23
But I am not entirely sure if its a correct solution.
I found the following solution:
public static Double getFloatAsDouble(Float fValue) {
return Double.valueOf(fValue.toString());
}
If you use float and double instead of Float and Double use the following:
public static double getFloatAsDouble(float value) {
return Double.valueOf(Float.valueOf(value).toString()).doubleValue();
}
Use a BigDecimal instead of float/double. There are a lot of numbers which can't be represented as binary floating point (for example, 0.1). So you either must always round the result to a known precision or use BigDecimal.
See http://en.wikipedia.org/wiki/Floating_point for more information.
Floats, by nature, are imprecise and always have neat rounding "issues". If precision is important then you might consider refactoring your application to use Decimal or BigDecimal.
Yes, floats are computationally faster than decimals because of the on processor support. However, do you want fast or accurate?
A simple solution that works well, is to parse the double from the string representation of the float:
double val = Double.valueOf(String.valueOf(yourFloat));
Not super efficient, but it works!
For information this comes under Item 48 - Avoid float and double when exact values are required, of Effective Java 2nd edition by Joshua Bloch. This book is jam packed with good stuff and definitely worth a look.
Does this work?
float flt = 145.664454;
Double dbl = 0.0;
dbl += flt;
There is a way to convert Float value into Double without adding the extra precision
Float aFloat= new Float(0.11);
String s = aFloat.toString();
Double aDouble = Double.parseDouble(s);
This Approach will not add an extra precisions to your Float value while converting. The only Problem with this approach is memory usage of the JVM by creating an extra tamp String object.
When calling an toString() (aDouble.toString()) on Double will never add an extra precisions. The precisions will be added while type conversion.

Converting a double value into float explicitly and storing that in a double variable

If I create a double variable and assign it an expression for instance (5d / 3d) and convert into float explicitly, like,
double c = (float)(5d / 3d);
System.out.println(c);
OUTPUT:
1.6666666269302368
It should have given precision of float datatype as float is smaller than double so double variable should have no problem in storing float value but the output is absurd. Why is it so?
Please help me in understanding the output of this code. I am unable to understand this output in the code.
It's because of the way the bit pattern is arranged when you divide five and three, it is an imprecise floating point value (it's 1.6666666 and a tiny bit). Simple as that. To demonstrate,
float f = (float) (5.0 / 3);
System.out.printf("%f=%s %s=%s%n", f, Float.toHexString(f),
(double) f, Double.toHexString(f));
System.out.printf("%s=%s %s=%s%n", f, Float.toHexString(f),
(double) f, Double.toHexString(f));
The output is
1.666667=0x1.aaaaaap0 1.6666666269302368=0x1.aaaaaap0
1.6666666=0x1.aaaaaap0 1.6666666269302368=0x1.aaaaaap0
In both cases you will notice the bit pattern is constant.
My Java skills are very rusty, but what I think happened here is that when you cast the result of the division to a float you threw away half the precision. Then, when you stored it in a double and passed that to System.out.println, System.out.println tried to print it to a gazillion decimal places.
But, because of the cast, those decimal places are inaccurate. System.out.println has, in effect, invented them. Try removing the cast, see what you get, or print the result as a float. Doing either should give more sensible results.

Why does multiplying a float and double give less accurate result than multiplying two floats [duplicate]

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?
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.
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
This is due the contract of Float.toString(float), which says in part:
How many digits must be printed for
the fractional part […]? 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.
I've encountered this issue today and could not use refactor to BigDecimal, because the project is really huge. However I found solution using
Float result = new Float(5623.23)
Double doubleResult = new FloatingDecimal(result.floatValue()).doubleValue()
And this works.
Note that calling result.doubleValue() returns 5623.22998046875
But calling doubleResult.doubleValue() returns correctly 5623.23
But I am not entirely sure if its a correct solution.
I found the following solution:
public static Double getFloatAsDouble(Float fValue) {
return Double.valueOf(fValue.toString());
}
If you use float and double instead of Float and Double use the following:
public static double getFloatAsDouble(float value) {
return Double.valueOf(Float.valueOf(value).toString()).doubleValue();
}
Use a BigDecimal instead of float/double. There are a lot of numbers which can't be represented as binary floating point (for example, 0.1). So you either must always round the result to a known precision or use BigDecimal.
See http://en.wikipedia.org/wiki/Floating_point for more information.
Floats, by nature, are imprecise and always have neat rounding "issues". If precision is important then you might consider refactoring your application to use Decimal or BigDecimal.
Yes, floats are computationally faster than decimals because of the on processor support. However, do you want fast or accurate?
A simple solution that works well, is to parse the double from the string representation of the float:
double val = Double.valueOf(String.valueOf(yourFloat));
Not super efficient, but it works!
For information this comes under Item 48 - Avoid float and double when exact values are required, of Effective Java 2nd edition by Joshua Bloch. This book is jam packed with good stuff and definitely worth a look.
Does this work?
float flt = 145.664454;
Double dbl = 0.0;
dbl += flt;
There is a way to convert Float value into Double without adding the extra precision
Float aFloat= new Float(0.11);
String s = aFloat.toString();
Double aDouble = Double.parseDouble(s);
This Approach will not add an extra precisions to your Float value while converting. The only Problem with this approach is memory usage of the JVM by creating an extra tamp String object.
When calling an toString() (aDouble.toString()) on Double will never add an extra precisions. The precisions will be added while type conversion.

Why is float to double cast unprecise, double to float not?

I know that floating point variables loose precision while casting. But what I don't understand is, why a cast from a smaller primitive to a bigger one is unprecise but vice versa not. I would understand if it happens from double to float but it's the other way around. Why is this so?
See the results from these two tests:
#Test
public void castTwoPrimitiveDecimalsUnpreciseToPrecise()
{
float var1 = 6.2f;
double var2 = var1;
assertThat(var2, is(6.2d)); //false, because it's 6.199999809265137
}
#Test
public void castTwoPrimitiviesDecimalsPreciseToUnpresice()
{
double var1 = 7.6d;
float var2 = (float)var1;
assertThat(var2, is(7.6f)); //true
}
The precision issue is in the initialization of your variables, not in the conversion.
In the first case, you start with a number that is only the float approximation to decimal 6.2. The conversion to double gets a double with exactly the same value as that float approximation. You then compare it against the much closer double approximation, so of course it does not match.
In the second case, you start with the double approximation to decimal 7.6. You then convert it to float. That will round the double to a float. Rounding twice, on the original conversion to double and on the cast to float, could conceivably produce a different answer from directly converting a number to float, but usually you will get the float approximation. You then compare it to the float approximation, so it is not surprising you get a match.
Suppose someone measures a peg with a ruler and determines that it/s 3/8" diameter. The other person measures a hole with a calipers and discovers that it's 9.5267mm. Will the peg fit in the hole?
If one converts the cruder measurement to the higher-precision form, one finds that the hole appears to be 0.0017mm (i.e. about 1/15000") larger than the peg. If one converts them both to the lower-precision form, one will find that the values are indistinguishable.
If the peg that was measured as 3/8" is in fact precisely 9.525mm [the exact metric equivalent], such a measurement may be converted to a higher-resolution form without conversion loss. If, however, it simply means "something that's closer to the 3/8" mark than to 23/64" or 25/64", such conversion will cause a value which would generally be expected to be an approximation to be interpreted as being more precise than it really is.
Some people would regard the fact that the peg and hole are regarded as different sizes as being a good thing. Personally, I would think it would be better to regard them as being indistinguishable. With the measurements as described, there's no particular reason to believe with any certainty that the peg is bigger than the hole; it probably isn't exactly equal, but calling them indistinguishable is more accurate than saying the peg is bigger.
Personally, I detest language rules that require values to be written as or cast to [single-precision] float merely to shut up the compiler. If one wants to set a float equal to the value closest to 4.7, one should be able to simply say:
float f=4.7;
and achieve that effect. A person who sees:
static final float coef = 4.7f;
... some time later
float f = coef;
double d = coef;
will have no way of knowing whether the goal was to set d to the double value equal to the float value closest to 4.7, or whether the goal was to set d to the double value closest to 4.7. Unfortunately, Java provides no means by which one can declare a constant which can be silently assigned to float without an explicit cast, but which when assigned to double will use the precision available in that type.
Incidentally, if my goal was to set some double variable v equal the value of the float closest to the specified numeric value of coef, rather than the value of the double closest to that numeric value, I'd probably code it very explicitly:
v = (double)(float)coef;
That would make clear and unambiguous the fact that the programmer was expecting and intending that a double would be assigned a value which had been previously rounded to float precision. Absent the (double) typecast, one would have to consider the possibilities that the programmer might have expected v to be a float (e.g. because when the code was written, it was a float, but since then it was changed to double). Absent the (float) typecast, one would have to consider the possibility that the programmer was expecting coef to be a double (e.g. because it had been, but someone changed it to a float to allow it to be assigned to variables of float type without the compiler squawking).

How to Map a double value to a float one In Java?

At first glance, my question could seem a bit odd; but casting a double to a float value is not what i want. Since when you cast it, you just lose some precision with respect to the rules defined IEEE-754 and can't achieve actual mapping of a double value to the range of float; it is useless. The following expression works, but it is very very expensive when you have a great amount of input:
float mappedVal = (float)((val * MAX_FLOAT_VALUE + 1) / MAX_DOUBLE_VALUE);
Can I approximate the result to the "mappedVal" mentioned above via some sort of bitwise operations to speed-up the very same computation?
I'm not sure what you're trying to achieve, since some double values are far outside the range of float.
But if you're willing to risk losing values that are too big for float, try this:
float f = new Double(val).floatValue();
Edit: which is exactly the same as casting to float. :)
This maps a double precision value into the float that has the same highest 32 bits:
float mappedVal = Float.intBitsToFloat((int)(Double.doubleToLongBits(val)>>32));
The arithmetic interpretation of this operation is a little complicated though, parts of the exponent are mapped into the mantissa...

Categories

Resources