# 
# Hello,
# 
# Here is my solution to Novice QOTW #7.  I haven't checked the
# spoilers, but I assume it is similar to others posted.
# 
# The idea is simple.
# * Sum up the input numbers, and find the difference w.r.t. 100.
# * Use the input precision to determine how many "ticks" there
#     are in the difference, where one "tick" must be given to
#     one number in the input, to fudge it.
# * Distribute the ticks across the scaled numbers, and return the new list.
# ----------------------8<----------------------8<----------------------
#!/usr/bin/env perl -s

# $Id: qotw7.pl,v 1.5 2002/12/02 15:32:23 ksundar Exp ksundar $

# Intention: Solve QOTW #7.

use 5.006;
use warnings;
use strict;

sub sum {
    my $s;
    $s += $_ for @_;
    $s;
}

my $TOTAL = 100;	# What should we add up to?

sub fudge_numbers {
    my $precision = shift;
    die "Error: \$precision = $precision is not a whole number\n"
	unless $precision =~ /^\d+$/;

    my $sum = &sum(@_);

    # Scale the numbers; round them off to $precision decimals.
    my @x = map {sprintf "%.${precision}f", $_ * $TOTAL / $sum} @_;

    my $delta = $TOTAL - &sum(@x);

    return @x unless $delta; # No fudging needed.

    # Round $delta to $precision decimals.
    $delta = sprintf "%.${precision}f", $delta;

    my $ticks = abs($delta*(10**$precision));

    my $epsilon = $delta/$ticks;

    # Fudge the last $ticks elements.
    $x[-$_] += $epsilon for 1..$ticks;

    @x;
}

# __BEGIN__

my @x = &fudge_numbers(@ARGV);

$" = $, = " ";
print &sum(@x), "=", @x, "\n"
    #if &sum(@x) != $TOTAL
    ;

__END__

Bugs:
&fudge_numbers(qw(0 1 1 1 1 1 1)) should yield
"16 16 17 17 17 17" and not "15 17 17 17 17 17".
----------------------8<----------------------8<----------------------

peace,                              || From Child Labour to Scholarship
--{kr.pA}                           || http://makeashorterlink.com/?J17F21842
-- 
"The war [on Iraq] is a weapon of mass distraction."  -- Seen on a placard.
