Your requirements are met most naturally by using another probability distribution than the uniform one rand is crafted to deliver. The requirement of a lower bound $Nl is easily dealt with by just considering the interval 0..($Nu-$Nl) and adding $Nl to all results. The requirement for an upper bound restricts us to distributions with a finite range. The requirement for a specified mean forces us to look at distributions with more parameters than rand provides.

The ad-hoccery one's tempted into, simply filtering or adjusting a uniform distribution, will lead to 'random' numbers with bizarre statistical properties.

Abramowitz and Stegun reveals one standard probability distribution for continuous finite intervals, the beta disribution, and two for integers, the binomial distribution and the hypergeometeric.distribution. All three have enough adjustable parameters to satisfy your requirements.

Both integer distributions make use of the binomial coefficients <wish cap="MathMl"/>, so I'll give a simple recursive implementation:

sub binomial { my ($n,$s)=@_; $_[1]<=$_[0]/2 ? $_[1] ? 0 | ($_[0] - $_[1] + 1) * binomial( $_[0], $_[1] - 1) / +$_[1] : 1 : $_[1] != $_[0] ? 0 | ($_[1] + 1) * binomial( $_[0], $_[1] + 1) / ($_[0] - + $_[1]) : 1; }
This is not very efficient, but it staves off large intermediate numbers and avoids copying as much as possible in a recursive definition. You may wish to do this using &Math::BigInt::bfac instead.

The plan is to make a largeish array of numbers from the interval, each represented in proportion to its probability, and pick numbers from that array with rand as index. For the binomial distribution:

# Usage: # my @probs = prob_binomial( $span, $avg); # these are 0 based arguments, subtract the min you want to get them. sub prob_binomial { my ($max, $avg) = @_; my $p = $avg / $max; map {binomial($max, $_) * $p**$_ * (1-$p)**($max-$_)} 0..$max; } my $min = 6; my $max = 21; my $avg = 17; my $num = 40; my @problist = prob_binomial($max-$min,$avg-$min); # using ~1000 element array, adjust to suit ranges my @picklist = map {($min+$_) x int( .5 + 1000 * $problist[$_])} 0..$m +ax-$min; print $picklist[rand @picklist],$" for 1..$num;
For the hypergeometric distribution you get a free extra parameter you can use to tweak your results. this is its point probability function, in terms of three integers $N1 < $N2 and $n with $n < $N1+$N2:
sub prob_hyper { my ($N1,$N2,$n)=@_; my $span = $N1<$n? $N1 : $n; map {binomial($N1,$_) * binomial($N2,$n-$_) / binomial($N1+$N2,$n) +} 0..$span; }
This has the great advantage that the relative probabilities can be made integers by making its @picklist binomial($N1+$N2,$n) in length. Then your results will be exact.

Note that these methods don't force a particular list of randoms to take on the average. That will happens in the long run, it's all statistics! Enjoy.

Update: Forgot to mention, the mean for the hypergeometric distribution is $n*$N1/($N1+$N2).

After Compline,
Zaxo


In reply to Re: list of random numbers with given avarage by Zaxo
in thread list of random numbers with given avarage by LupoX

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.