How do I generate 30 random numbers between 1-9, that all add up to 200 (or some arbitrary N), in C#?
I\'m trying to generate a string of digits that can add togethe
This is an old question but I discovered it looking for a solution to this problem for a practical use in a random data generation testing application.
Based on the ideas in this post I came up with two potential solutions.
The first method:
The second method is much simpler but results in a less random distribution:
Here is the code:
public static int[] getRandomsWithTotalA(int desiredTotal, int desiredNumbers, int upperBound)
{
Random r = new Random();
// Is this even a possible feat?
if (desiredNumbers * upperBound < desiredTotal) throw new ArgumentException("This is not possible!", "desiredTotal");
// Start by figuring out the closest number we can get to by repeating the initial number.
int lowestRepeating = desiredTotal / desiredNumbers;
// Determine the remainder
int lowestRepeatingRemainder = desiredTotal % desiredNumbers;
// Initialize and populate an array of numbers with the lowest repeater.
int[] results = Enumerable.Repeat(lowestRepeating, desiredNumbers).ToArray();
// We will perform (n*desiredTotal) shuffles.
int shuffles = (desiredTotal * desiredNumbers);
while (shuffles > 0)
{
int a = r.Next(desiredNumbers);
int b= r.Next(desiredNumbers);
if (a==b) continue; // do nothing if they're equal - try again.
// Test bounds.
if (results[a]+1>upperBound) continue;
if (results[b]-1<0) continue;
// Add one to the first item.
results[a]++;
// Do we still have a remainder left? If so, add one but don't subtract from
// somewhere else.
if (lowestRepeatingRemainder>0)
{
lowestRepeatingRemainder--;
continue;
}
// Otherwise subtract from another place.
results[b]--;
// decrement shuffles
shuffles--;
}
return results;
}
public static int[] getRandomsWithTotalB(int desiredTotal, int desiredNumbers, int upperBound)
{
Random r = new Random();
// Is this even a possible feat?
if (desiredNumbers * upperBound < desiredTotal) throw new ArgumentException("This is not possible!", "desiredTotal");
// Initialize and populate an array of numbers with the lowest repeater.
int[] results = new int[desiredNumbers];
while (desiredTotal > 0)
{
int a = r.Next(desiredNumbers);
// Test bounds.
if (results[a] + 1 > upperBound) continue;
// Add one to the first item.
results[a]++;
desiredTotal--;
}
return results;
}
A sample run:
static void Main(string[] args)
{
foreach (int i in getRandomsWithTotalA(200, 30, 9))
{
Console.Write("{0}, ", i);
}
Console.WriteLine("\n");
foreach (int i in getRandomsWithTotalB(200, 30, 9))
{
Console.Write("{0}, ", i);
}
}
3, 8, 7, 5, 9, 9, 8, 9, 9, 6, 8, 7, 4, 8, 7, 7, 8, 9, 2, 7, 9, 5, 8, 1, 4, 5, 4, 8, 9, 7,
6, 8, 5, 7, 6, 9, 9, 8, 5, 4, 4, 6, 7, 7, 8, 4, 9, 6, 6, 5, 8, 9, 9, 6, 6, 8, 7, 4, 7, 7,
These methods are understandably not as evenly distributed as one would like. It would make sense especially with the second method; if you have a random source that is truly evenly distributed, then your selection of the items to increment should have equal probability across all the possible values. The first one could potentially be a bit better also, but it still suffers from the fact that the random source is also ideally evenly distributed.
I feel like it might be possible to improve at least the first method by introducing some form of bias into the index selection, or possibly a randomization of how much we add and subtract (not always 1), or a randomization of whether we actually do the addition/subtraction or not. Just tweaking the number of iterations seems to change the distribution, but after a while it seems that we start favoring the outer boundaries. (Perhaps it's not possible to get a truly even distribution!)
In any case, there you go...A good place to start at least.