# How do I randomy generate perentages of a random number??

Hello,
I asked this question in the UnityAnswers section and the answer wasn’t really what I’m needing . I thought to ask it here due to the activity here versus there.

Original post:
I need to randomly generate a number between 10000 and 25000, then randomly distribute the result into 10 different variables.
Anyone have any ideas on how to do this in either C# or Uscript?

Clarification post:
Maybe I wasn’t very clear on what I’m trying to do. Here’s (hopefully) a better way to describe the operation that I’m trying to achieve
Generate a random number between 10000 and 25000 (done- let’s say it’s 15000) Then; take the result (15000) and distribute it over 10 variables by random percentage Resulting in var a= 1500 (10% of total) var b= 750 (5% of total) etc. until 100% of total is reached
In this case these would all be INT values

Thanks for any replies

``````var counter : int = 0;
var starter : int = Random.Range(10000, 25000) ;
for (i = starter ; i > 0 ; i = Random.Range(0, i)){
var[counter] = (i / starter);
}
``````

Pseudo code, may have syntax errors.
Basically you start high (100%) with a number, than every loop get a new number between 0 and the old number.
To get percentage you compare new number with the starting number - ratio 0-1

But getting exactly 10 variables is a bit harder. #10 would be leftovers, but 1-9 would need limits (Random.Range(LIMITHERE, i - ANOTHERLIMIT)) in some way.

For the percentage ranges (you mentioned 5% and 10%), is there a valid range there? Is it 5-15%? Or can it be from 0% to 95%? Does the distribution need to be truly random or can you just choose a fixed set:
7, 13, 5, 15, 8, 12, 6, 14, 9, 11, of which you randomly assign to variables A through J?

If so, you could probably do something like this:

``````var sum : int = Random.Range(10000, 25000);
var remainder : int = sum;

//distributions total 1.00 (100%)
var distribution : Array = new Array(0.07, 0.13, 0.05, 0.15, 0.08, 0.12, 0.06, 0.14, 0.09, 0.11);

var numResults = distribution.length;

var result : Array = new Array();

for (var i : int = 0; i < numResults; i++)
{
//grab a random distribution
var randomDistributionIndex : int = Random.Range(0, distribution.length);
var randomDistribution : float = distribution[randomDistributionIndex];

//this removes that distribution value so it's not duplicated
distribution.RemoveAt(randomDistributionIndex);

var portion : int = Math.Round(sum * randomDistribution);

remainder -= portion;

result.Push(portion);
}

//if there's round-off error, just throw the few digits on the last entry
if (remainder != 0)
{
result[result.length - 1] += remainder;
}

for (var i : int = 0; i < result.length; i++)
{
Debug.Log("RESULT " + i + ": " + result[i]);
}
``````

EDIT: I thought about that windexglow, but likely your distribution would tend to see relatively large numbers to start, then they would become much smaller as you go on. For example, 50% of the time, your first number will be larger than all other numbers combined.

EDITx2: nevermind, your logic/algorithm has gone over my head. Not sure what the distribution pattern would look like.

You’re right, it would lead to bigger initial numbers but that’s why you could add limitations to the number range (minimum random value is always 500 away from max, for example)

Still, there are a ton of ways to do this. I didn’t put a lot of thought into my code so it could be wrong. You could generate the percentages first (applying some kind of average effect to reduce big number differences) ectect.

Thanks for the replies,

@fizixman : I would need as true to random distribution as possible, so a fixed model wouldn’t work.

@windexglow : The remaining percentage being dregs would skew the whole operation and the total MUST equal 100% of the original number.

The issue that I’m having is how to randomly generate the PERCENTAGES. The product of all 10 percentage variables should equal 100% of the total given in the first random function. In my original post I was trying to describe the needed outcome and obviously not doing it well.

Here’s another shot at it:

x= random number from 10000-25000 (easy not a problem)

a=(random)% of x
b=(random)% of x
c=(random)% of x
d=(random)% of x
e=(random)% of x
f=(random)% of x
g=(random)% of x
h=(random)% of x
i=(random)% of x
j=(random)% of x

x=sum(a,b,c,d,e,f,g,h,i,j)=100% of x

Randomly generating the original number and randomly generating the percentages is no problem. The problem comes in with the percentages adding up to the original number in this case “x”.

I hope that is a bit more clear,

thanks again

I’ll ask again though, how random do you want your percentages? If you’re talking about truly random, you could have:

