Operacje na macierzach

Program realizujący jednocześnie dodawanie i mnożenie dwóch macierzy. Dane – czyli dwie macierze – znajduja się w pliku wejściowym o nazwie podanej przy wywołaniu. Wynik działania programu jest umieszczany automatycznie w pliku wyjściowym o nazwie również podanej przy wywołaniu.
Liczby występujące w macierzach powinny być z zakresu: 0-100
Ogólna postać macierzy dla m kolumn i n wierszy:

m n
A11 A12 A13 …… A1m
A21 A22 A23 …… A2m
A31 A32 A33 …… A3m
… … … …… …
An1 An2 An3 …… Anm

Przykłady zapisu macierzy:

3 4
1 3 4
4 5 2
1 1 1
8 9 9

5 5
01 22 33 12 43
92 23 43 21 12
22 22 22 22 22
66 66 66 66 66
13 56 56 21 32

Przykład wywołania Programu:

program2 dane1.wej dane1.wyj

; by Pawel Konieczny
; ver 1.0
.186
;................. Segment danych .................
dane1 segment
f_in    db    10 dup (?),'0'     ; nazwa pliku wejsciowego
f_out    db    10 dup (?),'0'     ; nazwa pliku wyjsciowego
buf_in    db    1000 dup ('$')
buf_out    db    1000 dup ('$')
error_1   db    'Niewlasciwy parametr$'
error_2   db    'Nie mozna czytac z pliku wejsciowego$'
error_3   db    'Nie mozna zamknac pliku$'
error_4   db    'Nie mozna znalezc pliku wejsciowego$'
error_5   db    'Nie mozna stworzyc pliku wyjsciowego$'
error_6   db    'Nie mozna zapisac do pliku wyjsciowego$'
kom_1     db    'Nie mozna dodac macierzy. $'
kom_2     db    'Dodawanie macierzy ...$'
kom_3    db    'Nie mozna pomnozyc macierzy. $'
kom_4     db      'Mnozenie macierzy ...$'
uchwyt    dw    ?    ; wskaznij do pliku wejsciowego
uchwyt2   dw    ?    ; wskaznik do pliku wyjsciowego
x1        dw    ?    ; pierwsza wspolrzedna pierwszej macierzy
x2        dw    ?    ; druga wspolrzedna pierwszej macierzy
x3        dw    ?    ; pierwsza wspolrzedna drugiej macierzy
x4        dw    ?    ; druga wspolrzedna drugiej macierzy
sk        dw    ?       ; skok do danych o wspolrzednych w drugiej macierzy
sk1    dw    ?    ; skok do nastepnego rzedu w macierzy 1
sk2    dw    ?       ; skok do nastepnej liczby w kolumnie w macierzy 2
w1        dw    ?       ; wskazuje na elementy pierwszej macierzy
w2    dw    ?       ; wskazuje na elementy drugiej macierzy
norma1    dw    ?
norma2    dw    ?
ok2    dw    ?
licz1     dw    ?
licz2     dw    ?
licz3    dw    ?
dane1 ends
;..................................................

ASSUME cs:code1, ds:dane1, ss:stos1

;................. Segment kodu ...................
code1 segment
start:
mov ax,seg dane1
mov ds,ax

; Na poczatku zapisujemy rozmiary pierwszej macierzy do zmiennych x1, x2.
; Dalej, na podstawie znajomosci tych danych wykonywany jest skok do
; miejsca w pliku, gdzie przechowywane sa rozmiary drugiej macierzy x3, x4

call CzyParam
inc bx                  ; przechodzimy przez spacje
xor di,di
call CzytPar1
next1:
cmp di,0
je Komunikat5         ; gdy nie ma pierwszego parametru
xor di,di
call CzytPar2
next2:
cmp di,0
je Komunikat6         ; gdy nie ma drugiego parametru
call OtwPlikWej
call CzytPlikWej
call StwPlikWyj
call OtwPlikWyj

; wczytywanie zmiennych

mov di,0           ; di = 0 wskazuje na pierwsza pozycje w pliku
call Czytaj        ; pierwsza pozycje z pliku ...
mov [x1],ax          ; ... zapisz do x1

