Generate n random numbers whose sum is m and all n

2020-07-11 05:44发布

I want to generate 9 non zero random numbers whose sum is 250. I have tried following code it gives me 9 random numbers but some numbers are zero.

 public void n_random()
{
  Random r = new Random();
ArrayList<Integer> load = new ArrayList<Integer>();
    int temp = 0;
    int sum = 0;
    for (int i = 1; i <= 9; i++) {
        if (!(i == 9)) {
            temp = r.nextInt(250 - sum);
            System.out.println("Temp " + (i) + "    " + temp);
            load.add(temp);
            sum += temp;

        } else {
            int last = (250 - sum);
            load.add(last);
            sum += last;
        }
    }

    System.out.println("Random arraylist " + load);
    System.out.println("Sum is "+ sum);

}

Where is my mistake or where i should improve my code or any other solution?

标签: java random
7条回答
三岁会撩人
2楼-- · 2020-07-11 06:00

I would suggest using:

temp = r.nextInt((250 - sum) / (9 - i)) + 1;

That will make sure that:

  • each number is strictly positive
  • you won't use the full "250 allowance" before reaching the 9th number

However the distribution of the results is probably biased.

Example output:

Random arraylist [18, 28, 22, 19, 3, 53, 37, 49, 21]

Explanation:

  • (250 - sum) is the amount left to reach 250, so you don't want to go over that
  • / (9 - i) if your sum has reached for example 200 (need 50 more) and you have 5 more to go, make sure the next random number is not more than 10, to leave some room for the next 4 draws
  • + 1 to prevent 0

An alternative which probably gives a better distribution is to take random numbers and scale them to get to the desired sum. Example implementation:

public static void n_random(int targetSum, int numberOfDraws) {
    Random r = new Random();
    List<Integer> load = new ArrayList<>();

    //random numbers
    int sum = 0;
    for (int i = 0; i < numberOfDraws; i++) {
        int next = r.nextInt(targetSum) + 1;
        load.add(next);
        sum += next;
    }

    //scale to the desired target sum
    double scale = 1d * targetSum / sum;
    sum = 0;
    for (int i = 0; i < numberOfDraws; i++) {
        load.set(i, (int) (load.get(i) * scale));
        sum += load.get(i);
    }

    //take rounding issues into account
    while(sum++ < targetSum) {
        int i = r.nextInt(numberOfDraws);
        load.set(i, load.get(i) + 1);
    }

    System.out.println("Random arraylist " + load);
    System.out.println("Sum is "+ (sum - 1));
}
查看更多
时光不老,我们不散
3楼-- · 2020-07-11 06:03

I don't see where you've checked to make sure that zero is excluded. Add a check before you insert it into the array.

Too many "magic numbers" in this code to suit me.

查看更多
爷、活的狠高调
4楼-- · 2020-07-11 06:04

A call to Random.nextInt(n) will return an integer between 0 and n-1

try temp = r.nextInt(250 - sum) + 1; and see if that solves your issue.

查看更多
狗以群分
5楼-- · 2020-07-11 06:07

this is javascript alternative

function getRandomNos(m,n) {

    var nums=[];
    var i;

    for (i = 0;i<n;i++) {
       nums[i] = Math.random();
    }
    var factor = (m-n) / nums.reduce(add, 0);
    for (i = 0;i<nums.length;i++) {
       nums[i] = parseInt(nums[i] * factor) + 1;
    }

    var fudge = m - nums.reduce(add, 0);

    for (i=0;i<fudge;i++) {
       nums[i] = nums[i] + 1;
    }
    console.log(nums);
    console.log(nums.reduce(add, 0));

}

function add(a, b) {
    return a + b;
}
查看更多
做自己的国王
6楼-- · 2020-07-11 06:14

Your code line:

r.nextInt(250 - sum);

... will generate a pseudo-random from 0 (included) to 250 - sum (excluded).

See API for Random.nextInt.

I won't try to solve all your problem here, but simply adding 1 to the expression above would guarantee that it never returns 0.

All remaining adaptations up to you though :)

For instance if 250 - sum - 1 evaluates to negative, then you'll throw an IllegalArgumentException.

查看更多
姐就是有狂的资本
7楼-- · 2020-07-11 06:20

Here's one way to do it, that avoids (most) magic numbers and provides a decent distribution of numbers though all will be smaller than other possible solutions.

public static void n_random(int count, int finalSum)
{
    Random r = new Random();
    int numbers[] = new int[count];
    int sum = 0;
    for (int i = 0; i < count - 1; i++)
    {
        numbers[i] = r.nextInt((finalSum - sum) / 2) + 1;
        sum += numbers[i];
    }
    numbers[count - 1] = finalSum - sum;

    StringBuilder numbersString = new StringBuilder("Random number list: ");
    for (int i = 0; i < count; i++)
        numbersString.append(numbers[i] + " ");
    System.out.println(numbersString);
}

public static void main(String[] args)
{
    n_random(9, 250);
}
查看更多
登录 后发表回答