Not sure if this exact question's been asked before, though a similar question has been asked here. Essentially, what I'm trying to is generate random integers of a minimum size that still sum up to a certain value (an invariant is that the sum / (number of randoms you want) is greater than the minimum value. Here's a sad attempt I coded up:
import java.util.Arrays;
import java.util.Random;
public class ScratchWork {
private static Random rand = new Random();
public static void main(String[] args) {
int[] randoms = genRandoms(1000, 10, 30);
for (int i = 0; i<randoms.length; i++) sop("Random Number "+ (i+1) + ": " + randoms[i]);
sop("Sum: " + sum(randoms));
}
public static int sum(int[] array) { int sum = 0; for (int i : array) sum+=i; return sum; }
public static int[] genRandoms(int n, int numberOfRandoms, int min) {
if (min > n/numberOfRandoms) throw new UnsupportedOperationException();
int[] intRandArray = {0};
while (sum(intRandArray) != n) {
////////////////////////
// See https://stackoverflow.com/questions/2640053/getting-n-random-numbers-that-the-sum-is-m
Double[] randArray = new Double[numberOfRandoms];
double workerSum = 0;
for (int i = 0; i<numberOfRandoms; i++) {
randArray[i] = ((double)rand.nextInt(n-1)+1);
workerSum += randArray[i];
}
for (int i = 0; i<randArray.length; i++) {
randArray[i] = n*(randArray[i]/(workerSum));
}
/////////////////////////
while (existsSmallerNumThanMin(randArray, min))
randArray = continueToFix(randArray, min);
//Convert doubles to ints
intRandArray = new int [randArray.length];
for (int i = 0; i < intRandArray.length; i++)
intRandArray[i] = (int)Math.round(randArray[i]);
}
return intRandArray;
}
public static boolean existsSmallerNumThanMin(Double[] randArray, int min) {
for (double i : randArray) if (i < (double)min) return true;
return false;
}
public static Double[] continueToFix(Double[]randArray, int min) {
Double[] tempArray = Arrays.copyOf(randArray, randArray.length);
Arrays.sort(tempArray);
int smallest = Arrays.asList(randArray).indexOf(tempArray[0]);
int largest = Arrays.asList(randArray).indexOf(tempArray[tempArray.length-1]);
double randomDelta = rand.nextInt(min);
randArray[smallest]+=randomDelta;
randArray[largest]-=randomDelta;
return randArray;
}
public static void sop(Object s) { System.out.println(s); }
}
This is neither an elegant nor high-performing way to do this... It also doesn't seem to work well (if at all) when passed in, say, (100,10,10), which only allows for the number 10 in the array. The distribution of the random numbers is also pretty bad.
Is there an elegant approach to this??
Also, my end goal is to implement this in Objective-C, though I'm still just learning the ropes of that language, so any tips for doing this in that language would be greatly appreciated.