Práctica Vectores y Matrices (Organización del Computador II)

De Cuba-Wiki
Revisión del 03:42 10 oct 2006 de 201.235.224.78 (discusión) (→‎Ejercicio 20)
(difs.) ← Revisión anterior | Revisión actual (difs.) | Revisión siguiente → (difs.)

Ejercicio 20

Escribir una función que verifique si la suma el elementos de la diagonal principal es igual a la suma de elementos de la diagonal transpuensta (supongo que diagonal "transpuensta" es la antidiagonal).

Este codigo recorre una vez la matriz guardando en edx:eax la suma total de los elementos de la diagonal principal y salvandolos en la stack al terminar, luego hace lo mismo con la antidiagonal, compara y devuelve el resultado.

global diagEq

%define ptrMat	[ebp+8]
%define tamFila	[ebp+12]
%define sumAlta	[ebp-16]
%define sumBaja	[ebp-20]

section .text

diagEq:

;Armo stack frame
	push ebp
	mov ebp, esp
	push ebx
	push esi
	push edi
	sub esp, 8

;Preparo registros
	mov ecx, tamFila	;ecx = iterador
	mov edi, tamFila	;edi = tamaño fila
	mov esi, ptrMat		;esi = puntero a matriz
	xor edx, edx		;edx = parte alta de la suma acumulada
	xor eax, eax		;eax = parte baja de la suma acumulada

;Recorro diagonal principal

diag1:	
	mov ebx, [esi]		;ebx = elemento actual
	cmp ebx, 0x0		;Comparo con cero para ver que le sumo a la parte alta
	jl restar1

;sumar1:	
	add eax, ebx		;Sumo partes bajas
	adc edx, 0x0		;Paso el carry
	jmp seguir1

restar1:	
	add eax, ebx		;Sumo partes bajas
	adc edx, 0xFFFFFFFF	;Paso el carry y sumo la sign extension

seguir1:
	lea esi, [esi + 4*edi + 4]
	loop diag1

;Guardo acumulados
	mov sumAlta, edx
	mov sumBaja, eax
	

;Repito para anti diagonal

;Preparo registros
	mov ecx, tamFila	;ecx = iterador
	mov esi, ptrMat		;esi = puntero a matriz
	xor edx, edx		;edx = parte alta de la suma acumulada
	xor eax, eax		;eax = parte baja de la suma acumulada

;Recorro antidiagonal 
	lea esi, [esi + 4*edi - 4]
diag2:	
	mov ebx, [esi]		;ebx = elemento actual
	cmp ebx, 0x0		;Comparo con cero para ver que le sumo a la parte alta
	jl restar2

;sumar2:	
	add eax, ebx		;Sumo partes bajas
	adc edx, 0x0		;Paso el carry
	jmp seguir2

restar2:	
	add eax, ebx		;Sumo partes bajas
	adc edx, 0xFFFFFFFF	;Paso el carry y sumo la sign extension

seguir2:
	lea esi, [esi + 4*edi - 4]
	loop diag2

;Comparo
	xor ebx, ebx
	cmp edx, sumAlta
	jne fin
	cmp eax, sumBaja
	jne fin
	mov ebx, 0x1

fin:
	mov eax, ebx

;Retorno
	add esp, 8
	pop edi
	pop esi
	pop ebx
	pop ebp
	ret

Este codigo, en cambio, recorre primero la mitad superior de la matriz y luego la inferior, calculando la diferencia entre las dos diagonales, y luego la compara con cero.

global diagEq

%define ptrMat	[ebp+8]
%define tamFila	[ebp+12]

section .text

diagEq:

;Armo stack frame
	push ebp
	mov ebp, esp
	push ebx
	push esi
	push edi

;Preparo registros
	mov ecx, tamFila	;ecx = iterador
	mov edi, tamFila	;edi = tamaño fila
	mov esi, ptrMat		;esi = puntero a matriz
	xor edx, edx		;edx = parte alta de la suma acumulada
	xor eax, eax		;eax = parte baja de la suma acumulada

;Recorro matriz

diag:	
	mov ebx, [esi]		;ebx = elemento actual
	cmp ebx, 0x0		;Comparo con cero para ver que le sumo a la parte alta
	jl restar1

