use strict; use warnings; use List::Util 'max'; sub distribution { my %param = ( function => \&{scalar sub {return 1}}, sample_size => 1e5, @_); my @values; do { my($r1, $r2) = (rand, rand); push @values, $r1 if &{$param{function}}($r1) > $r2; } until @values == $param{sample_size}; wantarray ? @values : \@values; } sub modifier_notch { my($x) = @_; return 2 * ( $x < 1/2 ? ( 1/2 - $x ) : ( $x - 1/2 ) ); } sub print_histogram { our %param = (n_bins => 10, width => 80, @_); my %counts; $counts{ int($_ * $param{n_bins}) / $param{n_bins} }++ for @{$param{data}}; our $max_value = max values %counts; print "Bin Counts Histogram\n"; printf "%4.2f %6d: %s\n", $_, $counts{$_}, hist($counts{$_}) for sort keys %counts; sub hist { scalar ('■') x ( $param{width} * $_[0] / $max_value ) } } print_histogram( data => \@{ distribution() } ); print "\n\n"; my @samples = distribution( function => \&modifier_notch, sample_size => 50_000); print_histogram( data => \@samples, n_bins => 20, width => 64);