0

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.

mskfisher
  • 3,291
  • 4
  • 35
  • 48
Iain
  • 9,432
  • 11
  • 47
  • 64

5 Answers5

17

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:

Cyril Gandon
  • 16,830
  • 14
  • 78
  • 122
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • so 1.490116E-08 is just a really small number but not zero die to rounding error? how do i solve? – Iain Jan 25 '09 at 23:04
  • 1
    use `decimal`, round to a known decimal place, or test equality / difference against a small range as "close enough" – Marc Gravell Jan 25 '09 at 23:06
  • 2
    Tcha. How am I meant to get rep when I can't even be the first to cite my own articles? ;) – Jon Skeet Jan 25 '09 at 23:07
  • @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 Jan 25 '09 at 23:09
  • 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 Jan 25 '09 at 23:12
  • @George IV - alas, he has written some fairly useful reference articles. – Marc Gravell Jan 25 '09 at 23:12
  • Come on Marc, Jon needs the rep after all – Chris S Jan 25 '09 at 23:13
  • 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 Jan 25 '09 at 23:14
  • @Jon/Chris - I just thought it polite to offer ;-p. – Marc Gravell Jan 25 '09 at 23:16
  • http://www.extremeoptimization.com/resources/Articles/FPDotNetConceptsAndFormats.aspx features somewhere in those links I think too – Chris S Jan 25 '09 at 23:44
12

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.

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
duffymo
  • 305,152
  • 44
  • 369
  • 561
1

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
  • 951,095
  • 183
  • 1,149
  • 1,285
0

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
  • 174,939
  • 50
  • 355
  • 478
0

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
  • 10,054
  • 10
  • 63
  • 85
  • 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 Jan 25 '09 at 23:22
  • 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 Jan 26 '09 at 00:02
  • "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 Jan 30 '09 at 03:51