a=99.1% of x
b=0.1% of x
c=0.1% of x
d=0.1% of x
e=0.1% of x
f=0.1% of x
g=0.1% of x
h=0.1% of x
i=0.1% of x
j=0.1% of x

Is that alright? The answer to the question will likely drive whatever algorithm we come up with.
(also, would it be OK if one of them randomly came out as 0%?)

As a second question, perhaps you could describe what it is you’re trying to achieve; there possibly may be a simpler method of achieving the same/similar result.

@fizixman

The scenario you give is an acceptable outcome if it happens in a truly random fashion. The odds would be astronomical to actually get that result but still possible. Getting a zero result is also acceptable. I would probably opt for a whole number in terms of the percentages for the sake of simplicity.

I am generating a character with randomly generated (within bounds, 10000-25000) experience points. the experience points need to be randomly distibuted over a number of attributes, as an arbitrary number 10. The number of attributes could vary from 5 to 25, and the range may change, but the concept should remain the same.

Thanks again

Personally I reckon I’d try generating the random experience points number

Then randomly generate each of your ‘percentage’ numbers, normalise them, multiply each normalised ‘percentage’ by 100 to create a real percentage, then divide up the overall experience value by those generated ‘real’ percentages. To vary the possible maximum and minimum values for any percentages just alter the range from which the pre-normalised percentages are generated. Does that make sense? It kinda did in my head.

Afraid I’ve not actually tested this though. My scripting technique is basically ‘poke it with a stick until it works’.

