1

I need to make four random generated numbers which sum have to be 100. Those numbers have to be in range from 1 to 100.

How can I do this?

Bernhard Barker
  • 54,589
  • 14
  • 104
  • 138
Alen
  • 1,750
  • 7
  • 31
  • 62

6 Answers6

5

You can generate four random numbers, for example in range 0..100, then rescale them to have 100 as sum:

x_i' = 1 + x_i*96.0/sum

This solution does not provide uniform distribution of {x_i}.

@PeterWood found better answer for this question Random numbers that add to 100: Matlab

Community
  • 1
  • 1
kassak
  • 3,974
  • 1
  • 25
  • 36
  • I don't understand this, can you explain please. – Alen Feb 26 '13 at 12:02
  • `double x1 = random(0, 100); double x2 = random(0, 100); double x3 = random(0, 100); double x4 = random(0, 100); double sum = x1+x2+x3+x4; x1 *= 100.0/sum; x2 *= 100.0/sum; x3 *= 100.0/sum; x4 *= 100.0/sum;` Note: thats just pseudocode – kassak Feb 26 '13 at 12:04
  • correct, but if integers are required, you need to make sure the rounding happens properly. C++ uses floor for integer division, so in a bad case the integers x_i' would sum up to 97 only. Consider the numbers [24.9, 24.9, 24.9, 25.3], as floats they sum up to 100.0, but their integer sum would be 24+24+24+25=97. – Piotr99 Feb 26 '13 at 12:04
  • x_i' = x_i * 100/(x_1 + x_2 + x_3 + x_4) – qPCR4vir Feb 26 '13 at 12:05
  • yep, integer sucks. As a suggestion I may recomend to distribute remainder according to fractional part of a numbers – kassak Feb 26 '13 at 12:11
  • But, they're no longer random. – Peter Wood Feb 26 '13 at 12:36
  • @Peter Wood Distribution would not be uniform, but numbers would be random =) – kassak Feb 26 '13 at 12:43
  • No, they wouldn't. Given any 3 of the numbers you could predict the 4th. They're no longer random. – Peter Wood Feb 26 '13 at 12:49
  • 1
    @PeterWood They **must** add up to 100 (according to the question). So of course you'll be able to predict the 4th. They should be random **subject to** this constraint. – Bernhard Barker Feb 26 '13 at 12:59
  • @PeterWood there is just dependance (x1, x2, x3) -> x4 – kassak Feb 26 '13 at 13:01
  • See answers to [this question](http://stackoverflow.com/q/8064629/1084416) on `matlab`. – Peter Wood Feb 26 '13 at 13:12
  • @PeterWood yep, you are right here, but no one told about distributions. Random numbers with non-uniform distributions stay random. That was just the simpliest way to get random numbers which sum to particular value. But you provided a correct solution. I will append it. – kassak Feb 26 '13 at 13:19
  • I’m sorry to say that this solution is now wrong. These mummer sums 103. You need to replace 99 with 96. – qPCR4vir Feb 27 '13 at 12:13
3

Generate first random number from range 1..97.

Then generate second random number from range 1..(98-first)

Then generate third random number from range 1..(99-(first+last))

Finally set the last number as 100 - (first+second+third)

Spook
  • 25,318
  • 18
  • 90
  • 167
  • 1
    I'm pretty sure that will be an uneven probability distribution, if that's something OP cares about. – Bernhard Barker Feb 26 '13 at 11:53
  • Besides that the OP asked for the range to start at 1, is there any rationale behind the limiting of the ranges instead of just taking three random numbers in the full range? – PlasmaHH Feb 26 '13 at 11:55
  • OP didn't requested specific probability distribution. The fact, that numbers have to sum to 100 is the main reason for inequal distribution, because one big number will always produce another three small ones. – Spook Feb 26 '13 at 11:55
  • @PlasmaHH Let's say, that these three numbers from the full range are 99, 87 and 76, what should be the last one? I wrote a solution, which will work with *any* pseudorandom generator. Imagine a broken one, which always returns a maximum value from the range. If you persistently tried to find three values from the whole range, your program would hang. – Spook Feb 26 '13 at 11:59
  • @Spook: Your method breaks as well, when I have a broken RNG that returns -1. Since you cannot reason about the possible outcomes of broken components, everyone assumes sane components. – MSalters Feb 26 '13 at 19:06
3

If integer in range [1,100] (with obviusly decay to [1,97]) is what you need:

double x1 = random(0, 1); 
double x2 = random(0, 1); 
double x3 = random(0, 1); 
double x4 = random(0, 1); 

double sum = x1+x2+x3+x4; 

int n1 = 1 + x1*96.0/sum; 
int n2 = 1 + x2*96.0/sum; 
int n3 = 1 + x3*96.0/sum; 

int n4 = 100 - n1 - n2 -n3;
qPCR4vir
  • 3,521
  • 1
  • 22
  • 32
  • 1
    Ok... I was writing... deleting – qPCR4vir Feb 26 '13 at 12:02
  • 1
    @Dukeling This is quite common on SO for few people to write similar answers in the same time, I see no reason go give downvote for that. Downvotes are for poor quality answers and this one perfectly answers the question. – Spook Feb 26 '13 at 12:06
  • Upss.. thank to both... I finded the way to salve the answer :-) – qPCR4vir Feb 26 '13 at 12:25
2

Generate the first between 1 and 100-3, the second between 1 and 100-first-2, the third between 1and 100-(first+second)-1 and the fourth = 100-(first+second+third).

Kamouth
  • 134
  • 2
  • 9
0

Nothing in the problem description says that each number has to be in the range of 1 to 100. You could just vary the mod with each pass. Something like:

int sum = 0;
std::vector<int> randomNums();
while (sum != 100) {
    const int randomNum = std::rand() % (99 - sum);
    sum += randomNum
    randomNums.push_back(randomNum);
}
john.pavan
  • 910
  • 4
  • 6
0
Already answered above, but if anyone is looking for a working example to copy and try quickly:

int main()
{
std::vector<int> v1;

int randNum1 = rand()%(97) + 1;
int randNum2 = rand()%(98-randNum1) +1;
int randNum3 = rand()%(99 - (randNum1+randNum2)) +1;
int randNum4 = 100 -(randNum1+randNum2+randNum);

v1.push_back(randNum1);
v1.push_back(randNum2);
v1.push_back(randNum3);
v1.push_back(randNum4);

int sum = 0;
for(const auto &itr : v1)
{
    cout << itr <<endl;
    sum =sum+itr;
}
cout << "sum is : " << sum <<endl;

return 0;

}