• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Question about a formula

Status
Not open for further replies.
Level 19
Joined
Aug 8, 2007
Messages
2,765
Im making a random item generator and a key trait of the generator would be to scale the values that it puts out to a graph

so lets say you have 3 numbers

number A is the minimum, 20
number B is the maximum, 100
number C determines the rarity of numberB to numberC. If number C is 0.5, than number A will show up twice as much as number B. If number C is 2, than number B will show up twice as much as number A. (This also applies to all numbers inbetween, e.g. 60 will show up 1.5x as much as number A)
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Whats the question?

how would i do whats stated in the top....

when generated randomly, (min) shows up (weight)x more than max and (min+max/2) shows up (weight/2) more than max and every number inbetween follows the same scheme
 
Level 14
Joined
Jun 27, 2008
Messages
1,325
Ok, this can be solved in a more general way.

Assume you have a probability density function (pdf) f that specifies your distribution. Then you can calculate the cumulative distribution function (cdf) F by integrating f (analytically).
F(u) = integrate f from -infinity to u
For x being uniformly distributed reals between 0 and 1 (use GetRandomReal native) F^-1(x) will return values distributed by the distribution specified by f. (F^-1 is the inverse of F, calculate it analytically).

Looks like this then:
CodeCogsEqn%20%282%29.jpg


All you need to do is write down the pdf for your problem with A,B,C as parameters (in your case a linear function, normalized to have an integral of 1).
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Ok, this can be solved in a more general way.

Assume you have a probability density function (pdf) f that specifies your distribution. Then you can calculate the cumulative distribution function (cdf) F by integrating f (analytically).
F(u) = integrate f from -infinity to u
For x being uniformly distributed reals between 0 and 1 (use GetRandomReal native) F^-1(x) will return values distributed by the distribution specified by f. (F^-1 is the inverse of F, calculate it analytically).

Looks like this then:
CodeCogsEqn%20%282%29.jpg


All you need to do is write down the pdf for your problem with A,B,C as parameters (in your case a linear function, normalized to have an integral of 1).

Thanks for trying, but im 15 and trying to understand what you said but i really have no idea. Ill try a few google searches, but...
 
Level 17
Joined
Jul 17, 2011
Messages
1,863
haha you can use weights, each number a,b and c is a weight so for example a = 2 b = 9 and c = 8 then you add all the weights together and divide each weight by that number to get a percentage

a+b+c = 19
2/19 = 10%
9/19 = 47%
8/19 = 42%

this way all the values are dependent on each other
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
haha you can use weights, each number a,b and c is a weight so for example a = 2 b = 9 and c = 8 then you add all the weights together and divide each weight by that number to get a percentage

a+b+c = 19
2/19 = 10%
9/19 = 47%
8/19 = 42%

this way all the values are dependent on each other

hm.. i must not be explaining myself properly

I don't want to select from a few pre-selected numbers, i want to get ANY number from the GetRandomInt function, but weigh it so that one side shows up more frequently than the others. Your method would work if there was a few pre-determined numbers, but there isn't.

(also, theres only one weight value that determines the scaling of the GetRandom)
 
Level 14
Joined
Jun 27, 2008
Messages
1,325
ok il go a little more into detail:

I.
Write down the pdf f for your problem. The pdf simply tells you what the chances are to get a specific observation (the random variable equals the specific value). In order to find the pdf we write down our necessities:
1. For your needs you need a stepwise defined function, in the interval [A, B] it is a linear function, outside of that interval it is 0.
Lets say the chance to get the number A is a, and the chance to get the number B is b.
So f(A) = a, f(B) = b
2. Then you want b = a*C. (thats how you defined the parameter C)
3. A function is a pdf if and only if the integral is 1 (the area under the function has to be 1). The area under a linear function is defined as:
area = (a+b)/2 * (B-A)
so we have the necessity
(a+b)/2*(B-A) = 1

This gives us:
a = 2/(C+1) * 1/(B-A)
b = (2-2/(C+1)) * 1/(B-A)

A linear function that interpolates the points (A, a) and (B, b) is
f(x) = (b-a)/(B-A) * x + (B*a - b*A)/(B-A)
and using the formulas for a and b:
f(x) = -2*(A*C - B - C*x + x)/((C+1)*(A-B)^2)
(on the interval [A, B], everywhere else f(x) is 0).
f(x) =
form1.jpg


Example: Lets use A = 20, B = 100, C = 0.5. Then we get
f(x) =
form2.jpg

which looks like this:
plot1.jpg


II.
We have to integrate the pdf f(x) to get the cdf F(x).
F'(x) =
form3.jpg

(with constant == 0)
But since we have a stepwise function we need to adjust the bounds:
F(x) = F'(x) - F'(A), if A <= x <= B (this case is the interesting one)
F(x) = 0, if x < A
F(x) = F'(B) - F'(A), if x > B