There are a couple of ways to do this. The simplest, requiring the least amount of work and knowledge, is to run the numbers through a loop, and assign them randomly. Something like this (not tested c#):

``````public int testNumber; //this will actually be your randomly generated number
private float[] results; //this will be the results of the division done

void RandomPercentages () {
float percentMonitor = 1.0f; //determines the amount of percentage taken, so that we do not exceed 100%
for (int i=0; i<10; i++) {
float thisPercent = Random.Range(0.0f, percentMonitor);
float rndmNumber = testNumber*thisPercent;
percentMonitor -= thisPercent;
results[i] = rndmNumber;
}
}
``````

You could even expand that to have it randomly determine the part of the array it gets assigned to or etc. Again, it’s the general concept of one way to do it without deducing too much logic or getting into probability distribution.

Regards,
Rob

@Wolgfie
Thanks for the idea. I sort of understand what you’re saying but I’d have to play with it to see whether the end result is what I’m looking for. I have a couple of instances where this algorithm is needed with different paramters, of course. My approach to programming is for the most part same as yours, maybe I’d need to to see a code example to get my head around it.

Something tells me that this is one of my minor challenges…

Again, Ezzerland’s method will result in the first few entries tending to be significantly larger then the later ones. But what you could do is run that through first, then randomize that array, then run them through the algorithm I suggested:

``````var sum : int = Random.Range(10000, 25000);
var remainder : int = sum;

var numResults = 10;

var distribution : Array = new Array();

var totalPercentage = 1.0f;

//generate random percentages that add up to 100%
//these will tend to go from large to small
for (var i : int = 0; i < numResults; i++)
{
var percentage : float = Random.Range(0.0f, totalPercentage);
totalPercentage -= percentage;
distribution.Push(percentage);
}

//this randomizes our distribution array, so even if we tend to have large numbers first, they'll get shuffled around anyway
for (var i : int = 0; i < numResults; i++)
{
var indexToSwap : int = Random.Range(i, numResults);

var oldValue : object = distribution[i];
distribution[i] = distribution[indexToSwap];
distribution[indexToSwap] = oldValue;
}

var result : Array = new Array();

for (var i : int = 0; i < numResults; i++)
{
//grab a random distribution
var randomDistributionIndex : int = Random.Range(0, distribution.length);
var randomDistribution : float = distribution[randomDistributionIndex];

//this removes that distribution value so it's not duplicated
distribution.RemoveAt(randomDistributionIndex);

var portion : int = Math.Round(sum * randomDistribution);

remainder -= portion;

result.Push(portion);
}

//if there's round-off error, just throw the few digits on the last entry
if (remainder != 0)
{
result[result.length - 1] += remainder;
}

//print the results
for (var i : int = 0; i < result.length; i++)
{
Debug.Log("RESULT " + i + ": " + result[i]);
}
``````

in my quickness, I also forgot to account for the result totalling the testNumber.

Anywho, it’s the generic concept of a cheap method to do it. Fizix response includes my after-included comment of randomizing where in the array they get placed. That method will be your cheapest way of getting truly randomized methods, again, without getting into the more complicated algorithms.

Many thanks to all,

I’ll play with the code examples a bit and see what happens. I still need to actually define the variables rather than use an array but that should be a minor thing.

again many thanks

Just out of curiosity, is there a reason an array would not work? The numbers are easily retrievable/defined, and it’s less resource consuming imo. Lighter on the code/cleaner too. Anywho, same concept without the array, you just need to toss in a switch or so to determine where to assign the variables.

You’re very right. The array will work just fine and be much cleaner. Sorting this all out in my head, not so much.

Cheers

Just to chime in:

If you imagine what you are actually asking for in physical real world terms, it is something akin to dumping a bag of marbles (which has anything between 10000 -25000 marbles in it over a series of 10 slots… now of course in real physical reality there would be other concerns… but really you should looping through the marbles themselves, not the slots, to find the totals in each slot.

in C#…

``````int numSlots = 10;

int[] marbles = new int[Random.Range(10000,25000)];
int[] slots = new int[numSlots];
float[] percentages = new float[numSlots];

for (int i=0; i < numSlots; i++ ) {
slots[i] = 0;
}

foreach (int marble in marbles) {
slot[Random.Range(0,9)]++;
}

for (int i=0; i < numSlots; i++) {
percentage[i] = slot[i] / marbles.Length;
}
``````

Note that the “marbles” algorithm makes it very unlikely that 100% would end up in any given slot (The actual odds for 25000 marbles being 1:10^25000.)

More than likely you would get almost exactly 10% in each “slot” To avoid this you could replace the 2nd loop with this:

``````int i=0;
int minGroupSize = 1;
int maxGroupSize = 100;
while (i < marbles.Length) {
int marbleGroup = Math.Clamp(Random.Range(minGroupSize, maxGroupSize), 1, marbles.Length - i);
slot[Random.Range(0,9)]+=marbleGroup;
i += marbleGroup;
}
``````

This means that up to 100 marbles can fall into one slot at a time and at least 1 will always fall into a slot. The higher the maxGroupSize the higher the deviation will be. If you set maxGroupSize to marbles.Length then the chances of getting 100% in one container are much higher. Playing with these variables is essentially affecting the curve of the deviation.

Randomness is not always totally random. You have to define it for yourself in some way…

Note: I used Mathf.Clamp here to ensure that you wouldn’t overshoot your total marbles… Also it should be noted that the Random.Range method is overloaded in C# so that it is returning an integer unless you specify that the lower and upper bounds are floats. That is why there is no need to RoundToInt in this case.

Also when you say “all of these should be INTs” it is rather confusing… Why would you need percentages as integer values? Moreover, if you are working with a random integer, integer percentages of that random number will not always yield an integer. (eg. get out your calculator and find 10% of 10001).

Only certain numbers between 10000 and 25000 could ever satisfy the condition.

Is this for a computing class or something?

Thanks Antitheory,
Now that my brain is a bit more clear, I see that I mis-spoke (typed) I should have said whole numbers. Your solution is actually the closest to what I am looking to achieve. This algorithm is actually needed for a game.

from an earlier post:

“I am generating a character with randomly generated (within bounds, 10000-25000) experience points. the experience points need to be randomly distibuted over a number of attributes, as an arbitrary number 10. The number of attributes could vary from 5 to 25, and the range may change, but the concept should remain the same.”

I understand what your saying about the math of percentages, but how often will 1/2 or 1/4 of a marble ever fall in a slot? I am sure some rounding will have to occur to total the 100% goal. Will the result be off? yes, but not to any great degree and I’m sure the error would be well with 0.1 standard Deviations. In short, acceptable error.

Ok that makes sense. The code I gave above (with the “while” loop substituted for the second “for” loop) should get you what you need. Just play around with the minimum and maximum group sizes and see what kind of deviation you need.

You could think of the while loop as a series of battles which the character won the experience points

the minGroupSize would then be the min EXP take from one battle. The maxGroupSize would be the max EXP take. The player then fights enough “battles” to account for all the EXP you decided on beforehand (between 10000-25000). For each battle the EXP is routed to the different attribute (maybe fighting a wizard earns you magic points, fighting an ogre earns you strength points).

I am just trying to suggest a way to visualize how the exp was attributed in the first place. It could give you an idea of the size of minGroupSize and maxGroupSize.