Jump to content

Weighted random number generator


Fillo Farber
 Share

You are about to reply to a thread that has been inactive for 4491 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

I'm working on a script that requires a weighted number generator between 1 and 118. The attempts I've made have used llPow but do not produce a sharp enough distribution curve. I need something that allows me to plug in a final "weight" value at the far end of the curve such as specifing that the odds are 1000 times greater of the number 1 being generated then the number 118. llLog?  Any suggestions?

 

Any suggestions?

Link to comment
Share on other sites

No clue how the odds would turn out, but generate two numbers and use the lower.

float a = llFrand(119.0);
float b = llFrand(119.0);
integer result;
 if (a < b) result = llCeil(a);else result = llCeil(b);

 Seems that would produce a bell curve of results targetted toward the lower end, instead of an even spread. Another option is to use a random number in the generator.

integer result = llCeil(llFrand(llFrand(118.0)));

 Seems that would produce a more linear spread, but no clue about the odds again.

  • Like 1
Link to comment
Share on other sites

Hi, no idea how many numbers you have, i solved this problem very rough ;)

Generate a list with all the number then put the "more wanted" numbers more often in that list.

Get a random number and use this as a string-position for the list.

I know this is very dirty and only works for smaller ranges but maybe someone can clean this up.

Monti

Link to comment
Share on other sites

A pretty simple aüpproach should be a list with avlues and a list of weightings that you use in generating your random results. Here is a simpkle example which could be made much nicer.

In the example, glItems are the possible results and glWeights the different weightings for the according position in the irems list:

 

list glItems =   ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"];list glWeights = [1,    2,   3,   4,   5,   5,   4,   3,   2,    1 ];integer giMax;default{	state_entry()	{		giMax = llListStatistics(LIST_STAT_SUM, glWeights);		}	touch_end(integer total_number)	{		integer randNum = (integer)(llFrand(giMax + 1));		integer i = 0;		integer counter;		for (; i < llGetListLength(glWeights); i++) {			counter += llList2Integer(glWeights, i);			if (randNum <= counter) {				llSay("The result is: " + llList2String(glItems, i);				return;			}		}	}}

 

Link to comment
Share on other sites

integer maxodds = 1000;integer minodds = 1;integer range = 118;integer rannum;integer odddiv;default{    state_entry()    {     llSetMemoryLimit(0x4000);     odddiv = (maxodds-minodds)/range;       integer x;     for(x=0;x<range;x++)rannum += maxodds-(x*odddiv);        llSay(0,(string)rannum); //test string              }    touch_start(integer total_number)    {     integer num = llCeil(llFrand(rannum));     integer x=0;     integer mo;     do      {       mo += (maxodds-(x*odddiv));         x++;       }        while(num>mo);      llSay(0,(string)x+ " - "+(string)num);    //test string     }}

 

Yes that is not hard to do, above is code that does as you ask, it is 1000 times more weighted to 1 than 118, it is not hard to see how it is done and creats a curve that you want. it has no steps and is a pure curve.

 

X is the number you want from the touch event.

oops changed the line integer mo = maxodds to integer mo = 0;, now its perfect, lol.

 

 

Link to comment
Share on other sites

This code will test the distribution of the numbers, let it run for a while then click it and it will list how many times each number was selected.

integer maxodds = 1000;integer minodds = 1;integer range = 118;integer rannum;integer odddiv;list nums = []; default{   state_entry()    {     llSetMemoryLimit(0x4000);     odddiv = (maxodds-minodds)/range;       integer x;     for(x=0;x<range;x++){rannum += maxodds-(x*odddiv);nums+=0;}     nums+=0;     llSay(0,(string)rannum); //test string     llSetTimerEvent(0.1);       }   timer()    {     llSetTimerEvent(0);      integer num = llCeil(llFrand(rannum));     integer x=0;     integer mo = 0;     do      {       mo += (maxodds-(x*odddiv));         x++;      }       while(num>mo);     nums = llListReplaceList(nums,[llList2Integer(nums,x)+1],x,x);       llSetTimerEvent(0.1);       }   touch_start(integer total_number)    {     integer x;     for(x=0; x<range;x++)llSay(0,(string)(x+1)+" = "+ llList2String(nums,x+1)+" times");    //test string    }}

 

 

 

 

Link to comment
Share on other sites

I might add that although you say 1000 to one for 1, that does not mean a 1000 times more, a random number is not linear(can't be predicted), so therefore not a single dimensional number, so therefore it has more than one component to it, so by treating the maxodd like that you will get more of the 1000 times than the 1000 to 1, for example treat the number as having 2 dimensions, then it would be maxodds squared, for three then cubed.

So by squaring or cubing maxodds might give you a number that you want.

For example in the code above, if you add the line

maxodds = llCeil(llPow(maxodds,2));

just after the llSetmemoryLimit(0x4000); will increase the chances of one, to nearer the 1000 times over 118 that you want.

Link to comment
Share on other sites

Sorry for keep commenting in this thread, but your question vexes me, you claim not to know, that may be true or it could be that you do know and that to get exactly what you want is just out side the range in the integer math's of script, until you posed the question I did not think about it, now you made me think about it you have in fact asked an impossible question, like the grain of rice on a chess board, anyway I gave you a way to do it, you either knew that all along and just testing us as to what we really know or you didn't, but why pick 118 and 1000, it is those 2 numbers that put the solution just outside the range in the integers here.

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 4491 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...