;sumar1:	
	add eax, ebx		;Sumo partes bajas
	adc edx, 0x0		;Paso el carry
	jmp seguir1
 
restar1:	
	add eax, ebx		;Sumo partes bajas
	adc edx, 0xFFFFFFFF	;Paso el carry y sumo la sign extension

seguir1:
	dec ecx	
	lea esi, [esi + 4*ecx]	;Apunto esi al elemento de la otra diagonal de la misma fila

	mov ebx, [esi]		;ebx = elemento actual
	cmp ebx, 0x0		;Comparo con cero para ver que le resto a la parte alta
	jl restar2

;sumar2:	
	sub eax, ebx		;Resto partes bajas
	sbb edx, 0x0		;Paso el carry
	jmp seguir2

restar2:	
	sub eax, ebx		;Resto partes bajas
	sbb edx, 0xFFFFFFFF	;Paso el carry y resto la sign extension

seguir2:
	dec ecx
	lea esi, [esi + 4*edi]	;Apunto esi al elemento de la diagonal ppal de la proxima fila
	neg ecx
	lea esi, [esi + 4*ecx]
	neg ecx
	jnz diag		;Loopeo mientras no sea cero


;Recorro la mitad inferior de la matriz

	mov ecx, tamFila	;Cargo en ecx de vuelta el tamaño de fila
	mov esi, ptrMat		;Apunto ecx al ultimo elemento
	mov ebx, edi
	imul ebx, edi
	lea esi, [esi + ebx - 1]

diagB:	
	mov ebx, [esi]		;ebx = elemento actual
	cmp ebx, 0x0		;Comparo con cero para ver que le sumo a la parte alta
	jl restarB1

;sumarB1:	
	add eax, ebx		;Sumo partes bajas
	adc edx, 0x0		;Paso el carry
	jmp seguirB1

restarB1:	
	add eax, ebx		;Sumo partes bajas
	adc edx, 0xFFFFFFFF	;Paso el carry y sumo la sign extension

seguirB1:
	dec ecx	
	neg ecx
	lea esi, [esi + 4*ecx]	;Apunto esi al elemento de la otra diagonal de la misma fila
	neg ecx

	mov ebx, [esi]		;ebx = elemento actual
	cmp ebx, 0x0		;Comparo con cero para ver que le resto a la parte alta
	jl restarB2

;sumarB2:	
	sub eax, ebx		;Resto partes bajas
	sbb edx, 0x0		;Paso el carry
	jmp seguirB2

restarB2:	
	sub eax, ebx		;Resto partes bajas
	sbb edx, 0xFFFFFFFF	;Paso el carry y resto la sign extension

seguirB2:
	dec ecx
	neg edi
	lea esi, [esi + 4*edi]	;Apunto esi al elemento de la diagonal ppal de la proxima fila
	neg edi
	lea esi, [esi + 4*ecx]
	jnz diagB		;Loopeo mientras no sea cero


;Comparo
	xor ebx, ebx
	cmp edx, 0
	jne fin
	cmp eax, 0
	jne fin
	mov ebx, 0x1

fin:
	mov eax, ebx

;Retorno
	pop edi
	pop esi
	pop ebx
	pop ebp
 	ret

Este es el codigo C para probar los dos asm anteriores

#include <stdio.h>

//Retorna 1 si true, 0 si false
//Recibe puntero a la matriz y ancho de fila/columna (matriz cuadrada)
extern int diagEq(int* matriz, int n); 

int main() {
	int m[16] = {
		0x7589AC45, 0x87221184, 0xAC449523, 0xFA57CD24,
		0x48792A98, 0xFA57CD24, 0x0F85AAEE, 0x4486AC66,
		0x65AA7854, 0x7589AC45, 0x0F85AAEE, 0xFFA55712,
		0x4578AFDE, 0x2584742A, 0x567CFFA8, 0x4578AFDE	};
	
	int res= diagEq(m, 4);

	if (res==1) printf("Suma de diagonal y antidiagonal iguales.\n");
	else printf("Suma de diagonal y antidiagonal distintas-\n");

	return 0;

}