# 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));

}

}

Tags

1. 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.

2. I wouldn’t want to answer this question… 😉

3. Simon says:

I’d expect there to be a number of ‘False’ strings output. Possibly even 4 of them….

4. 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.

5. Philip Hoppe says:

Floating point comparisons are notoriously unreliable. This just proves it.

6. Simon says:

OK, only one was. Why that one?

7. John Meyer says:

Interesting… a bug in Convert.ToDouble(String)

changing the code to

double a = Convert.ToDouble(1.170404D);

double b = Convert.ToDouble(2.170404D);

double c = Convert.ToDouble(3.170404D);

double d = Convert.ToDouble(4.170404D);

outputs True 4 times (so does the same code without the Ds)… we should be guaranteed that

Convert.ToDouble("1.170404")==Convert.ToDouble(1.170404)

is true for any and all numeric values, but we’re not!  WTF???  :-S

8. Kyle says:

Okay, I thought I knew the answer and then I ran the code and I was wrong.  Want to explain how it works?

9. Jeff Parker says:

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.

10. Garry Trinder says:

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)

11. KathyKam says:

I’m going to post answer/explaination in 2 weeks (or around then.. :))

12. this might have something to do with it…

and         esp,0FFFFFFF8h

13. Jeff Parker says:

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);

14. Shailen Sukul says:

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.

15. Murali says:

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.

16. Murali says:

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);

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

17. neolee says:

interesting….这看起来是一个浮点数的精度问题,我从对比逻辑上猜想一下:

a,b,c,d的四浮点数唯一的区别在于整数位转换成二进制的时候,他们的位数在内存中表示时是不一样的,我认为这是一个关键,a = 1,b=10,c=11,d=100,如果在处理浮点数时(0.170404),最大长度64位刚好除到62位(假设而已),加上整数的2位(好像在内存中的表示时会去掉最前面的"1"),则不存在浮点数的精度问题,可是如果整数位 > 3的话,就会出现浮点数的精度问题,我用程序侧面证明试了一下,所有大于3的数都是false,基本上符合我的猜想.

18. neolee says:

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.

19. Colin Han says:

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.

20. Jeffrey Sax says:

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.

21. Dah says:

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…

22. Did you know, that: a double can represent 0xFF D FFFFFFFFFFFFF = 18437736874454810623 distinct numbers?

23. mona says:

which sum is greater Colum A or Colum B?