Sumar polinomios en lenguaje ensamblador
Esta semana he estado haciendo una práctica de ensamblador, consistia en sumar dos polinomios desde ensamblador pas ándole los parámetros desde C a ensamblador.
Primero definiremos la práctica para entender mejor el código. Tenemos dos polinomios de exponentes siempre positivos, y en este caso no más grandes de 20 términos, aunque esto es lo de menos se puede modificar facilmente en el código y adaptarlo al tamaño del polinomio que necesitemos.
Cada polinomio está formado por dos vectores uno tendrá el indice del coeficiente y otro el indice del exponente.
Por ejemplo así:
1 2 3 4 | int p_coef[20]={-16,+10,+18,+2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //coeficientes del polinomio P int p_exp [20]={+15,+ 9,+ 5,+1,+0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; //exponentes del polinomio P |
Sería igual a este: -16*x^15 +10*x^9 +18*x^5 +2*x^1 -1*x^0
Los terminos “vacios” en el polinomio los hemos dejado como 0 ^-1, por lo tanto hemos rellenado las posiciones sin terminos con 0^1 hasta 20 que es el tamaño que hemos definido para el polinomio.
Si realizamos la suma de los dos polinomios p y q que tenemos declarados en el código obtendremos este resultado.
+1*x^10 -8*x^9 +5*x^8 +12*x^7
-16*x^15 +10*x^9 +18*x^5 +2*x^1 -1*x^0
————————————— ———————————————-
-16*x^15 +1*x^10 +2*x^9 +5*x^8 +12*x^7 +18*x^5 +2*x^1 -1*x^0
Segundo, ahora comentaremos como funciona el código. Para empezar declaramos en C los polinomios y creamos una función que mostrará el polinomio por pantalla.
1 2 3 4 5 6 7 8 9 10 | int p_coef[20]={-16,+10,+18,+2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //coeficientes del polinomio P int p_exp [20]={+15,+ 9,+ 5,+1,+0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; //exponentes del polinomio P int q_coef[20]={+0,+0,+0,+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int q_exp [20]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; int r_coef[20]={ +1,-8,+5,+12,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int r_exp [20]={+10,+9,+8, +7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; |
Función que mostrará el polinomio:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | void p_print(int v_coef[], int v_exp[]){ if (v_exp[0]==-1) { printf ("Polinomi sense termes \n\n"); } else { int i=0; while (v_exp[i]!=-1 && i<20) { if (v_coef[i]>=0) printf (" +"); else printf (" "); printf("%d*x^%d ",v_coef[i], v_exp[i]); i++; } printf("\n\n"); } } |
Y por último llamamos al código escrito en ensamblador pasándole los parametros que queremos:
suma_ensamblador(r_coef,r_exp,p_coef,p_exp,q_coef,q_exp);
Es importante el orden en el que los ponemos, pues al código ensamblador le llegará el primer parametro a traves del registro rdi, el segundo llegará a rsi, y sucesivamente llegarán a rdx, rcx, r8 y por último r9.
Este es el código completo con comentarios escrito en C:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | #include <stdio.h> /** la función que mostrará el polinomio **/ void p_print(int v_coef[], int v_exp[]){ if (v_exp[0]==-1) { printf ("Polinomi sense termes \n\n"); } else { int i=0; while (v_exp[i]!=-1 && i<20) { if (v_coef[i]>=0) printf (" +"); else printf (" "); printf("%d*x^%d ",v_coef[i], v_exp[i]); i++; } printf("\n\n"); } } int main() { /** * Programa Principal */ int p_coef[20]={-16,+10,+18,+2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //coeficientes del polinomio P int p_exp [20]={+15,+ 9,+ 5,+1,+0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; //exponentes del polinomio P int q_coef[20]={+0,+0,+0,+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int q_exp [20]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; int r_coef[20]={ +1,-8,+5,+12,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int r_exp [20]={+10,+9,+8, +7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; printf("Polinomio p(x)\n"); p_print(p_coef, p_exp); printf("Polinomio q(x)\n"); p_print(q_coef, q_exp); printf("******************************************\n"); p_print(r_coef, r_exp); p_print(p_coef, p_exp); printf("---------------------------------------*\n"); suma_ensamblador(r_coef,r_exp,p_coef,p_exp,q_coef,q_exp); p_print(q_coef, q_exp); } |
Este es el código comentado escrito en ensamblador para la arquitectura de 64bits (x86-64):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | section .data section .text ; declaramos las subrutinas que queremos hacer visibles desde C global suma_ensamblador ; Sumaos dos polinomios. t(x)=r(x)+s(x) ; Paràmetres d'entrada : r_coef(rdi), r_exp(rsi), ; s_coef(rdx), s_exp(rcx), ; t_coef(r8 ), t_exp(r9 ) suma_ensamblador: push rbp mov rbp, rsp push rbx push r10 push r11 ; guardamos los valores que queremos dejar intactos. push r12 push r13 push r14 mov rax,-1 mov r11,0 mov r10,0 ; para comparar mov rbx,0 ;numero total de elementos en el polinomio mov r12,0 ;r mov r13,0 ;s mov r14,0 ;t ; r_coef(rdi), r_exp(rsi), ; s_coef(rdx), s_exp(rcx), ; t_coef(r8 ), t_exp(r9 ) inicio: cmp rbx,20 je finalmal mov r10d,dword[rsi+r12*4] ;exp r mov r11d,dword[rcx+r13*4] ;exp s cmp r10d,r11d ;comparamos los exponentes r y s jl r_menor je equals ; caso de que sea mayor r q s mov [r9+r14*4],r10d ;movemos el exponente mov r10d, dword[rdi+r12*4] ;movemos el coeficiente mov [r8+r14*4],r10d inc rbx ;numero total de elementos en el polinomio inc r12 ;r inc r14 ;t jmp inicio r_menor: mov [r9+r14*4],r11d ;movemos el exponente mov r11d, dword[rdx+r13*4] ;movemos el coeficiente mov [r8+r14*4],r11d inc rbx ;numero total de elementos en el polinomio inc r13 ;s inc r14 ;t jmp inicio equals: cmp r10d,-1 je finalbien mov [r9+r14*4],r11d ;movemos el exponente mov r11d, dword[rdx+r13*4] ;movemos el coeficiente de s mov [r8+r14*4],r11d mov r11d, dword[rdi+r12*4] ;movemos el coeficiente de r add [r8+r14*4],r11d ;sumamos el coefciente de r a s inc rbx ;numero total de elementos en el polinomio inc r12 ;r inc r13 ;s inc r14 ;t jmp inicio finalbien: mov rax,0 finalmal: pop r14 pop r13 pop r12 pop r11 pop r10 pop rbx mov rsp, rbp pop rbp ret |