|
dev
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Double Trouble - bug in double?The following lines of code are basically all the same. However, some of the numbers evaluate to "true" while others evaluate to "false". I can not figure this out. Response.Write((Convert.ToDouble("3.170404") == 3.170404)); // is true Response.Write((Convert.ToDouble("5.170404") == 5.170404)); // why is this false? Response.Write((Convert.ToDouble("6.170404") == 6.170404)); // why is this false? Response.Write((Convert.ToDouble("8.170404") == 8.170404)); // is true Any ideas? This occurs in both .NET 1.x and 2.x. Is this a bug or am I missing something? Regards, Doug There's definitely some weird stuff going on:
Convert.ToDouble gives 5.1704039999999996 whereas the compiler gives a constant the exact value 5.170404 Of course there is nothing that says that the compiler should use the same conversion algorithm as the framework but it's not good. Also 5.170404F is exactly 5.170404 but (double)5.170404F gives 5.1704039573669434 which is wrong as there should be no change on widening float to double. Show quote "Doug" <D***@discussions.microsoft.com> wrote in message news:8C4AEB0B-9707-452F-8B26-198D58C44690@microsoft.com... > There appears to be a bug with Double, unless I'm missing something? > > The following lines of code are basically all the same. However, some of > the > numbers evaluate to "true" while others evaluate to "false". I can not > figure > this out. > > Response.Write((Convert.ToDouble("3.170404") == 3.170404)); // is true > Response.Write((Convert.ToDouble("5.170404") == 5.170404)); // why is this > false? > Response.Write((Convert.ToDouble("6.170404") == 6.170404)); // why is this > false? > Response.Write((Convert.ToDouble("8.170404") == 8.170404)); // is true > > Any ideas? This occurs in both .NET 1.x and 2.x. Is this a bug or am I > missing something? > > Regards, > > Doug Nick Hounsome <N***@NickHounsome.Me.Uk> wrote:
> There's definitely some weird stuff going on: No it doesn't. It can't possibly, as there's no double which is exactly > > Convert.ToDouble gives 5.1704039999999996 > whereas the compiler gives a constant the exact value 5.170404 that value. The closest you can get is: 5.17040400000000044400394472177140414714813232421875 See http://www.pobox.com/~skeet/csharp/floatingpoint.html for more on this, and a link to DoubleConverter.cs which is what I used to get the above. > Of course there is nothing that says that the compiler should use the same No, 5.170404F is actually 5.170403957366943359375.> conversion algorithm as the framework but it's not good. > > Also 5.170404F is exactly 5.170404 but (double)5.170404F gives > 5.1704039573669434 which is wrong as there should be no change on widening > float to double. -- Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too "Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message Obviously the value in the debugger is rounded but what seems to be news:MPG.1eb85fc86508b20d98d14a@msnews.microsoft.com... > Nick Hounsome <N***@NickHounsome.Me.Uk> wrote: >> There's definitely some weird stuff going on: >> >> Convert.ToDouble gives 5.1704039999999996 >> whereas the compiler gives a constant the exact value 5.170404 > > No it doesn't. It can't possibly, as there's no double which is exactly > that value. The closest you can get is: > > 5.17040400000000044400394472177140414714813232421875 happening is that Convert.ToDouble is getting the nearest value less than 5.170404 and the compiler is using your value which is the nearest greater - both are out by about 4 in the 16th place. The fact remains that ideally everything should use the same conversions. (My stuff with floats was wrong because I wasn't assigning back to a double in both cases) Nick Hounsome wrote:
> > No it doesn't. It can't possibly, as there's no double which is exactly But the compiler version is out by less - the compiler version is> > that value. The closest you can get is: > > > > 5.17040400000000044400394472177140414714813232421875 > > Obviously the value in the debugger is rounded but what seems to be > happening is that Convert.ToDouble is getting the nearest value less than > 5.170404 and the compiler is using your value which is the nearest greater - > both are out by about 4 in the 16th place. nearer to the correct value. It's interesting to note that the C# spec dictates how the compiler should behave - the documentation for Convert.ToDouble (and Double.Parse) is woefully inadequate, giving the impression that the exact number will actually be returned when of course that can't possibly be the case. > The fact remains that ideally everything should use the same conversions. Agreed (and never disputed, at least by me).Jon
Show quote
"Doug" <D***@discussions.microsoft.com> wrote in message Must have something to do with string to number conversions and floating news:8C4AEB0B-9707-452F-8B26-198D58C44690@microsoft.com... > There appears to be a bug with Double, unless I'm missing something? > > The following lines of code are basically all the same. However, some of > the > numbers evaluate to "true" while others evaluate to "false". I can not > figure > this out. > > Response.Write((Convert.ToDouble("3.170404") == 3.170404)); // is true > Response.Write((Convert.ToDouble("5.170404") == 5.170404)); // why is this > false? > Response.Write((Convert.ToDouble("6.170404") == 6.170404)); // why is this > false? > Response.Write((Convert.ToDouble("8.170404") == 8.170404)); // is true > > Any ideas? This occurs in both .NET 1.x and 2.x. Is this a bug or am I > missing something? > > Regards, > > Doug point precision. If you do Response.Write((Convert.ToDouble(5.170404) == 5.170404)) it yields true. This is from the sdk. When you work with floating-point numbers (Single Data Type (Visual Basic) and Double Data Type (Visual Basic)), keep in mind that they are stored as binary fractions. This means they cannot hold an exact representation of any quantity that is not a binary fraction (of the form k / (2 ^ n) where k and n are integers). For example, 0.5 (= 1/2) and 0.3125 (= 5/16) can be held as precise values, while 0.2 (= 1/5) and 0.3 (= 3/10) can be only approximations. Because of this imprecision, you cannot rely on exact results when you operate on floating-point values. In particular, two values that are theoretically equal might have slightly different representations. To compare floating-point quantities 1.. Calculate the absolute value of their difference, using the Abs method of the Math class in the System namespace. 2.. Determine an acceptable maximum difference, such that you can consider the two quantities to be equal for practical purposes if their difference is no greater. 3.. Compare the absolute value of the difference to the acceptable difference. In other words, Single and Double are not "exact" values except for a very
limited set of numbers. If you need that kind of precision, either use Decimal, which is implemented as Binary Coded Decimal, or find a "big int" library and scale your numbers to they are always integers. This is not a bug. It is a restriction in the hardware that we will have to deal with as long as computers use base 2 as their native numeric format. Mike Ober. Show quote "vMike" <MicZhaYel.GeoZr***@noYandZ.geZwaYrrenZ.com> wrote in message news:7bm3g.10040$MM6.5663@bignews3.bellsouth.net... > > > "Doug" <D***@discussions.microsoft.com> wrote in message > news:8C4AEB0B-9707-452F-8B26-198D58C44690@microsoft.com... > > There appears to be a bug with Double, unless I'm missing something? > > > > The following lines of code are basically all the same. However, some of > > the > > numbers evaluate to "true" while others evaluate to "false". I can not > > figure > > this out. > > > > Response.Write((Convert.ToDouble("3.170404") == 3.170404)); // is true > > Response.Write((Convert.ToDouble("5.170404") == 5.170404)); // why is this > > false? > > Response.Write((Convert.ToDouble("6.170404") == 6.170404)); // why is this > > false? > > Response.Write((Convert.ToDouble("8.170404") == 8.170404)); // is true > > > > Any ideas? This occurs in both .NET 1.x and 2.x. Is this a bug or am I > > missing something? > > > > Regards, > > > > Doug > Must have something to do with string to number conversions and floating > point precision. If you do > Response.Write((Convert.ToDouble(5.170404) == 5.170404)) it yields true. > > This is from the sdk. > > When you work with floating-point numbers (Single Data Type (Visual Basic) > and Double Data Type (Visual Basic)), keep in mind that they are stored as > binary fractions. This means they cannot hold an exact representation of any > quantity that is not a binary fraction (of the form k / (2 ^ n) where k and > n are integers). For example, 0.5 (= 1/2) and 0.3125 (= 5/16) can be held as > precise values, while 0.2 (= 1/5) and 0.3 (= 3/10) can be only > approximations. > > Because of this imprecision, you cannot rely on exact results when you > operate on floating-point values. In particular, two values that are > theoretically equal might have slightly different representations. > > To compare floating-point quantities > 1.. Calculate the absolute value of their difference, using the Abs method > of the Math class in the System namespace. > > 2.. Determine an acceptable maximum difference, such that you can consider > the two quantities to be equal for practical purposes if their difference is > no greater. > > 3.. Compare the absolute value of the difference to the acceptable > difference. > > > Michael D. Ober <ober***@.alum.mit.edu.nospam> wrote:
> In other words, Single and Double are not "exact" values except for a very Decimal isn't implemented as a Binary Coded Decimal. It's a floating > limited set of numbers. If you need that kind of precision, either use > Decimal, which is implemented as Binary Coded Decimal, or find a "big int" > library and scale your numbers to they are always integers. point number with a base of 10. See http://www.pobox.com/~skeet/csharp/decimal.html -- Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too Doug <D***@discussions.microsoft.com> wrote:
Show quote > There appears to be a bug with Double, unless I'm missing something? It seems that the compiler is using a slightly different algorithm to > > The following lines of code are basically all the same. However, some of the > numbers evaluate to "true" while others evaluate to "false". I can not figure > this out. > > Response.Write((Convert.ToDouble("3.170404") == 3.170404)); // is true > Response.Write((Convert.ToDouble("5.170404") == 5.170404)); // why is this > false? > Response.Write((Convert.ToDouble("6.170404") == 6.170404)); // why is this > false? > Response.Write((Convert.ToDouble("8.170404") == 8.170404)); // is true > > Any ideas? This occurs in both .NET 1.x and 2.x. Is this a bug or am I > missing something? Convert.ToDouble. Here's a program to find out what the values actually are: using System; class Test { static double d2; static void Main() { double d1 = Convert.ToDouble ("5.170404"); d2 = 5.170404d; Console.WriteLine (d1==d2); Console.WriteLine (d1.ToString("r")); Console.WriteLine (d2.ToString("r")); Console.WriteLine (DoubleConverter.ToExactString(d1)); Console.WriteLine (DoubleConverter.ToExactString(d2)); } } (DoubleConverter.cs is linked from http://www.pobox.com/~skeet/csharp/floatingpoint.html ) The results are: False 5.170404 5.1704040000000004 5.1704039999999995558255250216461718082427978515625 5.17040400000000044400394472177140414714813232421875 (The "r" specifier is "round-trip" - parsing the result should always give the same double back.) It looks to me like the compiler has done a better job - its value is closer to 5.170404 than the value returned by Convert.ToDouble. -- Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too |
|||||||||||||||||||||||