#!/usr/local/bin/perl

# this fudges the percents according to which give the lowest percent errors

use strict;
use warnings;

{
  local $, = "\t";
  local $\ = "\n";
  print 'final percents: ', fudge_numbers(3, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1);
}

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

  my $multiplier = 10 ** $precision;

  my $sum = 0;
  for (@data) {
    $sum += $_;
  }

  my (@percents, @rounded_percents);
  for (@data) {
    my $percent = $_ / $sum * 100;
    my $rounded_percent = sprintf ("%0." . $precision . "f", $percent);
    push (@percents, $percent);
    push (@rounded_percents, $rounded_percent);
  }

  my $rounded_percent_sum = 0;
  for (@rounded_percents) {
    $rounded_percent_sum += $_;
  }

  my $error = sprintf "%0.0f", (100 - $rounded_percent_sum) * $multiplier;
  my $absolute_error = $error;
  $absolute_error = $error * -1 if $error < 0; # how many numbers to alter
  my $increment = ($error / $absolute_error) / $multiplier; # how much to alter each number

  # in this for loop we test alter each number and find the resulting percent error
  my (%error_hash);
  for my $i (0..$#rounded_percents) {
    my $fudged_percent = $rounded_percents[$i] + $increment;
    my $percent_error = ($percents[$i] - $fudged_percent) / $percents[$i] * 100;
    $percent_error *= -1 if $percent_error < 0;
    $error_hash{$i} = $percent_error;
  }

  my @sorted_indices = sort { $error_hash{$a} <=> $error_hash{$b} } keys
%error_hash;

  for (0..$absolute_error-1) {
    $rounded_percents[$sorted_indices[$_]] += $increment;
  }

  return @rounded_percents;
}
