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; } #### # 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..$max-$min; print $picklist[rand @picklist],$" for 1..$num; #### 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; }