How to generate some random numbers so that they meet certain conditions and are equal to each other?

declare 40 < A < 60,20 < B < 80 and A + B = = 100
how to randomly generate An and B?

first modification:
statement 40 < A < 60,20 < B < 80,30 < C < 70 and A + B + C = = 150
how to randomly generate A, B and C?

Finally, this is used for roll CoC running character card, strength 3D6, physique 3D6, physique 2D6 6, agility 3D6, appearance 3D6, intelligence 2D6 6, will 3D6, education 2D6 6 6, the sum of 8 attributes is about 92

.

Update
uses Cucumber"s algorithm and writes

myself.
function main () {
    let sum = 24;
    let index = 0;
    // A[1,5], B[0,6], C[2,4], D[2,4], E[0,6], F[1,5], G[2,4], H[0,6]
    let maxs = [ 5, 6, 4, 4, 6, 5, 4, 6,]; // 
    let mins = [ 1, 0, 2, 2, 0, 1, 2, 0,]; // 
    let result = []; // 

    while (index < maxs.length - 1) {
        //  []  []  // [1,5]   (24-0-2-2-0-1-2-0 === 17)
        let max = Math.min(maxs[index], sum - mins.slice(index + 1).reduce((o, n) => o + n));
        // 
        let min = Math.max(mins[index], sum - maxs.slice(index + 1).reduce((o, n) => o + n));

        // 
        result[index] = Math.floor(Math.random() * ((max - min) + 1)) + min;

        // 
        sum -= result[index];
        indexPP;
    }
    // 
    result[maxs.length - 1] = sum;


    return result ;
}

but there is something wrong with this result, that is, the distribution is very uneven
after the execution of the main method above

var x = [0,0,0,0,0,0,0,0].map(v=>new Array(7).join(".").split(".").map(u => 0));

var N = 100000;
for(var i = 0;i<N;iPP){
    var r = main();
    for(var j = 0; j<8;jPP){
        x[j][r[j]] PP
    }
}

console.log(x)

the number of occurrences of each number in the results of each group is

[[    0, 20041, 19843, 20108, 20210, 19798,     0], // A
 [14193, 14407, 14449, 14394, 14280, 14137, 14140], // B
 [    0,     0, 33219, 33301, 33480,     0,     0], // C
 [    0,     0, 33080, 33519, 33401,     0,     0], // D
 [13194, 14225, 15147, 15090, 14927, 14273, 13144], // E
 [    0, 20608, 19647, 19446, 19445, 20854,     0], // F
 [    0,     0, 35357, 29025, 35618,     0,     0], // G
 [20940, 12813, 10764, 10847, 10907, 12756, 20973]] // H

it is obvious that the last number, H [0 br 6], has 20940 occurrences of 0 much more than 3 times 10847
and this is much less common in A than in H < 0 >. Why? How to avoid it?

Jul.07,2021

randomly generate A , and then Bath100
B the range is too large, and random generation may lead to unmatched A


.

look at the specific needs

  1. if you need to generate multiple random numbers frequently and quickly, you can use the look-up table method. Save all possible combinations (the total number of n is less than 48000) into an array, and then take one at a time at random. This is the fastest but increases initialization time and storage space
  2. it is more general to take An at random, and then calculate the range of B', a subset of B, according to the range of C, so that each element in B 'has at least one element in C to be a solution. Then take the Baker at random, and finally calculate the C.

for example, if An is randomly taken as 50, then the range added to C is 81-119, and B' can be calculated to be 31-69, from which one can be randomly selected, and finally C can be calculated.

[update]-

, it's kind of interesting.

this result shows that the previously thought algorithm is not accurate. After a brief analysis, the reason is that there are eight groups of numbers, and the sum of the first four groups of maximum values is smaller than 24, so no matter how these groups are selected, they will not affect their random range, so they can be considered completely random. Starting from the fifth group, its actual scope will be affected by the first few groups, so it can be considered that their selection is not completely random.

however, the sum of the maximum value of the first five groups is 25, which is only a little more than 24, so the impact of group 5 is very small. From the results, we can see that its randomness is still very good, and the deviation is basically negligible. But the latter three groups are not so lucky, and the deviation is relatively large.

you can use the look-up table method I gave earlier to avoid this problem, but I haven't thought of a better way yet.

[update again]-

it occurred to me just now that the selection order can also be random. Each time, one group is randomly selected as the next group, so the final result should be completely random.


Xeira's idea is right. I don't think you understand it thoroughly.

two numbers are randomly generated and the sum is equal, so after the first number is generated, the second number has been determined. so it's actually randomly generating a number.

the N number is randomly generated, and the sum is guaranteed to be equal, then the N number is also determined after the random generation of Nmuri 1 number.

this is the first point.
there is a second point.
every random number has a range, and the sum of all numbers is certain, which means that when randomly generating numbers, you can't just consider the range set by the number itself.

if the sum of N is certain, a certain number is within another range in addition to its own restriction of a < N < b.
Lower bound: and S-the sum of known numbers-the sum of all other unknown numbers, the current number must be greater than this number, otherwise it may occur that no matter how the sum is generated, it may not be equal to the upper limit of S
: similarly, after subtracting known numbers, Then subtract the sum of the minimum values of other unknowns. The current number must be less than this value, or it may not be satisfied anyway and is S.


<blockquote>(JavaScript)</blockquote>
 function randomInt(start, end) {
        return Math.floor(Math.random()*(end - start + 1) + start);
    }
 function computed() {
       while(true){
           let a = randomInt(41,60);
           let b = randomInt(21,80);
           let sum = 150;
           let c = sum - ( a + b );
           if(c > 30 && c < 70) {
               return [a,b,c]
           }
       }
   }
   console.log(computed())
Menu