Поделиться через


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 removed

  • Anonymous
    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,0FFFFFFF8h

  • Anonymous
    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.

    -Murali

  • Anonymous
    May 29, 2006
    The comment has been removed

  • Anonymous
    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