add di,3           ; di = 3 wskazuje na czwarta pozycje w pliku, ...
call Czytaj        ; ... ktora zpisujemy ...
mov [x2],ax          ; ... do x2

call Skok          ; obliczamy, gdzie znajduja sie w pliku dane drugiej macierzy

mov di,[sk]
call Czytaj        ; pierwsza wspolrzedna 2. macierzy ...
mov [x3],ax          ; ... zapisz do x3 ...

add di,3           ; ... druga, odlegla o 3 bajty od pierwszej ...
call Czytaj        ; ... odczytaj ...
mov [x4],ax          ; ... i zapisz do x4

; sprawdzanie poprawnosci romiaru macierzy w przypadku ich dodawania

mov ax,[x1]
cmp ax,[x3]
jne Kom1     ; gdy x1 != x3 skocz do mnozenia
mov ax,[x2]
cmp ax,[x4]
jne Kom1     ; gdy x2 != x4 skocz do mnozenia

; dodawanie macierzy

call Kom2
mov [w1],7           ; zaczynamy wczytywanie od siodmego bajtu, ...
mov ax,[x2]          ; ... bo tu jest pierwsza wspolrzedna
mov [licz2],ax       ; licz2 = x2

; -------------------------------
for1:
mov ax,[x1]
mov [licz1],ax      ; licz1 = x1
for2:
mov di,[w1]
call Czytaj        ; czytaj pierwszy skladnik z miejsca 'di' i umiesc w ax
push ax            ; poloz na stosie pierwszy skladnik

add di,[sk]          ; di = w1 + sk
call Czytaj        ; czytaj drugi skladnik z miejsca 'di' i umiesc w ax

pop bx             ; sciagnij ze stosu pierwszy skladnik
add ax,bx          ; dodaj do drugiego
call Zapisz        ; czytaj liczbe z ax i zapisz ja do pliku
call Spacja

add [w1],3         ; w1 = w1 + 3, przejscie przez spacje
dec [licz1]
cmp [licz1],0
jne for2
call Nwln

inc [w1]            ; przejscie do nowej linii
dec [licz2]
cmp [licz2],0
jne for1
; -------------------------------
call Nwln

; sprawdzanie poprawnosci romiaru macierzy w przypadku ich mnozenia

mnozenie:
mov ax,[x1]
cmp ax,[x4]
jne Kom3     ; gdy x1 != x4 wyjdz z programu

; mnozenie macierzy

call Kom4
call Skok1
call Skok2

mov ax,[x1]          ;         .....
mov [licz1],ax       ;      licz1 = x1
mov ax,[x2]          ;         ....
mov [licz2],ax       ;         ....
mov ax,[x3]
mov [licz3],ax       ;   licz3 = licz2 = x2

mov [w1],7           ; zaczynamy wczytywanie od siodmego bajtu, bo tu jest pierwsza wspolrzedna
mov [norma1],7       ; norma1 = w1 = 7
mov ax,[sk]
add ax,7
mov [w2],ax          ; w2 = sk + 7
mov [norma2],ax
mov [ok2],ax         ; ok2 = norma2 = w2 = sk + 7
xor cx,cx

