#! perl -slw use strict; use Data::Dump qw[ pp ]; our $N ||= 1e4; sub pickGen { my $scale = shift; my $ref = @_ > 1 ? \@_ : $_[ 0 ]; my $total = 0; $total += $_ for @$ref; my $pickStick = pack 'C*', map{ ($_) x ( $scale * $ref->[ $_ ] * 10 / $total ) } 0 .. $#$ref; return sub { return ord substr $pickStick, rand length $pickStick, 1; }; } my @items = 'A' ..'C'; ## Your "difficult" weights: my @weights = map sqrt $_, 2, 5, 11; ## Only required for testing my $total = 0; $total += $_ for @weights; print "Required weights(%):\n\t", join"\t", map $_ *100 / $total, @weights; for my $scale ( 1, 10, 100 ) { ## Generate a picker (cost amortized over $N uses) my $picker = pickGen $scale, @weights; ## use it $N times my %stats; $stats{ $items[ $picker->() ] }++ for 1 .. $N; ## Check the results print "\nResults for $N picks (scale:$scale)\n\t", join "\t\t\t", map $stats{ $_ } *100 / $N, @items; }