How to split a number N into M random positive parts whose sum is exactly N in JavaScript

1 Answer

0 votes
/*
    Split a number N into M random positive parts that sum to N.
 
    Algorithm (uniform integer composition):
    ----------------------------------------
    1. We want M positive integers p1, p2, ..., pM such that:
           p1 + p2 + ... + pM = N
 
    2. Generate (M - 1) random "cut points" in the range [1, N - 1].
       Example: N = 20, M = 4 → generate 3 cuts, e.g. {3, 11, 17}
       
    3. Sort the cut points.
 
    4. The parts are the differences between consecutive cuts:
         p1 = cut[0]
         p2 = cut[1] - cut[0]
         ...
         pM = N - cut[M-2]
 
    This produces a uniformly random composition of N into M parts.
*/

/*
    Important:
    -----------
    Random cut points must be UNIQUE.
    If two cut points are equal, their difference becomes 0,
    which produces an invalid part.
*/

// Generate M random positive parts summing to N
function split_into_random_parts(N, M) {
    if (M <= 0 || N < M) {
        throw new Error("Invalid N or M: require N >= M >= 1");
    }

    const cuts = [];
    const used = new Set();  // ensures uniqueness

    // Generate UNIQUE cut points
    while (cuts.length < M - 1) {
        const c = 1 + Math.floor(Math.random() * (N - 1));
        if (!used.has(c)) {
            used.add(c);
            cuts.push(c);
        }
    }

    // Sort the cut points
    cuts.sort((a, b) => a - b);

    // Build the parts
    const parts = [];
    let prev = 0;

    for (const c of cuts) {
        parts.push(c - prev);  // guaranteed >= 1
        prev = c;
    }

    parts.push(N - prev);      // last part, also >= 1

    return parts;
}

// Usage
const N = 30;
const M = 5;

const parts = split_into_random_parts(N, M);

console.log(`Splitting N = ${N} into M = ${M} random parts:`);
console.log(parts.join(" "));


/*
run:

Splitting N = 30 into M = 5 random parts:
1 23 1 2 3

*/

 



answered Jul 19 by avibootz

Related questions

...