The methods proposed so far are workable, but tend to produce results that are skewed. For example, forcing the last number to give the correct sum can give you a value that is a long way off the other values (and possibly negative, which might be a problem in some cases). Calculating random values in the range from zero up to the remaining sum will give you a series of numbers that rapidly approach zero.
Instead, to generate n
random numbers from 0
to total
, I would suggest picking n-1
random values in the range from 0
to total
(inclusive). Consider each of these values as the location of a bookmark in a deck of total
cards. If the deck is then separated into n
piles at these bookmarks, then the number of cards in each pile will give you a uniformly distributed set of values that sum to total
.
Here's some code to illustrate the idea (in C, sorry):
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int cmp(const void *a, const void *b) {
return *((int*)a) - *((int*)b);
}
int main(int argc, char *argv[]) {
int nterms, total, x, i, checksum;
int *array;
srand(time(0));
if (argc != 3) return puts("Require 2 arguments: <nterms> and <total>");
nterms = atoi(argv[1]); /* N.B. Input value checks omitted. */
total = atoi(argv[2]); /* Avoid large or negative values! */
/* We want to generate nterms intervals across the range from 0 to */
/* total (inclusive), so we need an array of nterms+1 values to mark */
/* the start and end of each interval. */
array = malloc((nterms+1) * sizeof(int));
/* The first and last items in this list must be zero and total (to */
/* ensure that the list of numbers add up to the correct amount) */
array[0] = 0;
array[nterms] = total;
/* Fill the rest of the array with random values from 0 to total. */
for (i=1; i<nterms; i++) {
array[i] = rand() % (total+1);
}
/* Sort these values in ascending order. */
qsort(array, nterms+1, sizeof(int), cmp);
/* Our list of random numbers can now be calculated from the */
/* difference between each pair of values in this list. */
printf("Numbers:");
for (i=checksum=0; i<nterms; i++) {
x = array[i+1] - array[i];
checksum += x;
printf(" %d", x);
}
printf("\nTotal: %d\n", checksum);
return 0;
}