0

Here is an excerpt from my code along with output. I've included print statements for debug purposes.

I've printed out all the values the code's if statement should check; they are all correct. The code works correctly for most test cases where checkWeights is added up (for example, with .2, .2, .2, .2). However, in the case of .1, .3, .3, .1, the code prints the Your weight distribution is invalid! message, and it should not. What is going wrong here?

Code:

   checkWeights = checkWeights + weights[i];
   fprintf(stdout, "%lf\n", checkWeights);
   fprintf(stdout, "%lf\n", totalWeight);
   fprintf(stdout, "%d\n", i);
    fprintf(stdout, "%d\n", categories - 1);

   if((i == (categories - 1)) && (checkWeights != totalWeight))
   {
    fprintf(stdout, "\nYour weight distribution is invalid! Try again.\n");
    dataProvided = 0;
    break;
   }
  } 

Output:

How many categories are you currently graded on? 4

These 4 categories account for how much of your grade? (1, .85, .1 etc.) .8

Weight for category 1 (1, .3, .22 etc.): .3
Please enter your score in category 1 (1, .23, .32 etc.): .321
0.300000
0.800000
0
3

Weight for category 2 (1, .3, .22 etc.): .1
Please enter your score in category 2 (1, .23, .32 etc.): .323
0.400000
0.800000
1
3

Weight for category 3 (1, .3, .22 etc.): .3
Please enter your score in category 3 (1, .23, .32 etc.): .232
0.700000
0.800000
2
3

Weight for category 4 (1, .3, .22 etc.): .1
Please enter your score in category 4 (1, .23, .32 etc.): .4534
0.800000
0.800000
3
3

Your weight distribution is invalid! Try again.
cf-
  • 8,598
  • 9
  • 36
  • 58
yaboi
  • 301
  • 1
  • 7
  • 20
  • 1
    Try not make the readers _insane_ by posting an incomprehensible question. If one needs to read over your question more than once, chances are that you need to reconsider how to ask. – devnull Mar 29 '14 at 05:37
  • 1
    Posting more of your code, such as those that read the user input, might be helpful to others. – R Sahu Mar 29 '14 at 06:01

3 Answers3

3

It's because the vast majority of numbers can only be approximated in floating point math like IEEE754. That makes sense since, with 64 bits available, there are at most 264 possible values (less in reality since IEEE754 uses some for special values like infinities and unknowns). But in mathematics, even between zero and one, there are actually in infinite number of values.

For example, 0.5 can be represented but 0.1 will be something like 0.100000001490116119384765625. You can see why this is the case by examining this answer of mine to a related question.

Because of these approximations, if you want to do equality checks, you should simply compare if they're close enough rather than exactly equal.

The easiest way to check for equality for numbers like 0.x is to check if the absolute difference (such as with the fabs() function) is less than, say, 0.00001.

Community
  • 1
  • 1
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
2

You are using == / != / < / > to compare a pair of floating point numbers. This is likely to give you unexpected results.

Read this article for an explanation of the problem and solutions:

But the short explanation is that floating point representations are inexact, and floating point calculations introduce rounding errors. The solution is to test if your numbers are equal using an expression something like this:

    fabs(checkWeights - totalWeight) < 0.00001

or > to test if they are not equal ... within a given threshold of accuracy.


No luck, the problem is that these values need to be the same (checkWeights needs to equal totalWeights to make sure user input is correct)

You are missing the point. The chances are that even if the values entered by the user are exactly right, they still won't add up to exactly the same number. Floating point arithmetic is like that ... see the article.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • how can i remedy this? – yaboi Mar 29 '14 at 05:39
  • I'm gonna try to use >= and <= operators – yaboi Mar 29 '14 at 05:42
  • I tried if((i >= (categories - 1)) && (checkWeights < totalWeight || checkWeights > totalWeight)) – yaboi Mar 29 '14 at 05:44
  • No luck, the problem is that these values need to be the same (checkWeights needs to equal totalWeights to make sure user input is correct) – yaboi Mar 29 '14 at 05:45
  • Yes I saw you updated your post after I commented, sorry. – yaboi Mar 29 '14 at 05:53
  • The problem is not with the `==` or `!=` operator per se. It is with with what you are doing with them. You are getting the "wrong" answer because the numbers are not exactly the same. The difference is less than 0.0000005 ... but it is really there. – Stephen C Mar 29 '14 at 05:53
  • I understand that, I'm trying to use the fabs function to make sure there is little difference, but I'm still out of luck. So far I've tried: if((i == (categories - 1)) && (fabs(checkWeights - totalWeight) < .0001)) and tried varying values of 0's in that last number, I will read further and see what I find. Thanks for the article – yaboi Mar 29 '14 at 05:57
  • You've got the expression wrong for what you are doing. If you want to test for inequality you need to use `>` not `<`. Think about it what the expression says. – Stephen C Mar 29 '14 at 06:01
0

You may not want to use floating point arithmetics, because of approximations. It's common for financial applications to use fixed point arithmetics. I don't think you need "arbitrary precision" arithmetic here.

See this post for more details: Financial formulas with cents and percentages in C++

Community
  • 1
  • 1
Sigi
  • 4,826
  • 1
  • 19
  • 23
  • Yes. But weights are ideally suited to floating point because real world weights are >>never<< exact. (Of course, money is different ... but this isn't money.) – Stephen C Mar 29 '14 at 06:07