#!/usr/bin/perl -w

use strict;
use List::Util qw(reduce sum);

my $rzad = shift @ARGV;       # pobieramy argument z wiersza polecen
$rzad = 1 if !defined $rzad;  # domyslnie ustawiamy 0 gdy nie podano rzedu
my @dane;                     # w tej zminnej bedziemy trzymali wczytane dane

while(<>){                    # dopoki sa jakies wiersze, to wczytuj do $_
  chomp;                      # usun z konca napisu znak nowego wiersza
  push @dane,$_;              # wstaw na koncu tablicy z danymi
}

# wypisz wynik obliczen sredniej
print "Srednia rzedu $rzad wynosi: ";
printf "%1.4f", srednia_ogolna($rzad,@dane);

exit;

sub srednia_ogolna {
  my $rzad = shift;     # zdejmujemy pierwszy argument z listy argumentow - to bedzie rzad
  my @dane = @_;        # reszte argumentow - cala liste danych po prostu przepisujemy

  # zwracamy wartosc Not Available Number gdy nie ma danych do usredniania
  return "NaN" if !scalar @dane;

  if($rzad==0){   # jezeli rzad sredniej jest 0, to jest to srednia geometryczna
    return (reduce {$a*$b} @dane) ** ( 1/scalar @dane );
  }
  elsif($rzad == -1){ # srednia harmoniczna
    return scalar(@dane) / reduce { 1/$a + 1/$b } @dane;
  }
  else{ # pozostale przypadki, w tym dla $rzad=1 srednia arytmetyczna
    return ( (sum map { $_ ** $rzad } @dane) / scalar @dane ) ** (1/$rzad);
  }
}

__END__

=pod

=head1 Srednie Uogolnione

  srednia.pl - obliczanie srednich uogolnionych.

=head2 Wersja

  1.00, [c]piotao, 20070220, perl v5.8.8, x86_64-linux-thread-multi

=head2 Streszczenie

  srednia.pl 3 < dane.txt
  cat dane.txt | srednia.pl 2
  ...

=head2 Opcje i sposob uzycia

Program nalezy uruchomic z jednym argumentem - stopniem sredniej (w zadaniu
chodzi o liczbe 0, 1 lub 2, ale mozna podac dowolna).  Dane wczytywane sa ze
standardowego wejscia az do napotkania konca pliku. Przykladowa sesja pracy z
programem moze wygladac np. tak:

  perl srednia.pl 0
  1
  2
  3
  Ctrl+D
  Srednia rzedu 0 wynosi 1.8171

=head2 Wymagania i zaleznosci

Program korzysta z modulu List::Util, z ktorego importuje nazwy dwoch funkcji:
C<reduce> oraz C<sum>. Pierwsza z nich dziala tak, ze wykonuje blok dla kazdej
danej z podanego ciagu danych. Zmienne C<$a> i C<$b> ktore mozna umiesic w
bloku beda kolejnymi danymi ze strumienia danych. Pierwsze wykonanie bloku
pobierze dwie pierwsze dane ze strumienia, nastepne wykonania beda pobierac po
jednej i podstawiac ja do zmiennej C<$b>. Zmienna C<$a> bedzie zawierala wynik
poprzednio obliczony w tym samym bloku dla poprzedniej pary zmiennych.
Dzialanie C<sum> polega na prostym arytmetycznym sumowaniu ciagu argumentow.

=cut