I heard that double is a more precise datatype and I would like to see the result of double
with the help of following program but still it is giving variable result each time similar but not exact to float.
What is the difference between float and double and when to use them in real time?
Can any body explain this scenario in simple terms
and specify the reason for this type of behaviour?
Thanks in advance :)
public class DoubleResult {
public static void main(String[] args) {
double number=1;
for(int i=0;i<5;i++){
number=number+0.1;
System.out.println(number);
}
}
}
output:
1.1
1.2000000000000002
1.3000000000000003
1.4000000000000004
1.5000000000000004
Both float and double are floating points. float is a single-precision (32 bit) floating point whereas double is a double-precision (hence the name) (64 bit)
Name Width in Bits Range
double 64 1.7e–308 to 1.7e+308
float 32 3.4e–038 to 3.4e+038
you can see this answer for a more precise description of the precision issue with floating points
A computer's floating point unit works with base 2 binary and 0.2 can't be represented precisely in binary, it is called a repeater fraction. In base-2 only numbers with denominators that are powers of 2 are terminating, which I think is only .25, .50, and .75, which is why 6.5 shows up as "same".
Imagine you had two decimal types, one with six significant digits, and one with sixteen.
What value would you use to represent pi for each of those types? In both cases you'd be trying to get as close to a number which you couldn't represent exactly - but you wouldn't end up with the same value, would you?
It's the same for float(32 bits) and double(64 bits) - both are binary floating point types, but double has more precision than float. so if you need precision then go for double.
See this for more details
Related
This question already has answers here:
Why converting from float to double changes the value?
(9 answers)
Closed 7 years ago.
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
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".
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:
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.
I am trying the code below to convert string to float and double but getting different results.
Code:
System.out.println(Float.parseFloat("120059389"));
System.out.println(Double.parseDouble("120059389"));
Output:
1.20059392E8
1.20059389E8
Could somebody explain me why I got different result for parsing string in float and double? What are the ranges for float and double?
This is because you're trying to parse a float by giving it more digits of precision than it can handle. The "ulp" (unit in last place) of a float that big is 8.0, but the "ulp" for a double that big is still reasonably small. That is, at that magnitude, the closest possible float values differ by 8, but the closest double values, with more precision, differ by far less.
System.out.println(Math.ulp(120059389f));
System.out.println(Math.ulp(120059389d));
This prints:
8.0
1.4901161193847656E-8
So the Float parser must use the closest float to the true value of 120059389, which happens to be 1.20059392E8.
The difference lies in the fact that Double and Float store numbers differently.
With Single and Double precision, allowing Double to give Double the amount of precision the Float can handle.
So the simple answer is that because of Float's limited memory in comparison to Double information is lost upon conversion of numbers out of the range Float can handle.
Float : 32-bit Numbers
Double : 64-bit Numbers
So in the conversion some information is lost when converting to the Float because it is truncated.
Generally...
Float stores numbers as 1 bit for the sign (-/+), 8 bits for the Exponent, and 23 bits for the fraction.
Double stores numbers as 1 bit for the sign (-/+), 8 bits for the Exponent, and 53 bits for the fraction.
When you convert your number 120059389 = 111001001111111010111111101b has 27 bits worth of information which can be covered by the Double's 53 bit allowence, but not by the Float's 23 bit allowance, and the data is truncated at the least significant end.
The conversion will round the number to the nearest representable number using 23 bits 1.20059392 = 111001001111111011000000000b and the exponent will handle the rest of the expansion.
The earlier links and answers give good technical answers. The 'laymans' answer is that a float is 32 bits and a double is 64 bits. Some of those bits are used for the number and some are used for the exponent. The number you put in your code simply had too many digits for the 32 bit 'float'. The 64 bit 'double' has more bits and can be more precise with larger numbers.
The same concept holds for even larger numbers when you reach the limits of a 64 bit double and need 128 bits of precision.
This question already has answers here:
Whats wrong with this simple 'double' calculation? [duplicate]
(5 answers)
Closed 9 years ago.
While I was having fun with codes from Java Puzzlers(I don't have the book) I came across this piece of code
public static void main(String args[]) {
System.out.println(2.00 - 1.10);
}
Output is
0.8999999999999999
When I tried changing the code to
2.00d - 1.10d still I get the same output as 0.8999999999999999
For,2.00d - 1.10f Output is 0.8999999761581421
For,2.00f - 1.10d Output is 0.8999999999999999
For,2.00f - 1.10f Output is 0.9
Why din't I get the output as 0.9 in the first place? I could not make any heads or tails out of this? Can somebody articulate this?
Because in Java double values are IEEE floating point numbers.
The work around could be to use Big Decimal class
Immutable, arbitrary-precision signed decimal numbers. A BigDecimal
consists of an arbitrary precision integer unscaled value and a 32-bit
integer scale. If zero or positive, the scale is the number of digits
to the right of the decimal point. If negative, the unscaled value of
the number is multiplied by ten to the power of the negation of the
scale. The value of the number represented by the BigDecimal is
therefore (unscaledValue × 10^-scale).
On a side note you may also want to check Wikipedia article on IEEE 754 how floating point numbers are stored on most systems.
The more operations you do on a floating point number, the more significant rounding errors can become.
In binary 0.1 is 0.00011001100110011001100110011001.....,
As such it cannot be represented exactly in binary. Depending where you round off (float or double) you get different answers.
So 0.1f =0.000110011001100110011001100
And 0.1d=0.0001100110011001100110011001100110011001100110011001
You note that the number repeats on a 1100 cycle. However the float and double precision split it at a different point in the cycle. As such on one the error rounds up and the other rounds down; leading to the difference.
But most importantly;
Never assume floating point numbers are exact
Other answers are correct, just to point to a valid reference, I quote oracle doc:
double: The double data type is a double-precision 64-bit IEEE 754
floating point. Its range of values is beyond the scope of this
discussion, but is specified in the Floating-Point Types, Formats, and
Values section of the Java Language Specification. For decimal values,
this data type is generally the default choice. As mentioned above,
this data type should never be used for precise values, such as
currency
class Test{
public static void main(String[] args){
float f1=3.2f;
float f2=6.5f;
if(f1==3.2){
System.out.println("same");
}else{
System.out.println("different");
}
if(f2==6.5){
System.out.println("same");
}else{
System.out.println("different");
}
}
}
output:
different
same
Why is the output like that? I expected same as the result in first case.
The difference is that 6.5 can be represented exactly in both float and double, whereas 3.2 can't be represented exactly in either type. and the two closest approximations are different.
An equality comparison between float and double first converts the float to a double and then compares the two. So the data loss.
You shouldn't ever compare floats or doubles for equality; because you can't really guarantee that the number you assign to the float or double is exact.
This rounding error is a characteristic feature of floating-point computation.
Squeezing infinitely many real numbers into a finite number of bits
requires an approximate representation. Although there are infinitely
many integers, in most programs the result of integer computations can
be stored in 32 bits.
In contrast, given any fixed number of bits,
most calculations with real numbers will produce quantities that
cannot be exactly represented using that many bits. Therefore the
result of a floating-point calculation must often be rounded in order
to fit back into its finite representation. This rounding error is the
characteristic feature of floating-point computation.
Check What Every Computer Scientist Should Know About Floating-Point Arithmetic for more!
They're both implementations of different parts of the IEEE floating point standard. A float is 4 bytes wide, whereas a double is 8 bytes wide.
As a rule of thumb, you should probably prefer to use double in most cases, and only use float when you have a good reason to. (An example of a good reason to use float as opposed to a double is "I know I don't need that much precision and I need to store a million of them in memory.") It's also worth mentioning that it's hard to prove you don't need double precision.
Also, when comparing floating point values for equality, you'll typically want to use something like Math.abs(a-b) < EPSILON where a and b are the floating point values being compared and EPSILON is a small floating point value like 1e-5. The reason for this is that floating point values rarely encode the exact value they "should" -- rather, they usually encode a value very close -- so you have to "squint" when you determine if two values are the same.
EDIT: Everyone should read the link #Kugathasan Abimaran posted below: What Every Computer Scientist Should Know About Floating-Point Arithmetic for more!
To see what you're dealing with, you can use Float and Double's toHexString method:
class Test {
public static void main(String[] args) {
System.out.println("3.2F is: "+Float.toHexString(3.2F));
System.out.println("3.2 is: "+Double.toHexString(3.2));
System.out.println("6.5F is: "+Float.toHexString(6.5F));
System.out.println("6.5 is: "+Double.toHexString(6.5));
}
}
$ java Test
3.2F is: 0x1.99999ap1
3.2 is: 0x1.999999999999ap1
6.5F is: 0x1.ap2
6.5 is: 0x1.ap2
Generally, a number has an exact representation if it equals A * 2^B, where A and B are integers whose allowed values are set by the language specification (and double has more allowed values).
In this case,
6.5 = 13/2 = (1+10/16)*4 = (1+a/16)*2^2 == 0x1.ap2, while
3.2 = 16/5 = ( 1 + 9/16 + 9/16^2 + 9/16^3 + . . . ) * 2^1 == 0x1.999. . . p1.
But Java can only hold a finite number of digits, so it cuts the .999. . . off at some point. (You may remember from math that 0.999. . .=1. That's in base 10. In base 16, it would be 0.fff. . .=1.)
class Test {
public static void main(String[] args) {
float f1=3.2f;
float f2=6.5f;
if(f1==3.2f)
System.out.println("same");
else
System.out.println("different");
if(f2==6.5f)
System.out.println("same");
else
System.out.println("different");
}
}
Try like this and it will work. Without 'f' you are comparing a floating with other floating type and different precision which may cause unexpected result as in your case.
It is not possible to compare values of type float and double directly. Before the values can be compared, it is necessary to either convert the double to float, or convert the float to double. If one does the former comparison, the conversion will ask "Does the the float hold the best possible float representation of the double's value?" If one does the latter conversion, the question will be "Does the float hold a perfect representation of the double's value". In many contexts, the former question is the more meaningful one, but Java assumes that all comparisons between float and double are intended to ask the latter question.
I would suggest that regardless of what a language is willing to tolerate, one's coding standards should absolutely positively forbid direct comparisons between operands of type float and double. Given code like:
float f = function1();
double d = function2();
...
if (d==f) ...
it's impossible to tell what behavior is intended in cases where d represents a value which is not precisely representable in float. If the intention is that f be converted to a double, and the result of that conversion compared with d, one should write the comparison as
if (d==(double)f) ...
Although the typecast doesn't change the code's behavior, it makes clear that the code's behavior is intentional. If the intention was that the comparison indicate whether f holds the best float representation of d, it should be:
if ((float)d==f)
Note that the behavior of this is very different from what would happen without the cast. Had your original code cast the double operand of each comparison to float, then both equality tests would have passed.
In general is not a good practice to use the == operator with floating points number, due to approximation issues.
6.5 can be represented exactly in binary, whereas 3.2 can't. That's why the difference in precision doesn't matter for 6.5, so 6.5 == 6.5f.
To quickly refresh how binary numbers work:
100 -> 4
10 -> 2
1 -> 1
0.1 -> 0.5 (or 1/2)
0.01 -> 0.25 (or 1/4)
etc.
6.5 in binary: 110.1 (exact result, the rest of the digits are just zeroes)
3.2 in binary: 11.001100110011001100110011001100110011001100110011001101... (here precision matters!)
A float only has 24 bits precision (the rest is used for sign and exponent), so:
3.2f in binary: 11.0011001100110011001100 (not equal to the double precision approximation)
Basically it's the same as when you're writing 1/5 and 1/7 in decimal numbers:
1/5 = 0,2
1,7 = 0,14285714285714285714285714285714.
Float has less precision than double, bcoz float is using 32bits inwhich 1 is used for Sign, 23 precision and 8 for Exponent . Where as double uses 64 bits in which 52 are used for precision, 11 for exponent and 1for Sign....Precision is important matter.A decimal number represented as float and double can be equal or unequal depends is need of precision( i.e range of numbers after decimal point can vary). Regards S. ZAKIR
I want to convert longitude and latitude that I get as a string from my database. The string is correct, and when i try to convert it into double, it is also correct. However when i am convert the double or the string value (i have tried both) into a float value, the last decimal gets round off.
The value of the string or double is 59.858139
The convertion to float is 59.85814
I've tried everything, and this is one desperate example :)
private float ConvertToFloat(double d)
{
float f = 00.000000f;
f = (float) d;
return f;
}
You are aware that doubles have more precision than floats and that floats round off, right? This is expected behaviour. There is no sense in casting a double to a float in this case.
Here's something to get you thinking in the right direction...
Double.doubleToRawLongBits(long value);
Float.intBitsToFloat(int bits);
Doubles can't fit into int and they have to fit into long. It's really twice the size, even mediating bits with strings won't do any good here.
1. float has only 24 bits of precision, which will be insufficient to hold the number of digits in your latitude and longitude.
2. The rounding off is due to the size of the number. So use double if you require floating point, or use BigDecimal
We are starting with your decimal number 59.858139
Convert that number to binary: 111011.11011011101011101111111101011100011011000001000110100001000100...
I.e. the number is an infinite fraction in binary. It is not possible to represent it exactly. (In the same way that it is not possible to represent 1/3 exactly with decimal numbers)
Rewrite the number to some form of binary scientific notation:
10 ^ 101 * 1.1101111011011101011101111111101011100011011000001000110100001000100...
Remember that this is still in binary, so the 10 ^ 101 corresponds to 2 ^ 5 in decimal notation.
Now... A float value can store 23 bits in the mantissa. If we round it up using "round to nearest" rounding mode, we get:
10 ^ 101 * 1.11011110110111010111100
Which is equal to:
111011.110110111010111100
That is all the precision that can fit into the float data type. Now convert that back to decimal:
59.8581390380859375
Seems pretty close to 59.858139 actually... But that is just luck. What happens if we convert the second closest float value to binary instead?
111011.110110111010111011 = 59.858135223388671875
So basically the resolution is approximately 0.000004.
So all we can really know from the float value is that the number is something like: 59.858139 ± 0.000002
It could just as well be 59.858137 or 59.858141.
Since the last digit is rather uncertain, I am guessing that the printing code is smart enough to understand that the last digit falls outside the precision of a float value, and hence, the value is rounded to 59.85814.
By the way, if you (like me are) are too lazy to convert between binary and decimal fractions by hand, you can use this converter. If you want to read more about the details of the floating point system, the wikipedia page for floating point representation is a great resource.