How to generate random positive integers that sum to N in C

1 Answer

0 votes
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/*
    Generate k random positive integers that sum to n.

    Algorithm (stick‑breaking / random composition):
    ------------------------------------------------
    1. Choose (k - 1) random cut points in the range [1, n - 1].
       These represent where we "break" the integer n into k parts.

    2. Sort the cut points.

    3. Compute the differences between consecutive points
       (including 0 and n as boundaries). These differences
       are the k positive integers that sum to n.

    This produces a uniformly random composition of n.
*/

/*
    Paper Run (Dry Run) of the Random-Sum Program
    ---------------------------------------------

    Input:
        n = 50
        k = 7

    We need (k - 1) = 6 random cut points in the range [1, 49].

    Simulated rand() outputs (rand() % 49):
        12, 3, 40, 25, 7, 33

    After adding +1 (because the code uses 1 + rand() % (n - 1)):
        cuts = {13, 4, 41, 26, 8, 34}

    Step 1: Sort the cut points
        cuts → {4, 8, 13, 26, 34, 41}

    Step 2: Convert cut points into segment lengths
        prev = 0

        out[0] = 4  - 0  = 4
        prev = 4

        out[1] = 8  - 4  = 4
        prev = 8

        out[2] = 13 - 8  = 5
        prev = 13

        out[3] = 26 - 13 = 13
        prev = 26

        out[4] = 34 - 26 = 8
        prev = 34

        out[5] = 41 - 34 = 7
        prev = 41

        out[6] = 50 - 41 = 9   (final segment)

    Final result:
        parts = {4, 4, 5, 13, 8, 7, 9}

    Verification:
        4 + 4 + 5 + 13 + 8 + 7 + 9 = 50

    Output:

        Random parts that sum to 50:
        4 4 5 13 8 7 9
        Sum = 50
*/

/* qsort comparator for integers */
int cmp_int(const void *a, const void *b) {
    return (*(int*)a - *(int*)b);
}

/* Generate k random positive integers that sum to n */
void generate_random_sum(int n, int k, int *out) {
    if (k <= 0 || n < k) {
        /* k positive integers must sum to n → minimum sum is k */
        fprintf(stderr, "Invalid n or k\n");
        exit(1);
    }

    int *cuts = malloc((k - 1) * sizeof(int));
    if (!cuts) {
        fprintf(stderr, "Memory allocation failed\n");
        exit(1);
    }

    /* Seed RNG with current time */
    srand((unsigned)time(NULL));

    /* Generate (k - 1) random cut points */
    for (int i = 0; i < k - 1; ++i) {
        cuts[i] = 1 + rand() % (n - 1);  /* uniform in [1, n-1] */
    }

    /* Sort the cut points */
    qsort(cuts, k - 1, sizeof(int), cmp_int);

    int prev = 0;

    /* Convert cut points into segment lengths */
    for (int i = 0; i < k - 1; ++i) {
        out[i] = cuts[i] - prev;
        prev = cuts[i];
    }

    /* Last segment: from last cut to n */
    out[k - 1] = n - prev;

    free(cuts);
}

int main(void) {
    int n = 50;   /* total sum */
    int k = 7;    /* number of random parts */

    int *parts = malloc(k * sizeof(int));
    if (!parts) {
        fprintf(stderr, "Memory allocation failed\n");
        return 1;
    }

    generate_random_sum(n, k, parts);

    printf("Random parts that sum to %d:\n", n);
    for (int i = 0; i < k; ++i) {
        printf("%d ", parts[i]);
    }
    printf("\n");

    /* Verify sum */
    int sum = 0;
    for (int i = 0; i < k; ++i) sum += parts[i];
    printf("Sum = %d\n", sum);

    free(parts);
    
    return 0;
}


/*
run:

Random parts that sum to 50:
4 1 0 3 8 18 16 
Sum = 50

*/

 



answered Jul 6 by avibootz
edited Jul 6 by avibootz
...