0

Possible Duplicate:
Why is floating point arithmetic in C# imprecise?
Why can't decimal numbers be represented exactly in binary?

I dont understand why, this formula works untill Scrap = 51, Rec Should be 17 but instead is 16.99.

Scrap = int.Parse(textBoxS.Text);

for (counter = 0; counter < Scrap; textBoxRec.Text = Rec.ToString() )
{
    if (Rec == (int)Rec + 0.66)
    {
        Rec = (int)Rec + 1;
        counter++;
    }
    else
    {
        Rec = Rec + 0.33;
        counter++;
    }
}
Community
  • 1
  • 1
  • 1
    This is essentially a floating point precision question. Please see http://stackoverflow.com/questions/1089018/why-cant-decimal-numbers-be-represented-exactly-in-binary – mtrw Aug 22 '12 at 09:11
  • 1
    Where is "Rec" defined, and what were all the starting values? – BugFinder Aug 22 '12 at 09:11
  • Can you give us the formula you're calculating by? – Sergei Rogovtcev Aug 22 '12 at 09:12
  • looking for this `counter <= Scrap` ? – Renatas M. Aug 22 '12 at 09:13
  • 1
    That "formula" (for division by three, I'd assume) looks weird... What's wrong with just saying `Rec += Scrap / 3;`? That's what the division operators are for, after all... – Nuffin Aug 22 '12 at 09:14
  • 3
    [What Every Computer Scientist Should Know About Floating-Point Arithmetic](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html). – Oded Aug 22 '12 at 09:14
  • Thank you all for you answers as they were all helpful in improving my code, thanks it works perfectly now, as u can see im new to C# – tuckismad Aug 22 '12 at 09:19
  • If anybody is interested in the details: The reason this works until Rec is 15 but not when Rec is 16 (presumably when Scrap is 51) is that the low five bits in the significand of .33 are 11111, but the next higher bit is 0. For values of Rec under 16, fewer than six bits are pushed out of the significand, causing rounding up. When Rec is 16, adding .33 pushes six bits out and rounds down (each of the two times .33 is added). Adding .66 pushes five bits out and rounds up. So, at that point, adding .33 twice differs from adding .66. – Eric Postpischil Aug 22 '12 at 12:31

4 Answers4

3

Comparing floating point numbers by == is never a good idea.

double d1 = 16.0 + 0.33 + 0.33
double d2 = 16.0 + 0.66

Then d1 != d2, since 0.33 does not have an exact representation as a double, since double is a binary floating point number and probably the double representation of 0.66 is different from two times the double representation of 0.33.

Use decimal.

And try to improve your code. Increasing the counter inside the loop and using the third position in the head of the for loop for a different purpose is horrible style, in my opinion.

JohnB
  • 13,315
  • 4
  • 38
  • 65
  • 2
    The binary floating-point representation of .66 is not different from the representation of 2 times .33. It is **binary** floating-point; a factor of two merely increments the exponent, and the significand is rounded identically. Additionally, it is neither a difference between .66 and 2*.33 nor the fact that .33 is not exactly representable that causes 16+.33+.33 to differ from 16+.66. The reason there is a difference is that, when 16+.33 is calculated, there is a rounding, which does not occur when a single .66 is added to 16. (E.g., 16+(.33+.33) would equal 16+.66.) – Eric Postpischil Aug 22 '12 at 11:42
0

I assume that Rec is double and its initial value is 0. than

Insted of

if (Rec == (int)Rec + 0.66)

use

 if (Math.Abs(Rec-(int)Rec-0.66) < 0.001)
user854301
  • 5,383
  • 3
  • 28
  • 37
0

Simple solution: change Rec from double to decimal. If so, you also have to change 0.66 to 0.66m and 0.33 to 0.33m.

Maarten
  • 22,527
  • 3
  • 47
  • 68
-1

Rec == (int)Rec + 0.66 can be false even if numbers are "equal". It is related to floating point numbers binary representation. Floating point numbers must be compared in slightly different way:

if (Math.Abs(Rec - ((int) Rec + 0.66)) < epsilon) ...

where epsilon is some small value, in this case 0.1 will be enough.