; -------------------------------
for4:                ; jedno przejscie w1 x1 razy
mov di,[w1]
call Czytaj        ; czytaj pierwszy skladnik z miejsca 'di' i umiesc w ax
push ax            ; poloz na stosie pierwszy skladnik
mov di,[w2]        ;
call Czytaj        ; czytaj drugi skladnik z miejsca 'di' i umiesc w ax
pop bx             ; sciagnij ze stosu pierwszy skladnik
mul bx             ; pomnoz ax przez bx
add cx,ax          ; dodaj do sumy 'cx'
add [w1],3           ; zwieksz w1 o 3, przejscie przez spacje
mov ax,[sk2]
add [w2],ax          ; zwieksz w2 o 'sk2'
dec [licz1]
cmp [licz1],0
jne for4             ; powtarzaj x1 razy
mov ax,cx
call Zapisz        ; zapisz liczbe
call Spacja        ; wstaw spacje
xor cx,cx          ; zerowanie sumy
mov ax,[norma1]
mov [w1],ax          ; wroc do poczatku linii
add [norma2],3       ; przejdz przez spacje do kolejnego rzedu drugiej macierzy
mov ax,[norma2]      ;      .......
mov [w2],ax          ;    w2 = norma2
mov ax,[x1]          ;       .....
mov [licz1],ax       ;    licz1 = x1
dec [licz3]
cmp [licz3],0
jne for4
call Nwln
xor cx,cx            ; zerowanie sumy
mov ax,[sk1]
add [norma1],ax      ; przejscie do nowej linii
mov ax,[norma1]      ;       ......
mov [w1],ax          ;     w1 = norma1
mov ax,[ok2]         ; wroc do pierwszego rzedu macierzy drugiej
mov [norma2],ax      ;      .......
mov [w2],ax          ;     w2 = norma2 = ok2
mov ax,[x1]          ;         ....
mov [licz1],ax       ;      licz2 = x2
mov ax,[x3]
mov [licz3],ax
dec [licz2]
cmp [licz2],0
jne for4
; ---------------------------------

call ZamkPlikWej
call ZamkPlikWyj
call Koniec

; =========================   Procedury   ===============================

CzyParam PROC               ; sprawdzenie czy sa parametry
mov bx,80h           ; sprawdzamy czy istnieje ...
mov cl,byte ptr es:[bx]       ; ... jakikolwiek parametr
cmp cl,0             ; jesli nie ma zadnego parametru, to ...
je Komunikat1        ; ... wypisz blad
ret
CzyParam ENDP

CzytPar1 PROC               ; czytanie pierwszego parametru
inc bx               ; parametry zaczynaja sie od 82h
mov dl,byte ptr es:[bx]       ; wczytujemy znak do dl
cmp dl,' '
je next1
mov f_in[di],dl      ; a nastepnie do bufora, ktory bedzie nazwa pliku
inc di
jmp CzytPar1
ret
CzytPar1 ENDP

CzytPar2 PROC               ; czytanie drugiego parametru
inc bx
mov dl,byte ptr es:[bx]       ; wczytujemy go do dl
cmp dl,0dh
je next2
mov f_out[di],dl     ; a nastepnie do bufora ,ktory bedzie nazwa pliku
inc di
jmp CzytPar2
ret
CzytPar2 ENDP

OtwPlikWej PROC             ; otwieranie pliku wejsciowego
mov ax,3d00h         ; otwieramy plik do odczytu
lea dx,[f_in]
int 21h
jc Komunikat4
mov [uchwyt],ax
ret
OtwPlikWej ENDP

CzytPlikWej PROC            ; czytanie z pliku wejsciowego do 'buf_in'
mov ax,3f00h
mov bx,[uchwyt]
mov cx,300         ; czytamy po 1 bajcie
lea dx,[buf_in]       ; do bufora
int 21h
jc Komunikat2
ret
CzytPlikWej ENDP

StwPlikWyj PROC             ; utworzenie pliku wyjsciowego
mov ax,3c00h        ; numer funkcji - utworzenie
xor cx,cx
lea dx,[f_out]    ; adres nazwy pliku
int 21h
jc Komunikat5
ret
StwPlikWyj ENDP

OtwPlikWyj PROC             ; otwieranie pliku wyjsciowego
mov ax,3d02h         ; otwieramy plik do zapisu
lea dx,[f_out]
int 21h
jc Komunikat4
mov [uchwyt2],ax
ret
OtwPlikWyj ENDP

Czytaj PROC                 ; czytanie z 'buf_in' i zapisywanie do 'ax'
mov al,[buf_in+di]  ; adres zmiennej ze stringiem
xor ah,ah
sub al,30h            ; ascii -> cyfra
mov bx,ax
shl ax,3                ; mnozenie przez 10
shl bx,1
add ax,bx             ; tu juz jest liczba
push ax
mov al,[buf_in+di+1]
xor ah,ah
sub al,30h
pop bx
add bx,ax
mov ax,bx
ret
Czytaj ENDP