III.
Invert the cdf to calculateF^-1(x). We use
F(x) = F'(x) - F'(A), since this area gets mapped to [0, 1] of the inverse.
F(x) =
form4.jpg

=
form5.jpg

The inverse is
F^-1(x) =
form6.jpg

=
form7.jpg


Use uniformly distributed random numbers in the interval of [0, 1] as input.
 
Level 21
Joined
Mar 27, 2012
Messages
3,232

I have a fitting curve. Without the math overkill.

Set i to random int between 1 and 100
set it to random between 1 and i
This basically does what you want, as the chance to get 0 is twice as much as for 100.
For every cycle that you add the chance increases.
Example
set i = random(1,100) //1% chance for every number
set i = random(1,i) //2% chance for 1 and 0.5% chance for 100
set i = random(1,i) //3% chance for 1 and 0.(3) for 100
set i = random(1,i) //4% and 0.25%
etc
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
I have a fitting curve. Without the math overkill.

Set i to random int between 1 and 100
set it to random between 1 and i
This basically does what you want, as the chance to get 0 is twice as much as for 100.
For every cycle that you add the chance increases.
Example
set i = random(1,100) //1% chance for every number
set i = random(1,i) //2% chance for 1 and 0.5% chance for 100
set i = random(1,i) //3% chance for 1 and 0.(3) for 100
set i = random(1,i) //4% and 0.25%
etc

That makes sense! Ty

e/ would this work? (need to test it)

JASS:
                real r = weight;
                real result = max;
                real nextResult;
                real r2;
                boolean invert = false;
                if(r < 1)
                {
                    invert = true;
                    r = 1 / r;
                }
                for(r >= 1)
                {
                    r = r - 1;
                    result = GetRandomReal(1, result);
                }
                if(r < 1)
                {
                    nextResult = GetRandomReal(1, result);
                    r2 = result - nextResult;
                    r2 = nextResult + (result / r);
                    result = r2;
                }
                if(invert)
                {
                    result = 0.5 - (result - 0.5)
                {
 
Last edited:
Level 21
Joined
Mar 27, 2012
Messages
3,232
That makes sense! Ty

e/ would this work? (need to test it)

JASS:
                real r = weight;
                real result = max;
                real nextResult;
                real r2;
                boolean invert = false;
                if(r < 1)
                {
                    invert = true;
                    r = 1 / r;
                }
                for(r >= 1)
                {
                    r = r - 1;
                    result = GetRandomReal(1, result);
                }
                if(r < 1)
                {
                    nextResult = GetRandomReal(1, result);
                    r2 = result - nextResult;
                    r2 = nextResult + (result / r);
                    result = r2;
                }
                if(invert)
                {
                    result = 0.5 - (result - 0.5)
                {

I don't understand much of this and it doesn't look like JASS to me.
Can you explain what you wanted it to do?
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
#10 is my own and it's easier than this.

Basically I don't understand zinc, only vanilla JASS and sometimes vJASS.

I get it that you combined it with weights, but how exactly I don't understand.

just ignore the {, replace the } with "endif" or "endloop" :eek:

its quite simple, it just loops through it untill the weight is >0<1 than gets another variable and adds on however much weight was lost... (so if it was a 25 than the next was a 15 an leftover weight was 0.5 it would end up to be 20)

JASS:
                local real r = weight;
                local real result = max;
                local real nextResult;
                local real r2;
                local boolean invert = false;
                if r < 1 then
                    set invert = true;
                    set r = 1 / r;
                endif
                loop
                    exitwhen r >= 1
                    set r = r - 1;
                    set result = GetRandomReal(1, result);
                endloop
                if r < 1 then
                    set nextResult = GetRandomReal(1, result);
                    set r2 = result - nextResult;
                    set r2 = nextResult + (result / r);
                    set result = r2;
                endif
                if invert then
                    set result = 0.5 - (result - 0.5)
                endif
 
Level 21
Joined
Mar 27, 2012
Messages
3,232
just ignore the {, replace the } with "endif" or "endloop" :eek:

its quite simple, it just loops through it untill the weight is >0<1 than gets another variable and adds on however much weight was lost... (so if it was a 25 than the next was a 15 an leftover weight was 0.5 it would end up to be 20)

JASS:
                local real r = weight;
                local real result = max;
                local real nextResult;
                local real r2;
                local boolean invert = false;
                if r < 1 then
                    set invert = true;
                    set r = 1 / r;
                endif
                loop
                    exitwhen r >= 1
                    set r = r - 1;
                    set result = GetRandomReal(1, result);
                endloop
                if r < 1 then
                    set nextResult = GetRandomReal(1, result);
                    set r2 = result - nextResult;
                    set r2 = nextResult + (result / r);
                    set result = r2;
                endif
                if invert then
                    set result = 0.5 - (result - 0.5)
                endif

I understand every piece separately, but not how it all comes together. Math is not my strong side.
That's why I avoid using JASS in my explanations.
 
Status
Not open for further replies.
Top