package Math::CMA;

use 5.010000;
use strict;
use warnings;
use List::Util qw/min max sum/;

require Exporter;

our @ISA = qw(Exporter);

our %EXPORT_TAGS = ( 'all' => [ qw(
  central_moving_averages
) ] );

our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );

our @EXPORT = qw(
	
);

our $VERSION = '0.1';

sub central_moving_averages {
  my $smoothing = shift;
  my @series = @{shift()};
  my $count = min($smoothing, $#series);
  my $left = -$count;
  my $right = $count;
  my $sum = 0;
  my @result;

  return @series unless $count > 0;

  # sum first element and window to the right
  for (0 .. $count) {
    $sum += $series[$_];
  }

  # head
  while ($left < 0) {
    push @result, $sum / ($right + 1);
    $left++;
    $sum += $series[++$right] if $right < $#series;
  }

  # middle part
  while (1) {
    push @result, $sum / ($right - $left + 1);
    $sum -= $series[$left++];
    last if $right >= $#series;
    $sum += $series[++$right];
  }

  # tail
  while (@result < @series) {
    push @result, $sum / ($right - $left + 1);
    $sum -= $series[$left++];
  }

  @result;
}

1;
__END__

=head1 NAME

Math::CMA - Central Moving Average noise removal

=head1 SYNOPSIS

  use Math::CMA 'central_moving_averages';
  my @averaged = central_moving_averages(2, [1, 2, 3, 4, 5]);
  # returns (2, 2.5, 3, 3.5, 4)

=head1 DESCRIPTION

The C<central_moving_averages> function takes a smoothing distance
and an array reference and returns a list that averages all values
in the input over the distance value, in other words, it returns
for each value in the input the arithmetic mean of that value plus
$distance many values before and $distance many values after it. A
practical application would be smoothing time series data.

=head2 EXPORTS

The function C<central_moving_averages> on request, none by default.

=head1 SEE ALSO

L<http://en.wikipedia.org/wiki/Moving_average>

=head1 AUTHOR / COPYRIGHT / LICENSE

  Copyright (c) 2012 Bjoern Hoehrmann <bjoern@hoehrmann.de>.
  This module is licensed under the same terms as Perl itself.

=cut
