PRÁCTICA 11 SUMA, RESTA, MULTIPLICACIÓN Y DIVISIÓN DE DOS NÚMEROS ENTEROS POSITIVOS DE HASTA 20 DÍGITOS DECIMALES 1. INTRODUCCIÓN Mediante esta práctica, trabajaremos con números binarios de hasta veinte dígitos decimales y haremos las operaciones básicas de suma, resta, multiplicación y división de dos números enteros positivos, donde el primer número debe ser mayor que el segundo 2. OBJETIVOS Al término de esta práctica el alumno podrá: 2.1. Trabajar con rutinas aritméticas multidígito 2.2. Realizar operaciones básicas y exhibir el resultado 2.3. Hacer que un programa sea más robusto, es decir, que no falle. 3. DESARROLLO 3.1. Capturar los siguientes módulos con el nombre MBIN.ASM, ensamblarlo y meterlo a la librería REM. %TITLE CUATRO OPERACIONES FUNDAMENTALES EN NÚMEROS DE 8 BYTES IDEAL DOSSEG MODEL small DATASEG Ent1 DQ 0 variable para 64 bits Ent2 DQ 0 ídem Salt1 DQ 0 ídem Salt2 DQ 0,0 para 128 bits doble dd 0,0 CODESEG PUBLIC PUBLIC SumaBin,RestaBin,MultiBin,DivideBin,CompBin MbinAsc,MbinAscD,CopiaBin,EntraBin 11-1
SumaBin SUMA DE DOS NÚMEROS BINARIOS DE 64 BITS Entrada: SI = dirección del primer número DI = dirección del segundo número BX = dirección del resultado Salida: Resultado donde se pedía Registros: Ninguno PROC SumaBin push si di bx cx ax salva todo mov cx,4 pone número de palabras clc limpia CF mov ax,[si] trae palabra del primer número inc si apunta a siguiente palabra inc si adc ax,[di] suma palabra de segundo número inc di apunta a siguiente palabra inc di mov [bx],ax pone palabra resultante inc bx apunta a siguiente palabra in bx loop @@10 pop ax cx bx di si recupera orno ENDP SumaBin RestaBin RESTA DOS NÚMEROS BINARIOS DE 64 BITS Entrada: SI = dirección del primer número (sustraendo) DI = dirección del segundo número (minuendo) BX = dirección del resultado (segundo primero) Salida: Resultado en su lugar, banderas se afectan según resultado Registros: Ninguno PROC RestaBin push si di bx cx ax Salva todo mov cx,4 resta cuatro palabras clc borra préstamo mov ax,[di] trae palabra de segundo número in di apunta a siguiente palabra inc di sbb ax,[si] sustrae palabra pushf salva banderas inc si apunta a siguiente palabra inc si mov [bx],ax salva resultado inc bx apunta a siguiente palabra inc bx 11-2
popf loop @@10 recupera banderas pop ax cx bx di si repone ENDP RestaBin MultiBin MULTIPLICA DOS NÚMEROS BINARIOS DE 64 BITS Entrada: SI = dirección del primer factor DI = dirección del segundo factor BX = dirección para resultado Salida: Resultado de 128 bits Registros: Ninguno PROC MultiBin push si di bx cx ax salva todo Limpia área de resultado push bx salva apuntador mov x,0 pone ceros mov cx,8 es de doble precisión cld hacia delante mov [bx],ax limpia una palabra inc bx apunta a siguiente palabra inc bx loop @@10 16 bytes pop bx recobra dirección mov cx,4 trae número de palabras @@20: push cx salva contador externo mov dx,[si] trae palabra del primer factor inc si apunta a siguiente palabra inc si push bx di salva registros durante lazo interno mov cx,4 pone número de palabras pop di restaura directorio a dividendo mov si,offset Sal2 SI apunta a divisor temporal inicia contador de corrimientos mov cx,1 conteo de uno normaliza divisor test [word si+14],8000h prueba bit más significativo jnz @@20 sale si ya normalizado call CorreI corre a la izquierda si no 11-3
inc cx :cuenta el corrimiento jmp @@10 sigue hasta normalizar Lazo para comparar, restar y corre @@20: call CompBin compara divisor contra dividendo ja @@30 salta si muy grande call Sustrae lo resta si cabe stc nuevo bit de cociente es uno jmp @@40 salta a fin de lazo @@30: cic @@40: call CorreCoc mete bit en el cociente nuevo bit de cociente es cero call CorreD corre divisor lógicamente loop @@20 pop ax cx bx di si recobra ENDP DivideBin PROC CorreI push si cx salva registros mov cx,8 pone contador clc limpia CF rcl [word si],1 corre una palabra un bit inc si apunta a siguiente palabra inc si loop @@10 hace todo el divisor pop cx si repone ENDP CorreI PROC CorreCoc push bx cx salva registros mov cx,4 precisión sencilla rcl [word bx],1 corre palabra de cociente una vez inc bx apunta a siguiente palabra inc bx loop @@10 pop cx bx restaura ENDP CorreCoc Rutina local para corregir el divisor lógicamente a la derecha PROC CorreD push si cx salva registros 11-4
add si,14 apunta a final de divisor temporal mov cx,8 para doble precisión clc limpia CF rcr [word si],1 rota una palabra a la vez dec si apunta a siguiente palabra dec si loop @@10 para todo el divisor pop cx si repone ENDP CorreD Rutina local para sustraer el divisor corrido del dividendo PROC Sustrae push si di cx salva todo clc limpia acarreo final mov cx,8 resta ocho palabras mov ax,[si] trae palabra del divisor inc si apunta a siguiente palabra inc si sbb [di],ax sustrae de palabra de dividendo inc di apunta a siguiente palabra inc di loop @@10 pop cx di si recupera ENDP Sustrae CompBin COMPARA DOS NÚMEROS BINARIOS DE 128 BITS Entrada: SI apunta a NUM1, DI apunta a NUM2 Salida: Registro de banderas se afecta según comparación: CMP, NUM1, NUM2 Registros: Banderas PROC CompBin push si di cx salva std add si,14 apunta al final add di,14 ídem mov cx,8 hasta ocho palabras compara más significativo primero repz cmpsw compara palabra a palabra ENDP pop cx di si repone CompBin 11-5
CopiaBin COPIA UN NÚMERO BINARIO DE 64 BITS Entrada: SI apunta a NUM1, DI apunta a NUM2 Salida: Registro de banderas se afecta según comparación: CMP, NUM1, NUM2 Registros: Banderas PROC CopiaBin push si di cx cld mov cx,4 salva copia hacia delante rep movsw compara palabra a palabra pop cx di si repone P386N MBinAsc Entrada: Salida: Registros: CONVIERTE UN NÚMERO BINARIO DE 64 BITS ASCII SI apunta a NUM1, DI apunta a cadena ASCIIZ La cadena ASCIIZ se llena de caracteres ASCII según número Ninguno PROC MBinAsc push ax bx cx dx si di salva Limpia la cadena mov al,30h ceros mov cx,20 conteo de 20 mov [di],al pone nulo inc di apunta a siguiente byte cmp [dword si+4],10 puede usar DIV? jb @@20 si, brinca Lazo eterno @@20: push si salva dirección del binario Divide por 10 mov ebx,0 bandera a cero mov cx,2 cuatro palabras en número mov edx,0 inicializa residuo add si,4 apunta a final del binario @@30: push cx salva contador mov eax,[si] trae 16b bits mov ecx,10 divisor de 10 div ecx divide 11-6
mov [si[,eax regresa 16 bits or ebx,eax verifica si cero sub si,4 apunta a siguiente palabra pop cx repone contador loop @@30 mov [di],dl trae dígito de residuo add [byte di], 0 lo hace ASCII dec di apunta a siguiente carácter pop si restaura dirección de binario cmp ebx,0 fue número cero? jnz @@20 repite si no pop di si dx cx bx ax recupera ENDP MBinAsc Efectúa división mediante corrimientos.. GranDiv: mov cx,64 xor eax,eax mov ebx,10 shift: call Corre96 cmo eax,ebx jb aunno sub aunno add [word si] aunno: loop shift mov [di],al add [byte di], 0 lo hace ASCII dec di apunta a siguiente carácter pop si restaura dirección de binario cmp [dword si+4],0 fue número cero? jnz GranDiv repite si no cmp [dword si],0 jnz GranDiv pop di si dx cx bx ax recupera PROC shl rcl rcl ENDP Corre96 [dword si] [dword si+4 eax,1 Corre96 11-7
MBinAscD Entrada: Salida: Registros: CONVIERTE UN NÚMERO BINARIO DE 128 BITS A ASCII SI apunta a NUM1, DI apunta a cadena ASCIIZ La cadena ASCIIZ se llena de caracteres ASCII según número Ninguno PROC MBinAscD push ax bx cx dx si di salva Limpia la cadena mov al,30h ceros mov cx,33 conteo de 33 mov [di[,al pone nulo inc di apunta a siguiente byte loop @@10 Lazo eterno @@20: push si salva dirección del binario Divide por 10 mov bx,0 bandera a cero mov cx,8 ocho palabras en número mov dx,0 inicializa residuo add si,14 apunta a final del binario @@30: push cx salva contador mov ax,[si] trae 16 bits mov cx,10 divisor de 10 div cx divide mov [si],ax regresa 16 bits or bx,ax verifica si es cero sub si,2 apunta a siguiente palabra pop cx repone contador loop @@30 mov [di],di lo hace ASCII dec di apunta a siguiente carácter pop si restaura dirección de binario cmp bx,0 fue número cero? jnz @@20 repite si no pop di si dx cx bx ax recupera ENDP MBinAscD 11-8
EntraBin Entrada: Salida: Registros: ENTRA UN NÚMERO BINARIO DADO EN DECIMAL HASTA DE 18 DÍGITOS SI = dirección del número Dato donde se pedía Ninguno PROC EntraBin push ax bx cx di salva registros call dec64 mete número decimal mov [si],ebx lo salva mov [si+4],edx pop di cx bx ax recobra ENDP EntraBin Dec64 Entrada: Salida: Registros: RECIBE DESDE EL TECLADO UN NÚMERO DECIMAL Y REGRESA 64 BITS Ninguna Binario de 64 bits en DX:BX Ninguno PROC Dec64 push ax cx salva registros xor ebx,ebx limpia EBX mov edx,ebx y EDX mov ah,1 mete carácter del teclado int 21h con DOS sub al,30h resta 0 jl @@99 salir si no es dígito decimal cmp al,9 jg @@99 salir si no es dígito decimal call near ptr mten multiplica por 10 res previa and eax,offh. Para sumar 32 bits add ebx,eax suma dígito adc edx,0 por si es muy grande jmp @@10 @@99: pop cx ax recobra multiplica por 10 cantidad de 64 bits mten: shl ebx,1 por 2 rcl edx,1 mov [dword doble],ebx salva por 2 mov [dword doble+4],edx shl ebx,1 por 4 rcl edx,1 shl ebx,1 por 8 rcl edx,1 add ebx,[dword doble] por 10 11-9
adc ENDP END edx,[dword doble+4] Dec64 fin de módulo MBIN.ASM 3.2. Capturar el programa ABIN.ASM, ensamblarlo y crear el programa ejecutable. %TITLE SUMA, RESTA, MULTIPLICA Y DIVIDE NÚMEROS BINARIOS P386N IDEAL DOSSEG MODEL SNACK small Programa ABIN.ASM que hace aritmética binaria. Ensamblarlo con TASM /zi ABIN ligarlo con: TLINK /v ABIN,,,REM rc EQU 13 ASCII de orno de carro nl EQU 10 ASCII de nueva línea DATASEG clavefin DB 0 saludos DB Este programa encuentra la suma, la resta, el producto, DB el cociente entero y,rc,nl DB su residuo de dos números decimales enteros, teclear DB primeroel mayor de ellos.,rc,nl,0 RepCPU DB El programa requiere por lo menos un 80386,rc,nl,0 fuente DQ 99898999264 8 bytes para binario destino DQ 17581480361 ídem para destino suma DQ 0 suma en BCD resta DQ 0 resta en BCD multi DQ 2 dup (0) ResSuma DB 22 dup (0) resultado de la suma ResResta DB 22 dup (0) resultado de resta CadSuma DB La suma es..:,0 CadResta DB La resta es...:,0 Apr1er DB Teclear primero número decimal :,0 Apr2do DB Teclear segundo número decimal :.0 ResMulti DB 35 dup (0) CadMulti DB El producto es.:,0 dividendo DQ 0 divisor DQ 0 cociente DQ 0 CadCociente DB El cociente es.:,0 ResCociente DB 22 dup (0) CadResiduo DB El residuo es.:,0 ResResiduo DB 22 dup (0) 11-10
CODESEG EXTRN EXTRN EXTRN Sumaban:proc,Restaban:proc,MBinASC:proc SacaCadena:proc,NuevaLinea:proc,cpul:proc CopiaBin:proc,DivideBin:proc,MBinAscD:proc,EntraBin:proc Inicia: mov ax,@data mov ds,ax inicia DS mov es,ax call NuevaLinea salta línea call cpul indaga tipo de CPU cmp ax,386h por lo menos un 80386 jae @@10 mov di,offset RepCPU call SacaCadena avisa que saldrá mov ah,4ch función de DOS int 21h para salir mov di,offset saludo bienvenida e instrucciones call SacaCadena mov di,offset Apr1er pide número mayor call SacaCadena mov si,offset fuente apunta a buffer de número mayor call EntraBin recibe los dígitos call NuevaLinea salta línea mov di,offset Apr2do repite para segundo número call SacaCadena mov si,offset destino call EntraBin recibe los dígitos call NuevaLinea salta línea realiza la operación de suma.. mov eax,[dword destino] trae 32 bits add eax,[dword fuente] y los suma mov [dword suma],eax salva parte baja mov eax,[dword destino+4] trae 32 bits adc eax,[dword fuente+4] los suma con CF mov [dword suma+4] salva mov di,offset ResSuma apunta a cadena ASCIIZ mov si,offset Suma apunta a suma en binario call MBinASC convierte a ASCII mov di,offset CadSuma exhibe letrero de resultado call SacaCadena de suma mov di,offset ResSuma exhibe dígitos de suma call PoneBlancos elimina algunos ceros call SacaCadena realiza la resta.. call NuevaLinea salta línea 11-11
mov eax,[dword fuente] trae 32 bits sub eax,[dword destino] resta 32 bits mov [dword resta],eax salva parte baja mov eax,[dword fuente+4] trae 32 bits altos sbb eax,[dword destino+4 resta 32 bits mov [dword resta+4] salva mov di,offset ResResta apunta a cadena ASCIIZ mov si,offset Resta apunta a resta en binario call MBinASC convierte a ASCII mov di,offset CadResta exhibe letrero de resultado call SacaCadena de resta mov di,offset RestaBin exhibe dígitos de resta call PoneBlancos omite algunos ceros call SacaCadena exhibe resta producto.. call NuevaLinea Salta línea mov si,offset fuente apunta a fuente (mayor) mov bx,offset multi multi es nuevo destino mov di,offset destino apunta a número menor call MultiBin multiplica binarios mov di,offset ResMulti apunta a cadena ASCIIZ mov si,offset multi apunta a producto en binario call MBinAscD convierte a ASCII mov di,offset CadMulti exhibe letrero de resultados call SacaCadena de multiplicación mov di,offset ResMulti exhibe dígitos de producto call PoneBlancos omite ceros delanteros call SacaCadena exhibe producto división divi: call NuevaLinea salta línea mov di,offset fuente apunta a fuente (dividendo) mov bx,offset cociente resultado en cociente mov si,offset destino apunta a número divisor call DivideBin divide binarios mov di,offset ResCociente apunta a cadena ASCIIZ mov si,offset Cociente apunta a cociente en binario call MbinAsc convierte a ASCII mov di,offset CadCociente exhibe letrero de resultado call SacaCadena de división mov di,offset ResCociente exhibe dígitos de producto call PoneBlancos omite ceros delanteros call SacaCadena exhibe cociente call NuevaLinea mov di,offset ResResiduo para poner ASCII del residuo mov si,offset fuente apunta a residuo en binario call MbinAsc convierte a ASCII mov di,offset CadResiduo exhibe letrero de resultado call SacaCadena de división (residuo) 11-12
mov di,offset ResResiduo exhibe dígitos de residuo call PoneBlancos omite ceros delanteros call SacaCadena exhibe residuo mov ah,4ch fin de programa con función de DOS mov al,[clacefin] int 21h PoneBlancos PONE HASTA DIEZ ESPACIOS EN CERO DELANTEROS Entrada: DI = dirección de cadena ASCIIZ con resultados Salida: Aumenta a DI el número de ceros delanteros Registros: Ninguno PROC PoneBlancos push cx,ax salva registros mov cx,10 pone 10 espacios máximo mov al, ASCII de espacio mov bx,0 cld cmp [byte,di], 0 ceros a espacios jne @@99 stob pone en blanco loop @@10 @@99: pop ax cx repone registros ENDP PoneBlancos MultBin MULTIPLICA DOS NÚMEROS SIN SIGNO DE 64 BITS Entrada: DI = dirección del primer factor, SI = dirección del segundo factor BX = dirección de resultado de 128 bits Salida: Área de salida con el resultado Registros: Ninguno PROC MultiBin mov [dword bx+12] limpia resultado mov [dword bx +8],0 mov eax,[dword si] trae 32 bits bajos mult [dword di] multiplica por bits bajos mov [dword bx],eax llena parte baja mov [dword bx+4].edx mov eax,[dword si] trae 32 bits bajos mul [dword di+4] multiplica por bits altos add [dword bx+4],eax suma en área de resultados adc [dword bx+8],edx mov eax,[dword si+4] trae 32 bits altos mul [dword di] multiplica por bits bajos add [dword bx+4],eax suma 11-13
adc [dword bx+8],edx suma con CF mov eax,[dword si+4] trae 32 bits altos mul [dword di+4] por 32 bits bajos add [dword bx+8] suma adc [dword bx+12],edx suma con acarreo ENDP MultiBin END Inicia fin de módulo ABIN.ASM 3.3. Ejecutar el programa: C:\>ABIN (Se muestran cuatro corridas) C:\SEM386>abin Este programa encuentra la suma, la resta, el producto, el cociente entero y su residuo de dos números decimales enteros. Teclear primero el mayor de ellos. Teclear primer número decimal : 12345679 Teclear segundo número decimal: 63 La suma es..: 00012345742 La resta es : 00012345616 El producto es: 000000000000000777777777 El cociente es.: 00000195963 El residuo es : 00000000010 C:\SEM386> C:\SEM386>abin Este programa encuentra la suma, la resta, el producto, el cociente entero y su residuo de dos números decimales enteros. Teclear primero el mayor de ellos. Teclear primer número decimal : 99898999 Teclear segundo número decimal: 1758148 La suma es..: 00101657147 La resta es : 00098140851 El producto es: 000000000175637225293852 El cociente es.: 00000000056 El residuo es : 00001442711 C:\SEM386> C:\SEM386>abin Este programa encuentra la suma, la resta, el producto, el cociente entero y su residuo de dos números decimales enteros. Teclear primero el mayor de ellos. Teclear primer número decimal : 29990217983 Teclear segundo número decimal: 1602070822 La suma es..: 31592288805 La resta es : 28388147161 El producto es: 000048046453175983992026 El cociente es.: 00000000018 El residuo es : 01152943187 C:\SEM386> 11-14
C:\SEM386>abin Este programa encuentra la suma, la resta, el producto, el cociente entero y su residuo de dos números decimales enteros. Teclear primero el mayor de ellos. Teclear primer número decimal : 1125899906842624 Teclear segundo número decimal: 281474977056334 La suma es..: 1407374883898958 La resta es : 844424929786290 El producto es: 316912650446256178371720380416 El cociente es.: 00000000003 El residuo es : 281474975673622 C:\SEM386> 3.4. Este programa se puede depurar con turbo debugger mediante el siguiente comando: C>TD ABIN.EXE Ejecutar paso a paso las rutinas Dec64 y MBinASC y estudiar cómo trabajan 3.5. Poner los registros en 32 bits y visualizar las variables fuente y destino, en decimal. 4. TAREAS 4.1. Introducir al programa el procedimiento Confirma y llamarlo para verificar la opción de realizar otro cálculo. 2 n n 2 0 = 16 0 16 n n 256 8 2 4 = 16 1 1 0 512 9 2 8 = 16 2 16 1 1 024 10 2 12 = 16 3 256 2 2 048 11 2 16 = 16 4 4 096 3 4 096 12 2 20 = 16 5 65 536 4 8 192 13 2 24 = 16 6 1 048 576 5 16 384 14 2 28 = 16 7 16 777 216 6 32 768 15 2 32 = 16 8 268 435 456 7 65 536 16 2 36 = 16 9 4 294 967 296 8 131 072 17 2 40 = 16 10 68 719 476 736 9 262 144 18 2 44 = 16 11 1 099 511 627 776 10 524 288 19 2 48 = 16 12 17 592 186 044 416 11 1 048 576 20 2 52 = 16 13 281 474 976 710 656 12 2 097 152 21 2 56 = 16 14 4 503 599 627 370 496 13 4 194 304 22 2 60 = 16 15 72 057 594 037 927 936 14 8 388 608 23 2 64 = 16 16 1 152 921 504 606 846 976 15 16 777 216 24 4.2. Verificar los valores de la tabla dada corriendo ABIN. 11-15
4.3. Agregar al programa la capacidad de recibir los dos números en la línea de comandos. 4.4. En el módulo MBIN.ASM añadir una rutina para recibir números decimales enteros negativos y otra para recibir enteros decimales de hasta 32 bits. 4.5. Hacer que el programa ABIN elimine todos los ceros delanteros al desplegar los resultados. 11-16