#!/usr/bin/perl -l

# Podprocedura calkowanie() wykorzystuje algorytm Romberga do przyblizenia 
# calki funkcji $funkcja (przekazanej jako odwolanie do kodu) w przedziale 
# od $dolny do $gorny.
#
# Ta procedura obliczy ($kroki + 1) * ($kroki + 2) / 2 przyblizen calki,
# z ktorych ostatnie bedzie najdokladniejsze.
#
# Funkcja calkowanie() przerywa wczesniej prace, jesli posrednie przyblizenie
# zmieni sie o mniej niz $epsilon.
#
sub calkowanie {
    my ($funkcja, $dolny, $gorny, $kroki, $epsilon) = @_;
    my ($h) = $gorny - $dolny;
    my ($i, $j, @r, $suma);

    # Poczatkowe przyblizenie.
    $przyblizenie[0][0] = ($h / 2) * ( &{$funkcja}( $dolny ) + &{$funkcja}( $gorny ) );

    # Obliczenie kolejnych wierszy tablicy Romberga.
    for ($i = 1; $i <= $kroki; $i++) {

        $h /= 2;
        $suma = 0;

        # Obliczenie pierwszej kolumny aktualnego wiersza.
        for ($j = 1; $j < 2 ** $i; $j += 2) {
            $suma += &{$funkcja}( $dolny + $j * $h );
        }
        $przyblizenie[$i][0] = $przyblizenie[$i-1][0] / 2 + $suma * $h;

        # Obliczenie pozostalych kolumn w danym wierszu.
        for ($j = 1; $j <= $i; $j++) {
            $przyblizenie[$i][$j] = ($przyblizenie[$i][$j-1] - $przyblizenie[$i-1][$j-1])
                / (4**$j - 1) + $przyblizenie[$i][$j-1];
        }

        # Czy wystarczajaco blisko?
        return $przyblizenie[$i][$i] if $epsilon and
            abs($przyblizenie[$i][$i] - $przyblizenie[$i-1][$i-1]) <= $epsilon;
    }
    return $przyblizenie[$kroki][$kroki];
}

# Podprocedura pasmo() zwraca przepustowosc pasma (w kilobajtach na sekunde) 
# miedzy Bostonem a Warszawa dla okreslonej godziny.
#
sub pasmo {
    my $czas = shift;
    $czas = $czas % 24 + $czas - int($czas);
    # Godziny pracy w Bostonie i Warszawie.
    if ($czas >= 3 && $czas < 17) {
        return 51 - 50 / (($czas - 10) ** 2 + 1);
    } else {
        $czas = 20 - $czas if $czas < 3;
        return 200 - 6 * (($czas - 22) ** 2);
    }
}

use constant epsilon  => 1e-14;
use constant pi       => 3.14159265358979;
use constant nieskonczonosc => 1000;

$piata_do_jedenastej_rano = calkowanie( \&pasmo,  5, 11, 6, epsilon ) * 3.6e6;
print $piata_do_jedenastej_rano;                                        # 713 MB

$piata_do_jedenastej_wieczorem = calkowanie( \&pasmo, 17, 23, 6, epsilon ) * 3.6e6;
print $piata_do_jedenastej_wieczorem;                                   # 3.4 GB

$dziewiata_do_jedenastej_rano = calkowanie( \&pasmo,  9, 11, 6, epsilon )  * 3.6e6;
print $dziewiata_do_jedenastej_rano;                                    # 84 MB

sub obszar{ 2 * pi / $_[0] }       # Powierzchnia wycinka rogu Gabriela
sub objetosc { pi / ($_[0] ** 2) } # Objetosc wycinka rogu Gabriela

$powierzchnia_gabriela   = calkowanie(\&obszar, 1, nieskonczonosc, 10, epsilon);
$objetosc_gabriela = calkowanie(\&objetosc, 1, nieskonczonosc, 10, epsilon);

print "Objetosc wynosi $objetosc_gabriela, ale powierzchnia to $powierzchnia_gabriela.\n";

