# 
# Just for fun, I added an additional requirement: When it's necessary to
# tweak numbers, do the largest ones first (so that the proportional error
# is smaller). Furthermore, if two values are equal it should be random
# which one gets fudged so that there's no bias introduced by the order of
# the arguments. (Of course, this makes the output non-deterministic :)
# 
#!/usr/bin/perl
use warnings;
use strict;

print join(' ', fudge_numbers(1, 10, 20, 30)), "\n";

sub fudge_numbers {
    my $p    = shift; # display precision
    my @data = @_;

    my $sum = 0;
    $sum += $_ foreach (@data);

    # Auxillary array containing indices of @data sorted by the value at
    # that index. For equal values we take them in random order. (n.b.
    # sort() is stable in 5.8.0)
    my $n = 0;
    my @indices =
        map  {$_->[1]}
        sort {$b->[0] <=> $a->[0] || int(rand(2)) ? 1 : -1}
        map {[$_, $n++]}
        @data;

    # format data and determine percentage total
    my $psum = 0;
    foreach (@data) {
        $_ = sprintf("%.${p}f", 100 * $_ / $sum);
        $psum += $_;
    }

    # determine fudge factor
    my $ff = ($psum > 100) ? -10 ** -$p : 10 ** -$p;

    # adjust data so that it totals 100%
    while (sprintf("%.${p}f", $psum) != sprintf("%.${p}f", 100)) {
        $data[shift @indices] += $ff;
        $psum += $ff;
    }
    return @data;
}

