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;
}