|
dev
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Addition error in DotNet 2.0Hi all,
Wondering if someone can help me with this: when i'm in Visual Studio 2005 I get a wierd addition error when adding 0.1+0.2 (both as doubles) the result that comes back is 0.30000000000000004 not 0.3 as expected. Any ideas what's causing this or what's wrong? A few results: 0.1+0.2 0.30000000000000004 double 0.1+0.2+0.1+0.2 0.60000000000000009 double 0.1+0.3 0.4 double 0.2+0.3 0.5 double Somewhere in your code, you are using floats, not doubles.
Try the following in a console app (C#): static void Main(string[] args) { double a = 0.1; double b = 0.2; double c = a + b; double d = 0.1 + 0.2; float e = 0.1f; float f = 0.2f; double g = e + f; Console.WriteLine("a={0}", a); Console.WriteLine("b={0}", b); Console.WriteLine("c={0}", c); Console.WriteLine("d={0}", d); Console.WriteLine("e={0}", e); Console.WriteLine("f={0}", f); Console.WriteLine("g={0}", g); Console.Read(); } -- Show quoteGregory A. Beamer MVP; MCP: +I, SE, SD, DBA *************************** Think Outside the Box! *************************** "Owen" wrote: > Hi all, > Wondering if someone can help me with this: > > when i'm in Visual Studio 2005 I get a wierd addition error when adding > 0.1+0.2 (both as doubles) > > the result that comes back is 0.30000000000000004 not 0.3 as expected. Any > ideas what's causing this or what's wrong? > > A few results: > 0.1+0.2 0.30000000000000004 double > 0.1+0.2+0.1+0.2 0.60000000000000009 double > 0.1+0.3 0.4 double > 0.2+0.3 0.5 double > > > Nope.
still not right. the console outputs correct but the underlying numbers are wrong which fails the unit testing in my application. Check out this screen shot: http://www.bgeek.net/photos/d/3559-2/screen.jpg Cheers Owen Evans Cowboy - MVP (Gregory A. Beamer) wrote:
> Somewhere in your code, you are using floats, not doubles. I think you'll find that the default formatting is leading you astray.Show quote > This prints 0.3, yes, but c is not 0.3. Try> Try the following in a console app (C#): > > static void Main(string[] args) > { > double a = 0.1; > double b = 0.2; > double c = a + b; > double d = 0.1 + 0.2; > float e = 0.1f; > float f = 0.2f; > double g = e + f; > > > Console.WriteLine("a={0}", a); > Console.WriteLine("b={0}", b); > Console.WriteLine("c={0}", c); Console.WriteLine("c={0}", c-0.3); > Console.WriteLine("d={0}", d); Doing the addition at compile time doesn't help, either, tryConsole.WriteLine("d={0}", d-0.3); > Console.WriteLine("e={0}", e); It's only apparent in this example with float and not double because> Console.WriteLine("f={0}", f); > Console.WriteLine("g={0}", g); double's default ToString rounds to a point which hides the discrepancy, but float's doesn't (it has a bigger disrecpancy too). > Console.Read(); In any event, more digits of precision would just be a palliative -> } better to fix the real problem, and use an exact type (as I'm sure you are aware). -- Larry Lard Replies to group please When starting a new topic, please mention which version of VB/C# you are using Owen wrote:
> Hi all, Your expectations are wrong.> Wondering if someone can help me with this: > > when i'm in Visual Studio 2005 I get a wierd addition error when > adding > 0.1+0.2 (both as doubles) > > the result that comes back is 0.30000000000000004 not 0.3 as > expected. Any ideas what's causing this or what's wrong? The numbers 0.1 and 0.2 do not have exact representations in binary floating point - which is what .NET uses for floats and doubles. Consequently, when you add a number very close to 0.1 to a number very close to 0.2, the best you can hope for is a number very close to 0.3. Four double, which you're apparently using here, you can expect about 17 digits of accuracy. When comparing floating point numbers for "equality", you should always compare for equality wiithin some small range, e.g. instead of x == y, use Math.Abs(x-y) < 0.0000000001. When displaying floating point numbers, you should always specify how many digits after the decimal point, according to your needs. If you need to be able to add 0.1 to 0.2 and get exactly 0.3 (e.g. you're doing financial calculations), then you should use the System.Decimal type instead. It is a decimal floating point number and can represent negative powers of 10 (e.g. 0.1) exactly. Be aware though - decimal is orders of magnitude slower than double, so unless you really need absolute decimal accuracy, you're probably better off using double. You should also take a look at the paper at the following url. It goes into the details of working with binary floating point numbers in great detail. http://docs.sun.com/source/806-3568/ncg_goldberg.html -cd Ok that explains why it's happening. but why is it different for 2003 and
2005? the unit tests used to pass in 2003, but now fail. And it's only for these numbers ie if i change it to (double)0.1+(double)0.3 i get 0.4 and this passes an nunit.Assert.AreEqual test. Cheers OWen Evans Owen wrote:
> Ok that explains why it's happening. but why is it different for 2003 and Well, when I ask the immediate window in VS2003 and VS2005> 2005? the unit tests used to pass in 2003, but now fail. ?0.1+0.2-0.3 both times it tells me 0.000000000000000055511151231257827. I would be surprised if the details of the Framework's floating point implementation had changed, but they would be perfectly within their rights to do so, so long as they still met all the relevant contracts. By the way, thanks for the example - I always used to use 0.1+0.1+0.1-0.3 evaluating to not zero as my 'pet teaching example' of why not to use floating point types for exact calculations, but 0.1+0.2-0.3 not being zero is, I think, a little better. -- Larry Lard Replies to group please Owen <O***@discussions.microsoft.com> wrote:
> Ok that explains why it's happening. but why is it different for 2003 and You should always express this sort of test with a tolerance - i.e. > 2005? the unit tests used to pass in 2003, but now fail. And it's only for > these numbers ie if i change it to (double)0.1+(double)0.3 i get 0.4 and this > passes an nunit.Assert.AreEqual test. specify a range of values for which the test will pass. For more information about floating point, along with a way of finding the exact value of a floating point number (i.e. getting rid of formatting rounding etc) see http://www.pobox.com/~skeet/csharp/floatingpoint.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 Owen wrote:
> Ok that explains why it's happening. but why is it different for 2003 The "why" is easy: you were lucky (or perhaps it's unlucky).> and 2005? the unit tests used to pass in 2003, but now fail. And it's > only for these numbers ie if i change it to (double)0.1+(double)0.3 i > get 0.4 and this passes an nunit.Assert.AreEqual test. -cd Has anyone actually tested Decimal vs. Double. The reason I ask is that
both data types are implemented in the x87 FPU hardware (built into the 80486 and later) and have about the same clock cycle requirements. Mike Ober. Show quote "Carl Daniel [VC++ MVP]" <cpdaniel_remove_this_and_nospam@mvps.org.nospam> wrote in message news:eWlNR30pGHA.4760@TK2MSFTNGP05.phx.gbl... > Owen wrote: > > Hi all, > > Wondering if someone can help me with this: > > > > when i'm in Visual Studio 2005 I get a wierd addition error when > > adding > > 0.1+0.2 (both as doubles) > > > > the result that comes back is 0.30000000000000004 not 0.3 as > > expected. Any ideas what's causing this or what's wrong? > > Your expectations are wrong. > > The numbers 0.1 and 0.2 do not have exact representations in binary floating > point - which is what .NET uses for floats and doubles. Consequently, when > you add a number very close to 0.1 to a number very close to 0.2, the best > you can hope for is a number very close to 0.3. Four double, which you're > apparently using here, you can expect about 17 digits of accuracy. > > When comparing floating point numbers for "equality", you should always > compare for equality wiithin some small range, e.g. instead of x == y, use > Math.Abs(x-y) < 0.0000000001. > > When displaying floating point numbers, you should always specify how many > digits after the decimal point, according to your needs. > > If you need to be able to add 0.1 to 0.2 and get exactly 0.3 (e.g. you're > doing financial calculations), then you should use the System.Decimal type > instead. It is a decimal floating point number and can represent negative > powers of 10 (e.g. 0.1) exactly. Be aware though - decimal is orders of > magnitude slower than double, so unless you really need absolute decimal > accuracy, you're probably better off using double. > > You should also take a look at the paper at the following url. It goes into > the details of working with binary floating point numbers in great detail. > > http://docs.sun.com/source/806-3568/ncg_goldberg.html > > -cd > > Michael D. Ober wrote:
> Has anyone actually tested Decimal vs. Double. The reason I ask is The decimal type is not implemented by the x87 FPU 0 or at least not > that both data types are implemented in the x87 FPU hardware (built > into the 80486 and later) and have about the same clock cycle > requirements. directly. The .NET System.Decimal type is a wrapper around the OLE VAR_DECIMAL type and is implemented by ole32.dll (IIRC). Whether the decimal support library makes use of the x87 decimal type I do not know. If it does, it'd have to be doing format conversion, because the x87 decimal stores the mantissa as BCD (decimal digit per nibble), while the .NET decimal type stores the mantissa as a 96-bit unsigned binary integer. My guess would be that it doesn't make use of the x87 decimal type at all. -cd Thanks.
Mike. Show quote "Carl Daniel [VC++ MVP]" <cpdaniel_remove_this_and_nospam@mvps.org.nospam> wrote in message news:%23mbsIJVqGHA.3484@TK2MSFTNGP04.phx.gbl... > Michael D. Ober wrote: > > Has anyone actually tested Decimal vs. Double. The reason I ask is > > that both data types are implemented in the x87 FPU hardware (built > > into the 80486 and later) and have about the same clock cycle > > requirements. > > The decimal type is not implemented by the x87 FPU 0 or at least not > directly. > > The .NET System.Decimal type is a wrapper around the OLE VAR_DECIMAL type > and is implemented by ole32.dll (IIRC). Whether the decimal support library > makes use of the x87 decimal type I do not know. If it does, it'd have to > be doing format conversion, because the x87 decimal stores the mantissa as > BCD (decimal digit per nibble), while the .NET decimal type stores the > mantissa as a 96-bit unsigned binary integer. My guess would be that it > doesn't make use of the x87 decimal type at all. > > -cd > > > That is how "double" type works. See .NET framework document. It is the same
to other language where "duoble" or similar floating type is implemented. I have been seeing the same or similar questions appearing in NGs for classical VB every other week or so in many years. If the rounding precision is an issue to your app, you might want to consider to use "decimal" type instead of "double" or "single". Show quote "Owen" <O***@discussions.microsoft.com> wrote in message news:433D0159-BBA9-4B70-9390-41B955D0D875@microsoft.com... > Hi all, > Wondering if someone can help me with this: > > when i'm in Visual Studio 2005 I get a wierd addition error when adding > 0.1+0.2 (both as doubles) > > the result that comes back is 0.30000000000000004 not 0.3 as expected. > Any > ideas what's causing this or what's wrong? > > A few results: > 0.1+0.2 0.30000000000000004 double > 0.1+0.2+0.1+0.2 0.60000000000000009 double > 0.1+0.3 0.4 double > 0.2+0.3 0.5 double > > > |
|||||||||||||||||||||||