# 
# My solution features a liberal use of sprintf and defaults to spreading
# the error at the beginning of the list.
# 
# Garth

###############################################################################
# QOTW #7 - print fudged percentages so that they always add up to 100 given
# a data list
###############################################################################
use strict;

use constant FLOAT => 1; # size of difference (real-actual) allowable
                         # in final decimal place

my $precision = 2;
# my @data = (100, 100, 100);
my @data = (10, 20, 30, 30);

my @percents = fudge_numbers($precision, @data);
print "(", join(" , ", @percents), ")\n";


sub fudge_numbers {
    my($precision, @data) = @_;

    my @percentages;

    die("Negative precision not allowed.\n") if ($precision < 0);

    # calculate the of sum of the data elements, negative values are an error
    my $sum = 0;
    foreach my $datum (@data) {
        die("Negative value for data element.\n") if($datum < 0);
        $sum += $datum;
    }

    # Calculate the percentage for each element, rounding to the desired
    # precision
    foreach my $datum (@data) {
        my $percent = sprintf("%." . $precision . "f", $datum/$sum*100);
        push(@percentages, $percent);
    }

    # Determine the sum of the percentages and get the difference from
    # 100%
    my $difference = 100;
    foreach my $p (@percentages) {
        $difference -= $p;
    }

    # round to the appropriate level of precision
    $difference = sprintf("%." . $precision . "f", $difference);
    print "diff is $difference\n";

    # If the difference is positive then FLOAT units have to be added to the
    # percentage, negative means FLOAT units have to be removed.
    # The amount that each percentage can be changed is:
    # FLOAT * 10^(-)$precision
    my $adjustment = sprintf("%." . $precision . "f", FLOAT * 10 ** (-1 * $precision));

    if($difference > 0) {
        my $index = 0;
        while($difference > 0) {
            $percentages[$index] += $adjustment;
            $difference -= $adjustment;
        }
    } elsif ($difference < 0) {
        my $index = 0;
        while($difference < 0) {
            $percentages[$index] -= $adjustment;
            $difference += $adjustment;
        }
    }

    return @percentages;
}


