Very simple code, but program freezes every time

Oct 29, 2013 at 8:09pm
Hi!

I'm trying to answer a very simple mathematical question by a program. The question is:
There's a family of 20 people. They all work. Women gain 30$/hour, men, 15$/hour and kids, 5$/hour. If the whole family wins 200$/hour, how many women, men and kids are they?

I've written this code, thinking it would work immediately, but everytime I compile it, I get a message from Windows saying the program stopped working. I tried to do the program without the randomize (I removed the money condition) and it worked well, so I think the problem is from the randomization, but I just can't find it. Here's the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;


int main()
{
    srand( time( NULL ) );
    int money=0;
    int men=0;
    int women=0;
    int kids=0;
while (money!=200)
    {
       women=rand() % (20 - 1 ) + 1;
       men=rand() % (20-women-1)+1;
       kids=rand()%(20-women-men-1)+1;
       money=30*women+15*men+5*kids;
    }

    cout<<"There are "<<women<<" women, "<<men<<" men and "<<kids<<" kids \n";
    return 0;
}

Thank you!
Oct 29, 2013 at 8:21pm
Probably a divide by zero error. For example, if (20-women-men-1) evaluates as zero, then rand() % 0 will be attempted, and fail.
Oct 29, 2013 at 8:22pm
You only break out of the loop when money is EXACTLY 200... what happens when money jumps from 180 to, say 250? Your loop will keep going.

Perhaps you should end the loop when money is greater than or equal to 200?

@Chervil
I didn't think about that. I figured he was eventually triggering some sort of overflow by running that loop too long. I ran it through the VS2010 debugger and the div by zero is exactly what happened.

@OP The solution I suggested would have not exposed the bug Chervil mentions, since it happened when money == 255. Definitely fix the bug along with your loop condition.
Last edited on Oct 29, 2013 at 8:26pm
Oct 29, 2013 at 8:24pm
You're solving this problem by jumping around with rand() rather than going through the list of possible combinations of women, men, and children (Side note, women gain more than men and children aren't complete money sinks? Where can I sign up for this utopia?). Like this, the worst case scenario for your program is that it will never end assuming it didn't crash.

Three loops would work better than one loop and three rands.

-Albatross
Last edited on Oct 29, 2013 at 8:26pm
Oct 29, 2013 at 8:26pm
This is a good exercise for learning how to use the debugger.

I ran your code and experienced the crash. Fortunately, I was running the debugger so when it crashed I was able to see at which line it occurred and the value of each variable.

For me it crashed on line 19.

women = 16, men = 3.

Now if I look at this I see:
1
2
3
4
kids = rand() % (20 - women - men - 1) + 1;
kids = rand() % (20 - (16) - (3) - 1) + 1;
kids = rand() % (20 - 20) + 1;
kids = rand() % (0) + 1;


And that's where our problem is. Try running this application:
1
2
3
4
int main() {
    int a = 5 % 0;
    return 0;
}


You'll see the same crash. You need to avoid the condition where you %0.
Oct 29, 2013 at 8:30pm
Thank you for all the replies! I'll try a different code and avoid the %0.
Oct 29, 2013 at 8:48pm
Just one comment. Is there more than one possible solution, and if so do you need to list them all?
Oct 29, 2013 at 9:13pm
I don't think there are multiple solutions, but I absolutely need to find a combination that gives 200$.
Oct 29, 2013 at 9:23pm
Just a suggestion, it's still not the most efficient way to do this calculation, but instead of using random combinations, try systematically iterating through each set of combinations until you find one or more solutions. This way you are sure not to get the combination over and over and you will eventually find the solution if there is one.

Example:
1
2
3
4
5
6
7
8
9
10
11
const int ppl = 20;
for (int men = 0; men <= ppl; ++men)
{
  for (int women = 0; women <= ppl - men; ++women)
  {
    int kids = ppl - men - women;
    int money=30*women+15*men+5*kids;
    if (money == 200)
      cout<<"There are "<<women<<" women, "<<men<<" men and "<<kids<<" kids \n";
  }
}


Edit: There is one solution that has men, women and children. There are three solutions if 0 is a valid number of one type of person.
Last edited on Oct 29, 2013 at 9:27pm
Oct 29, 2013 at 9:41pm
@Stewbond Thanks for the suggestion and the code! I also think it's a better idea to not use random numbers, as it gets very complicated (for a beginner like me)
Oct 29, 2013 at 9:50pm
For the one solution
if (money==200&&kids!=0&&women!=0&&men!=0)
Oct 29, 2013 at 10:03pm
If you want the non-zero solution, you could modify the code from Stewbond above so the loops start from 1 rather than 0 and end 2 or 1 iterations short of the current limits, to allow there to be always at least 1 of each category. That cuts down the total iterations from 231 to 171, though it runs very quickly in either case.
Oct 29, 2013 at 10:16pm
Good! Thanks @Chriscpp and @Chervil!
Topic archived. No new replies allowed.