Skok PROC                   ; obliczanie skoku do danych drugiej macierzy
mov ax,[x1]
add ax,[x1]
add ax,[x1]
inc ax
mul [x2]
add ax,9             ; ax = (3 * x1 + 1) * x2 + 9
mov [sk],ax            ; dlugosc skoku
ret
Skok ENDP

Skok1 PROC                  ; obliczanie skoku do nowej linii w pierwszej macierzy
mov ax,[x1]
add ax,[x1]
add ax,[x1]
inc ax                   ; ax = (3 * x1 + 1)
mov [sk1],ax               ; dlugosc skoku
ret
Skok1 ENDP

Skok2 PROC                  ; obliczanie skoku do kolejnej liczby w kolumnie w drugiej macierzy
mov ax,[x3]
add ax,[x3]
add ax,[x3]
inc ax                   ; ax = (3 * x3 + 1)
mov [sk2],ax               ; dlugosc skoku
ret
Skok2 ENDP

Zapisz PROC                 ; zapisz liczbe do 'buf_out', pozniej do pliku
mov bl,10
div bl               ; al = al / 10

mov ch,ah
xor ah,ah
div bl               ; al = al / 10    -    pierwsza cyfra
mov cl,ah            ; w 'cl' jest druga cyfra

add al,'0'
mov [buf_out],al

add cl,'0'
mov [buf_out+1],cl

add ch,'0'
mov [buf_out+2],ch

mov ax,4000h
mov bx,[uchwyt2]
mov cx,3
lea dx,[buf_out]
int 21h
jc Komunikat6
ret
Zapisz ENDP

Spacja PROC                 ; umieszcza znak spacji w pliku
mov [buf_out],' '
mov ax,4000h
mov bx,[uchwyt2]
mov cx,1
lea dx,[buf_out]
int 21h
jc Komunikat6
ret
Spacja ENDP

Nwln PROC                   ; umieszcza znak przejscia do nowej linii w pliku
mov buf_out[0],13
mov buf_out[1],10
mov ax,4000h
mov bx,[uchwyt2]
mov cx,2
lea dx,[buf_out]
int 21h
jc Komunikat6
ret
Nwln ENDP

ZamkPlikWej PROC            ; zamykanie pliku wejsciowego
mov ax,3e00h
mov bx,[uchwyt]
int 21h
jc Komunikat4
ret
ZamkPlikWej ENDP

ZamkPlikWyj PROC            ; zamykanie pliku wyjsciowego
mov ax,3e00h
mov bx,[uchwyt2]
int 21h
jc Komunikat2
ret
ZamkPlikWyj ENDP

Koniec PROC                 ; powrot do systemu
mov ax,4C01h
int 21h
Koniec ENDP

Komunikat1:
lea dx,error_1         ; mov dx,offset error
call sh_err

Komunikat2:
lea dx,error_2         ; mov dx,offset error
call sh_err

Komunikat3:
lea dx,error_3         ; mov dx,offset error
call sh_err

Komunikat4:
lea dx,error_4         ; mov dx,offset error
call sh_err

Komunikat5:
lea dx,error_5         ; mov dx,offset error
call sh_err

Komunikat6:
lea dx,error_6         ; mov dx,offset error
call sh_err

Kom1:
lea dx,kom_1         ; mov dx,offset error
mov ah,9h
int 21h
jmp mnozenie

Kom2:
lea dx,kom_2         ; mov dx,offset error
mov ah,9h
int 21h
ret

Kom3:
lea dx,kom_3         ; mov dx,offset error
mov ah,9h
int 21h
call Koniec

Kom4:
lea dx,kom_4         ; mov dx,offset error
mov ah,9h
int 21h
ret

sh_err:                   ; wypisuje na ekran bledy
mov ah,9h
int 21h
call Koniec

code1 ends
;..................................................

;................ Segment stosu ...................
stos1 segment STACK
dw 3000 dup(?)
stos1 ends
;..................................................

END start

Dodaj komentarz