#!/usr/bin/perl # [c] piotao, 20070112 # Program wykonujacy mnozenie macierzy # Uruchomienie: # pomnoz.pl plik-danych.txt # - plik danych musi zawierac dwa bloki liczb, w N kolumnach i M wierszach # pomiedzy macierzami musi byc przynajmmiej jeden pusty wiersz use strict; use warnings; # deklarujemy dane my $N; # wymiar poziomy macierzy my $M; # wymiar pionowy macierzy # macierze: my @A = my @B = my @C = (); # wszystkie na razie sa pustymi tablicami # okreslenie argumentow programu # i zdecydowanie, czy dane beda podane z klawiatury interaktywnie, wczytane # z pliku danych lub wczytane nieinteraktywnie ze standardowego wejscia if( defined $ARGV[0] and -f $ARGV[0] ){ # mamy jeden argument i jest to plik #otwieramy i wczytujemy plik #zakladamy ze macierze sa wpisane w kolumnach i wierszach tak jak wyglada ich normalna #reprezentacja, a nastepna macierz jest oddzielona od poprzedniej jedna pusta linia, np: # 1 2 3 4 5 # 2 3 4 5 6 <---n---> # 3 4 5 6 7 # # 1 2 3 ^ # 2 3 4 | # 4 3 4 n # 4 3 2 | # 2 3 4 v # my $macierz = 'a'; # pierwsza macierz, do ktorej czytamy, to A my $file; # deklarujemy lokalna zmienna plikowa if( open $file,'<',$ARGV[0] ){ # jezeli udalo sie otworzyc plik, to mamy go w uchwycie $file while( <$file> ){ # wczytujemy w petli pojedyncze wiersze (do zmiennej $_) chomp; # usuwamy z kazdego kolejnego wiersza znak nowej linii if($_ eq ''){ # jezeli wczytalismy pusta linie $macierz = 'b'; # zmieniamy macierz, do ktorej wczytujemy dane next; # i od razu zaczynamy nastepna iteracje petli } my @wiersz = split; # dzielimy wczytany wiersz na osobne liczby i wpisujemy je do tablicy if($macierz eq 'a'){ # jezeli wczytywanie odbywa sie do macierzy A, to push @A,[@wiersz]; # zapamietujemy wiersz w macierzy A } else{ # a w przeciwnym wypadku push @B,[@wiersz]; # zapamietujemy wczytany wiersz w macierzy B } } } } else{ # nie podano zadnego pliku lub plik nie istnieje. die "Nie podano pliku z danymi macierzy do przemnozenia. Uruchom program z nazwa pliku jako argumentem.\n"; } # po wczytaniu macierzy, okreslamy ich rozmiar na podstawie macierzy A $N = scalar @{$A[0]}; # dlugosc pierwszego wiersza macierzy to wymiar poziomy $M = scalar @A; # dlugosc tabeli @A to wymiar pionowy macierzy # sprawdzamy rozmiary macierzy B my $Mb = scalar @{$B[0]}; # wymiar poziomy macierzy B (musi byc rowny pionowemu A) my $Nb = scalar @B; # wymiar pionowy macierzy B (musi byc rowny poziomemu B) unless($Mb == $M and $Nb == $N){ # gdy rozmiary macierzy nie pasuja do siebie, napisz to i zdechnij die "Nie pasuja do siebie wymiary macierzy A i B! A=[$M,$N], B=[$Mb,$Nb]\n"; } # teraz, gdy dane mamy wczytane, mozemy smialo mnozyc macierze! for(my $n=0; $n<$N; $n++){ # po wierszach @A i kolumnach @B for(my $m=0; $m<$M; $m++){ # po kolumnach @A i wierszach @B for(my $k=0; $k<$N; $k++){ # petla sumujaca wyniki mnozen $C[$n][$m] += $A[$n][$k] * $B[$k][$m]; } } } # piszemy teraz macierz A: map{ map{ printf "%4i",$_ } @{$_};print "\n" } @A; print "* \n"; #piszemy macierz B: map{ map{ printf "%4i",$_ } @{$_};print "\n" } @B; print "= \n"; # a teraz wypisywanie macierzy wynikowej: # ale najpierw sprawdzamy, jaka jest najwieksza dlugosc liczby # w calej macierzy, aby ladnie dobrac szerokosc kolumn my $len = 0; my $max = $len; for(my $m=0;$m<$N;$m++){ for(my $n=0;$n<$M;$n++){ $len = length($C[$m][$n]); if($max < $len){ $max = $len } } } ## sposob bardziej perlowy moze byc np. taki (sprawdz, to dziala) #for(map{map{ $_ } @{$_} } @C){ # $max = ( ($len = length $_) > $max) ? $len : $max; #} # majac dlugosc najdluzszego elementu macierzy C, ustalamy format # wypisywanych liczb: $max++; my $format = "\%${max}i"; # (ten sposob pisania wykorzystuje dwie zaglebione petle for # i moze niektorym z Was wydawac sie prostszy, ale raczej # nie jest prostszy... :) prostsze jest wykorzystanie MAP) for(my $m=0;$m<$N;$m++){ for(my $n=0;$n<$M;$n++){ printf $format,$C[$m][$n]; } print "\n"; }