Home All Groups Group Topic Archive Search About

Addition error in DotNet 2.0

Author
14 Jul 2006 11:25 AM
Owen
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

Author
14 Jul 2006 12:44 PM
Cowboy (Gregory A. Beamer) - MVP
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();
}


--
Gregory A. Beamer
MVP; MCP: +I, SE, SD, DBA

***************************
Think Outside the Box!
***************************


Show quoteHide quote
"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
>
>
>
Are all your drivers up to date? click for free checkup

Author
14 Jul 2006 1:03 PM
Owen
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
Author
14 Jul 2006 3:12 PM
Larry Lard
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 quoteHide quote
>
> 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);

This prints 0.3, yes, but c is not 0.3. Try

     Console.WriteLine("c={0}", c-0.3);

>     Console.WriteLine("d={0}", d);

Doing the addition at compile time doesn't help, either, try

     Console.WriteLine("d={0}", d-0.3);

>     Console.WriteLine("e={0}", e);
>     Console.WriteLine("f={0}", f);
>     Console.WriteLine("g={0}", g);

It's only apparent in this example with float and not double because
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
Author
14 Jul 2006 2:00 PM
Carl Daniel [VC++ MVP]
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
Author
14 Jul 2006 2:10 PM
Owen
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
Author
14 Jul 2006 3:07 PM
Larry Lard
Owen wrote:
> 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.

Well, when I ask the immediate window in VS2003 and VS2005

?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
Author
16 Jul 2006 7:13 AM
Jon Skeet [C# MVP]
Owen <O***@discussions.microsoft.com> wrote:
> 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.

You should always express this sort of test with a tolerance - i.e.
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
Author
16 Jul 2006 2:14 PM
Carl Daniel [VC++ MVP]
Owen wrote:
> 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.

The "why" is easy:  you were lucky (or perhaps it's unlucky).

-cd
Author
17 Jul 2006 2:27 AM
Michael D. Ober
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 quoteHide 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
>
>
Author
17 Jul 2006 3:37 AM
Carl Daniel [VC++ MVP]
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
Author
17 Jul 2006 4:21 AM
Michael D. Ober
Thanks.

Mike.

Show quoteHide 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
>
>
>
Author
14 Jul 2006 2:14 PM
Norman Yuan
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 quoteHide 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
>
>
>

Bookmark and Share