views:

1173

answers:

5

What's going on?! Subtraction works fine until I get to 0.1 - 0.1. I'm in visual c# 2008 using the nonoba.com API.

Console.WriteLine("hit! " + Users[targetNum].character.health + " : " + player.character.profile.attackPower);

Users[targetNum].character.health -= player.character.profile.attackPower;

Console.WriteLine("health! " + Users[targetNum].character.health);

output:

hit! 0.1 : 0.1
health! 1.490116E-08

Thanks all - I might use the decimal type, as I'm normally adding/subtracting nice "round" numbers. For now I'll just go with:

if (Users[targetNum].character.health <= 0.00001)

By the way I knew this wasn't really going to be a "bug" in c# - I thought it would either by a bug in my code or some lack of understanding, which it was.

Having read all the recommended reading, I'm going to conclude that my folly was due to normally using the ActionScript Number type, which maybe has a decimal rather than binary floating point - anyway, it would never give this output.

+15  A: 

That seems pretty normal for floating point math... you always have to check against a small delta to account for imperceptible rounding differences. Depending on the scenario, decimal might be what you want.

Basically, unless you can be sure that it is exactly the same 0.1 in both cases (i.e. nothing has been done to them), you aren't likely to get zero; in general you'll get something very nearly zero. With decimal you'll usually get more what you expect intuitively.

See also Jon Skeet's pages here:

Marc Gravell
so 1.490116E-08 is just a really small number but not zero die to rounding error? how do i solve?
Iain
use `decimal`, round to a known decimal place, or test equality / difference against a small range as "close enough"
Marc Gravell
Tcha. How am I meant to get rep when I can't even be the first to cite my own articles? ;)
Jon Skeet
@Jon - sorry, but at least I cited them fairly... if you want, I'll take off the links and you can post them? (sounds fair...)
Marc Gravell
haha I love how the answer involves Jon Skeet.. +1!
geowa4
If you really think I care that much about rep, I'm very disappointed. (Not that votes would give me rep right now anyway.) I feel honoured any time an article is linked (and I have an immediate fear that I need to check and revise it...)
Jon Skeet
@George IV - alas, he has written some fairly useful reference articles.
Marc Gravell
Come on Marc, Jon needs the rep after all
Chris S
I know. I just find it funny, especially after reading that Chuck Norris like question on SO. (And I know you just want to help John)
geowa4
@Jon/Chris - I just thought it polite to offer ;-p.
Marc Gravell
http://www.extremeoptimization.com/resources/Articles/FPDotNetConceptsAndFormats.aspx features somewhere in those links I think too
Chris S
+11  A: 

You obviously need to read "What Every Computer Scientist Should Know About Floating Point Numbers".

Instead of thinking that I've found a bug in situations like this, I usually assume that one of my assumptions needs checking first.

duffymo
A: 

Floating point math is always approximate, in any language, because that's how CPUs work. If you care about the absolute precision of your answers - for example, because you're dealing with money - then you shouldn't use floating point.

Marcus Downing
It really depends on what you mean by "precise". I suspect you'd recommend using System.Decimal, despite the fact that that's a floating point type too. It's just we have different expectations of decimal numbers, and System.Decimal has a floating *decimal* point.
Jon Skeet
Actually, for cases of money, I'd likely use an integer to store the number of cents, unless it was one of the rare cases where you need to be working with fractions of those too. In other cases, then maybe.
Matthew Scharley
"I suspect you'd recommend using System.Decimal" -- except I use Java :) . For money I rolled my own classes wrapped around integers. In the database, I actually store them as strings, eg "GBP:499.99", so there's no chance of ambiguity.
Marcus Downing
+1  A: 

If you're always adding and subtracting "nice round" numbers, that is tenths or hundredths, then you can keep track of your hit and health values in integer tenths-of-units. An analogy is a financial program that keeps track of money in integer cents, instead of floating point dollars. Using integers avoids all the problems of floating point math.

Greg Hewgill
A: 

Slighly offtopic, but here's an interesting read that describes why cos(x) != cos(y) can be true even if x == y:

http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.18

Thomas