Pathologically Eclectic Rubbish Lister PerlMonks

### custom random number generator

 on Nov 29, 2011 at 15:36 UTC Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

i'm working on a perl script and i need a very specific random number generator.

what i have right now is multrand. it returns a random number between x/y and x*y, with the median result being x. half the time less than x, half the time, greater than x.

i want to build a sub that returns a random in the same range, but with the result more likely to be closer to x.

with a simple random, i'd just run the sub z times and return result/z. graph the results of that, and you get a bell curve.

the results/z method won't work here because i still want the results to be half the time less than x and half the time greater than x.

any ideas?

```sub multrand {
my ( \$inmed, \$inmult ) = @_;
my \$randreturn = 0;
# \$randtemp is used to determine if result will be more than,
+less than, or equal to original
my \$randtemp = int(rand(\$inmed * 2));
if ( \$randtemp > \$inmed ) {
# \$randreturn can be up to \$inmed * \$inmult
\$randreturn = int(rand((\$inmed*\$inmult)-\$inmed)) + int
+(\$inmed);
} elsif ( \$randtemp < \$inmed ) {
# \$randreturn can be as little as \$inmed / \$inmult
\$randreturn = int(rand(\$inmed*(1-(1/\$inmult)))) + int(
+\$inmed*(1/\$inmult));
} else {
\$randreturn = \$inmed;
}

if ( \$debug > 2 ) {
print "\$randreturn\n";
}
return \$randreturn;
}

Replies are listed 'Best First'.
Re: custom random number generator
by salva (Abbot) on Nov 29, 2011 at 16:17 UTC
```\$r = \$x * \$y ** (1 - rand 2);

update:

Or if you want to reduce the variance:

```\$r = \$x * \$y ** ((1 - rand 2) ** \$n)
where \$n is an odd integer bigger than one.
Re: custom random number generator
by BrowserUk (Pope) on Nov 29, 2011 at 18:12 UTC

Improved and better tested:

```#! perl -slw
use strict;
use Data::Dump qw[ pp ];
use Math::Random::MT qw[ rand srand ];

sub xrand {
my( \$x, \$y ) = @_;
my \$lo = \$x / \$y;
my \$hi = \$x * \$y;
if( rand() < 0.5 ) {
my \$root = sqrt( \$hi - \$x );
my \$rv = rand( \$root )**2 + \$x;
return \$rv;
}
else {
my \$diff = \$x - \$lo;
my \$root = sqrt( \$diff );
my \$rv = ( \$diff - rand( \$root )**2 ) + \$lo;
return \$rv;
}
}

our \$T //= 1000;
our \$X //= 10;
our \$Y //= 2;
my \$min = \$X / \$Y;
my \$max = \$X * \$Y;

my( \$loCount, \$exactX, \$hiCount ) = (0) x 3;
my  %dist;
for ( 1 .. \$T ) {
my \$rand = xrand( \$X, \$Y );
die 'Out of range' unless \$rand >= \$min and \$rand <= \$max;
if( \$rand < \$X ) {
++\$loCount;
}
elsif( \$rand > \$X ) {
++\$hiCount;
}
else {
++\$exactX;
}
++\$dist{ int( \$rand *10 ) / 10 };
}

pp \%dist;

printf "After \$T samples %f%% < %f%% < %f%%\n",
\$loCount * 100 / \$T, \$exactX *100 / \$T, \$hiCount * 100 / \$T;

With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
Re: custom random number generator
by JavaFan (Canon) on Nov 29, 2011 at 17:10 UTC
Without further constraints, why not take a random number, if it's less than 0.5, return a random number between x/y and x; if the first random number exceeds 0.5, return a random number between x and x*y. Something like (untested):
```sub r2 {
my (\$low, \$high) = @_;
\$low + rand(\$high-\$low);
}
sub myrand {
my (\$x, \$y) = @_;
rand() < .5 ? r2(\$x/\$y, \$x) : r2(\$x,\$x*\$y);
}
(This assumes 1 <= \$y < \$x; adjust to taste).
Re: custom random number generator
by TJPride (Pilgrim) on Nov 29, 2011 at 20:56 UTC
I think you'll like this. Not only does it randomize your values for you, but it gives a visual display of the result so you can see the distribution. Change the weight to see how it affects things - larger numbers mean closer to \$x, smaller means further, with 1 being classic bell curve.

```use strict;
use warnings;

my (\$x, \$y, \$weight, @r) = (5, 10, 2);

push @r, multirand(\$x, \$y, \$weight) for 1..10000;
display(\@r, 50);

sub multirand {
my (\$x, \$y, \$weight) = @_;
return \$x * \$y ** (rand() ** \$weight * (rand() > 0.5 ? 1 : -1));
}

sub display {
my (\$r1, \$max) = @_;
my (@r2, \$skip, \$i);

\$skip = (\$#\$r1 + 1) / 40;
@r2 = sort { \$a <=> \$b } @\$r1;

for (\$i = 0; \$i <= \$#r2; \$i += \$skip) {
print 'x' x (\$r2[\$i] / \$max * 80 + 0.5) . "\n";
}
}

Output:

```x
x
x
xx
xx
xx
xxx
xxx
xxx
xxxx
xxxx
xxxxx
xxxxx
xxxxxx
xxxxxx
xxxxxxx
xxxxxxx
xxxxxxxx
xxxxxxxx
xxxxxxxx
xxxxxxxx
xxxxxxxx
xxxxxxxx
xxxxxxxx
xxxxxxxxx
xxxxxxxxx
xxxxxxxxxx
xxxxxxxxxxx
xxxxxxxxxxxx
xxxxxxxxxxxxx
xxxxxxxxxxxxxx
xxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Re: custom random number generator
by toro (Beadle) on Nov 30, 2011 at 07:24 UTC

Anonymous Monk, you could

1. do your bell curve trick to produce a standard normal ∈ (−∞, +∞) centred on 0
2. map the negative half (−∞, 0] thru exp onto 0,1 and thence thru ƒ(\$num) = x over {1 + y • (1 − \$num)} onto [x/y, x].
3. map the positive half (0, +∞) thru g(\$rand) = 1−exp(−\$rand) onto (0,1) and thence thru h(\$num) = x • (1 + \$num • y) onto (x, xy).
. That will be centred on x, mound-shaped, and put half the probability mass on either side of x — stretched according to your whims.

Re: custom random number generator
by BrowserUk (Pope) on Nov 29, 2011 at 16:51 UTC

Update: Ignore this. It works for my test values, but not for others.

With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.

Create A New User
Node Status?
node history
Node Type: perlquestion [id://940642]
Approved by marto
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (2)
As of 2018-04-22 17:06 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
My travels bear the most uncanny semblance to ...

Results (83 votes). Check out past polls.

Notices?