455,462 Members | 1,369 Online Need help? Post your question and get tips & solutions from a community of 455,462 IT Pros & Developers. It's quick & easy.

# Bug in Framework on Double arithmetic...?

 P: n/a Hi all, I'm facing a strang issue doing calculation on Double values. I read some thread on the newsgroups warning about type translations (eg Single to Double), but here I'm doing no conversion at all. The issue I'm facing looks so basic but I'm really lost... I'm doing all my calculations in Double, and the results are not correct. Did I miss something? double a, b; a = 4.5d; b = a + 0.10d; Console.WriteLine(ee == 4.6d); // returns true b = a + 0.20d; Console.WriteLine(ee == 4.7d); // returns true b = a + 0.10d + 0.10d; Console.WriteLine(ee == 4.7d); // returns false !!! b = a + 0.30d; Console.WriteLine(ee == 4.8d); // returns true b = a + 0.10d + 0.10d + 0.10d; Console.WriteLine(ee == 4.8d); // same: returns false Many thanks in advance for your help, Best regards, Lionel Aulofee supervision systems (http://www.aulofee.com) * security and log correlation * IT asset management and inventory * reporting * network cartography May 16 '06 #1
8 Replies

 P: n/a Lionel wrote: Hi all, I'm facing a strang issue doing calculation on Double values. I read some thread on the newsgroups warning about type translations (eg Single to Double), but here I'm doing no conversion at all. The issue I'm facing looks so basic but I'm really lost... I'm doing all my calculations in Double, and the results are not correct. Did I miss something? double a, b; a = 4.5d; b = a + 0.10d; Console.WriteLine(ee == 4.6d); // returns true Lucky. b = a + 0.20d; Console.WriteLine(ee == 4.7d); // returns true Lucky again! b = a + 0.10d + 0.10d; Console.WriteLine(ee == 4.7d); // returns false !!! Not surprising. b = a + 0.30d; Console.WriteLine(ee == 4.8d); // returns true b = a + 0.10d + 0.10d + 0.10d; Console.WriteLine(ee == 4.8d); // same: returns false Many thanks in advance for your help, Short answer: Don't use floating point types for exact calculation. In particular, don't ever use == with floating point types. Slightly longer answer: If you are using quantities best represented by floating point types (and numbers such as 0.1, 4.6, are not), and you want to compare equality, decide on some small epsilon which for your application can mean 'close enough'; and then say two floating point quantites are equal if they are within epsilon of each other. eg: static const double epsilon = 0.0001d; static bool CloseEnough(double d1, double d2) { return (Math.Abs(d1 - d2) < epsilon); } Here's the C# for my favorite example for why floating point is inappropriate for exact quantities: Console.WriteLine((0.1d + 0.1d + 0.1d - 0.3d)); Try it! (First guess what you think the output will be of course...) Long answer: Go look up floating point at wikipedia or somewhere :) -- Larry Lard Replies to group please May 16 '06 #2

 P: n/a This is no bug. You can never assume that for example 2.0 + 0.1 == 2.1. floating point numbers are using an approximating internal representation thus you can never rely on exact values but just approximated ones. -- "Lionel" schrieb im Newsbeitrag news:11*********************@j55g2000cwa.googlegro ups.com... Hi all, I'm facing a strang issue doing calculation on Double values. I read some thread on the newsgroups warning about type translations (eg Single to Double), but here I'm doing no conversion at all. The issue I'm facing looks so basic but I'm really lost... I'm doing all my calculations in Double, and the results are not correct. Did I miss something? double a, b; a = 4.5d; b = a + 0.10d; Console.WriteLine(ee == 4.6d); // returns true b = a + 0.20d; Console.WriteLine(ee == 4.7d); // returns true b = a + 0.10d + 0.10d; Console.WriteLine(ee == 4.7d); // returns false !!! b = a + 0.30d; Console.WriteLine(ee == 4.8d); // returns true b = a + 0.10d + 0.10d + 0.10d; Console.WriteLine(ee == 4.8d); // same: returns false Many thanks in advance for your help, Best regards, Lionel Aulofee supervision systems (http://www.aulofee.com) * security and log correlation * IT asset management and inventory * reporting * network cartography May 16 '06 #3

 P: n/a Larry Lard wrote: Here's the C# for my favorite example for why floating point is inappropriate for exact quantities: Console.WriteLine((0.1d + 0.1d + 0.1d - 0.3d)); Try it! (First guess what you think the output will be of course...) Hmm... despite understanding floating point reasonably well, I'd expected that to be 0. No calculations are done in the above code at runtime - it's all done by the compiler. I'd expect the compiler to be smart enough to sort out constant expressions somewhat better. I must look at what the language spec says... -- Jon Skeet - http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too May 16 '06 #4

 P: n/a > Larry Lard wrote: Here's the C# for my favorite example for why floating point is inappropriate for exact quantities: Console.WriteLine((0.1d + 0.1d + 0.1d - 0.3d)); Try it! (First guess what you think the output will be of course...) Hmm... despite understanding floating point reasonably well, I'd expected that to be 0. No calculations are done in the above code at runtime - it's all done by the compiler. I'd expect the compiler to be smart enough to sort out constant expressions somewhat better. I must look at what the language spec says... Wouldn't the compiler just perform that same calculation internally, using the exact same "roundoffs", and so ending up with the same result as the resulting program would get it *that* performed the calculation? A quick test: Console.WriteLine((0.1d + 0.1d + 0.1d - 0.3d)); double d1 = 0.1d; double d2 = 0.3d; Console.WriteLine((d1 + d1 + d1 - d2)); resulted in twice 5,55111512312578E-17 Hans Kesting May 16 '06 #5

 P: n/a Hans Kesting wrote: Hmm... despite understanding floating point reasonably well, I'd expected that to be 0. No calculations are done in the above code at runtime - it's all done by the compiler. I'd expect the compiler to be smart enough to sort out constant expressions somewhat better. I must look at what the language spec says... Wouldn't the compiler just perform that same calculation internally, using the exact same "roundoffs", and so ending up with the same result as the resulting program would get it *that* performed the calculation? Not necessarily. It appears to in this case, but I wouldn't have been surprised to find that the compiler could work to a higher precision (or use decimal arithmetic) in order to evaluate constant expressions. You piqued my curiosity though, so I've checked with the spec, and indeed: The compile-time evaluation of constant expressions uses the same rules as run-time evaluation of non-constant expressions, except that where run-time evaluation would have thrown an exception, compile-time evaluation causes a compile-time error to occur. That seems to be a reasonable description of the observed behaviour. -- Jon Skeet - http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too May 16 '06 #6

 P: n/a Jon Skeet [C# MVP] checked with the spec: The compile-time evaluation of constant expressions uses the same rules as run-time evaluation of non-constant expressions, except that where run-time evaluation would have thrown an exception, compile-time evaluation causes a compile-time error to occur. That seems to be a reasonable description of the observed behaviour. IMO a very reasonable behavior. Compile-time evaluation should be transparent. I'd hate to see the behavior of my program change just because I changed a constant to a parameter with the same value. Ole N. May 16 '06 #7

 P: n/a Ole Nielsby wrote: That seems to be a reasonable description of the observed behaviour. IMO a very reasonable behavior. Compile-time evaluation should be transparent. I'd hate to see the behavior of my program change just because I changed a constant to a parameter with the same value. Well, there can be changes in terms of string handling, certainly. For instance: string x = "hello Jon"; string y = "hello "+"Jon"; string name = "Jon"; string z = "hello "+name; x and y are guaranteed to be references to the same object. z is guaranteed to be different. -- Jon Skeet - http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too May 16 '06 #8

 P: n/a This is not a .NET thing. This is universal across all languages (that I've ever worked in) and all chipsets (that I've ever worked on). Floating point numbers cannot be represented exactly. They are all very accurate approximations. So, as you do arithmetic with them... even apparently simple arithmetic, you introduce small amounts of error. There is an entire area of computing, called Numerical Analysis, that studies how various algorithms affect floating point error (either accentuating it or damping it). However, at the very least, you can never count on two floating point quantities that "should be" equal being in fact equal. As Larry pointed out, if you want to compare floating point quantities for "equality" you must choose a minimum tolerance for error (aka an "epsilon") and compare using that. This is, incidentally, why you should never use floating point (ie float or double) to represent monetary values. You should always use the Decimal type. I believe that Decimal is considerably less efficient than float or double (I could be wrong), but it does make stronger guarantees about accuracy. double and float are generally used for mathematical calculations such as work in engineering or the sciences, statistical analysis, etc. decimal is more generally used in business, where you can't just "lose a penny" here and there and get away with it. May 16 '06 #9

### This discussion thread is closed

Replies have been disabled for this discussion. 