#!/usr/bin/perl

$target_mean = 100;
$target_std_dev = 20;
$target_min = 0;
$target_max = 200;

$top_min = 1;
$top_exclude = 1/10;

$bottom_min = 1;
$bottom_exclude = 1/10;

sub max {
  my $i = shift;
  while (my $j = shift) {
    if ($i < $j) {
      $i = $j;
    }
  }
  return $i;
}

sub std_dev {
  my $num_args = 0;
  my $sum = 0;
  my $sum_squares = 0;

  my @l = @_;
  my $size = scalar @l;
  my $start = max($bottom_exclude * $size, $bottom_min);
  my $end = $size - max($top_exclude * $size, $top_min);
  
  for (my $i = $start; $i < $end; $i++) {
    $elt = $l[$i];
    $num_args++;
    $sum += $elt;
    $sum_squares += $elt * $elt;
  }

  if ($num_args < 2) {
    return 1;
  }

  my $es = $sum / $num_args;
  my $es2 = $es * $es;
  return sqrt(($sum_squares - $num_args * $es2) / ($num_args - 1));
}

sub mean { 
  my $num_args = 0;
  my $sum = 0;

  my @l = @_;
  my $size = scalar @l;
  my $start = max($bottom_exclude * $size, $bottom_min);
  my $end = $size - max($top_exclude * $size, $top_min);
  
  for (my $i = $start; $i < $end; $i++) {
    $elt = $l[$i];
    $num_args++;
    $sum += $elt;
  }

  if ($num_args == 0) {
    return 0;
  }
  return $sum / $num_args;
}

sub renormalize {
  my $grade = shift;
  my $mean = shift;
  my $sd = shift;

  if ($sd == 0) {
    $sd = 1;
  }
  my $grade = $target_mean + (($grade - $mean) / $sd) * $target_std_dev;
  if ($grade < $target_min) {
    $grade = $target_min;
  }
  elsif ($grade > $target_max) {
    $grade = $target_max;
  }

  return $grade;
}

