Quiz of the Month: Double Trouble
Without compiling and running this program. Can you tell me what the output would be?
class MainProgram
{
static void Main(string[] args)
{
double a = Convert.ToDouble("1.170404");
double b = Convert.ToDouble("2.170404");
double c = Convert.ToDouble("3.170404");
double d = Convert.ToDouble("4.170404");
Console.WriteLine((a == 1.170404));
Console.WriteLine((b == 2.170404));
Console.WriteLine((c == 3.170404));
Console.WriteLine((d == 4.170404));
}
}
Comments
Anonymous
May 08, 2006
No, I can't. But I have a feeling that it will say 'false' for all 4 the cases. I know that doubles and == don't like each other very much.Anonymous
May 08, 2006
I wouldn't want to answer this question... ;)Anonymous
May 09, 2006
I'd expect there to be a number of 'False' strings output. Possibly even 4 of them....Anonymous
May 09, 2006
My guess is all true, but I don't think you'd be posing the question if that were the case, but I can't think of why any of them wouldn't be true.Anonymous
May 09, 2006
Floating point comparisons are notoriously unreliable. This just proves it.Anonymous
May 09, 2006
OK, only one was. Why that one?Anonymous
May 09, 2006
The comment has been removedAnonymous
May 09, 2006
Okay, I thought I knew the answer and then I ran the code and I was wrong. Want to explain how it works?Anonymous
May 09, 2006
hmm well if I had to guess without running it I would guess all of them would write out false.
Doubles are big floats, 64 BIT I believe, which when converted like that usually will never maintain the precision very well in a conversion. I would imagine you would get similar results as well if you were converting Int32 to a double that there would be precision loss.
The only thing I know of that would maintain the precision in that way could be doing it this way
double a = 1.170404D;
double b = 2.170404D;
double c = 3.170404D;
double d = 4.170404D;
Using Convert here would be a waste since it will just return the original.
But that doesn't help you in converting a string to a double. Thats an interesting problem. One of those why I typically avoid floats. If I have to deal with decimal points and need precision I typically use a decimal. Floats are ok if you are going to round them off in display later and not do a whole lot with them. I am going to have to run it now, to see what I get but I am guessing what ever I get will be wierd and not make much sense as dealing with floats don't usually. I am going to have to look in the spec and see what it says as well. I have never researched the rhyme nor reason on floats and their precisions.Anonymous
May 09, 2006
Well, after make a semi-logical guess, I ran the code to discover that I was 75% correct (wrong about b). Of course, a even naive guess would also get you 75% right (but wrong about d instead)Anonymous
May 09, 2006
I'm going to post answer/explaination in 2 weeks (or around then.. :))Anonymous
May 09, 2006
this might have something to do with it...
and esp,0FFFFFFF8hAnonymous
May 10, 2006
Hah, well why playing with this to see if I could get the answer I found some other interesting things.
Try the folloing code as well:
Will it run, or Divide by 0 exception.
Console.WriteLine((1.0D / 0.0D) == (-1.0D / 0.0D));
Console.WriteLine(1.0D / 0.0D);Anonymous
May 11, 2006
The weird behaviour observed by variable d is quite disconcerting and indeed, a larger value of d = 4.180404 will return true ie it will not lose precision in the conversion.
The question is to ask is: why does double lose precision for the particular values of 4.170404, 5.170404, 6.170404, etc.
well done kathy, on this excellent puzzle.
I am looking forward to the answer.Anonymous
May 19, 2006
I believe that you can attribute that to the IEEE roundoff error inhernent in the double precision floating point variables.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <float.h>
int main(int argc, char **argv)
{
double a,d;
a = atof("1.170404");
d = atof("4.170404");
printf("a=%.*g, d=%.*gn",DBL_DIG,a,DBL_DIG,d);
// Reproduces the results
printf("test a: %sn",(a == 1.170404?"true":"false"));
printf("test d: %sn",(d == 4.170404?"true":"false"));
// A better test when working with floating point numbers
printf("test a: %sn",(fabs(a - 1.170404) <= sqrt(DBL_EPSILON)?"true":"false"));
printf("test d: %sn",(fabs(d - 4.170404) <= sqrt(DBL_EPSILON)?"true":"false"));
}
Notice the the sqrt(DBL_EPSILON) is a better equality test with double precision floating point numbers. == alone for floating point numbers can be risky.Anonymous
May 21, 2006
I believe that you can attribute that to the IEEE roundoff error inhernent in the double precision floating point variables.
I better test would be as follows (shown in C++)
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <float.h>
int main(int argc, char **argv)
{
double a,d;
a = atof("1.170404");
d = atof("4.170404");
printf("a=%.*g, d=%.*gn",DBL_DIG,a,DBL_DIG,d);
// Reproduces your results
printf("test a: %sn",(a == 1.170404?"true":"false"));
printf("test d: %sn",(d == 4.170404?"true":"false"));
// A better test when working with floating point numbers
printf("test a: %sn",(fabs(a - 1.170404) <= sqrt(DBL_EPSILON)?"true":"false"));
printf("test d: %sn",(fabs(d - 4.170404) <= sqrt(DBL_EPSILON)?"true":"false"));
}
Notice the the sqrt(DBL_EPSILON) is a better equality test with double precision floating point numbers. == alone for floating point numbers can be risky.
-MuraliAnonymous
May 29, 2006
The comment has been removedAnonymous
May 29, 2006
interesting....
this 4 FloatingPoint's integer part chang to binary system,
a = 1,
b=10,
c=11,
d=100
I think this is a key.
If 0.170404 chang to binary system of lenth equal to 62bit(guess),and adding to integer part 2 bit, it's not out of Floating Point ,
If integer part exceed 3 bit, it's out of Floating Point
It's my guess of all.Soryy,my english is very poor,I'm from china.Anonymous
May 31, 2006
0010101110011111100110001011011100011011100010101010000000000000
+123456789+123456789+123456789+123456789+123456789+123456789+123
This is binary value for 0.170404. it has 51 bit virtual value.
Double has 53 bit virtual value.Anonymous
June 16, 2006
Excellent find, Kathy! It looks to me like this is due to the different way the C# compiler and the .NET framework parse real numbers.
Notice all the zeros at the end of the binary expansion in Colin Han's comment above. The rotor code contains an unnecessary optimization based on the faulty assumption that a round-off error in the 64th bit will not propagate to the final result. My guess is the same error is present in the actual .NET code. See http://blogs.extremeoptimization.com/jeffrey/archive/2006/06/16/16647.aspx for details.
More examples of "floating-point wierdness" can be found in this article: http://www.extremeoptimization.com/Resources/Articles/FPDotNetConceptsAndFormats.aspx.Anonymous
July 29, 2006
I am a computer science student..I don't know about "floating point internal expression in computer"..But after I read the article Jeffrey Sax said(http://www.extremeoptimization.com/Resources/Articles/FPDotNetConceptsAndFormats.aspx)..I think I know the reason..3 in binary format is "11" while 4 is "100"..there's a "overflow" in the computer's internal operation.. maybe that's the reason...Anonymous
August 16, 2006
Did you know, that: a double can represent 0xFF D FFFFFFFFFFFFF = 18437736874454810623 distinct numbers?Anonymous
March 04, 2007
which sum is greater Colum A or Colum B?Anonymous
June 15, 2009
PingBack from http://edebtsettlementprogram.info/story.php?id=22782