CUESTIÓN B

Calcular Si Un Número es Perfecto

Descargar Código X86     Descargar Código ARM

Programa ARM
 AREA ejer,CODE,READWRITE

SWI_Salir EQU &11 ; salida del programa
SWI_write0 EQU &2 ; muestra por pantalla
SWI_ReadC EQU &4 ; leer un caracter del teclado

 ENTRY

INICIO
  ADR  r0, cad1  ;Obtenemos dirección de la cadena
  SWI  SWI_write0  ;interrupción para mostrar cadena
  SWI  SWI_ReadC ;Punto de ruptura para introducir el dato en R0
  MOV  r1,r0  ;Movemos el valor introducido en r0 a r1
  SUB r1,r1,#48 ;Restamos 48 al valor ascii del dato introducido para
                ;poder operar con él
  MOV  r2, #2 ;Para dividir el numero entre dos y no comprobar con
              ;números superiores a su mitad 
  MOV  r4, #0 ;Inicializamos el registro r4 a 0. Y así poder usar la
              ;division
  MOV r3, #1  ;Inicializamos el registro r3 a 1, que contendrá el
              ;cociente.
  CMP r1, #2  ;Comprobamos que el número introducido no es menor de 2
  BLT NO_PERFECTO ;Saltamos cuando el número introducido sea menor de 2
  MOV  r7, r1  ;Duplicamos el número introducido
  
     ;Dividimos el número introducido entre 2
MITAD  SUB  r7, r7, r2 ;restamos 2 a r7 (contiene el numero
                       ;introducido)
  ADD  r3, r3, #1 ;vamos sumando 1 al divisor que será el contador del
                  ;bucle siguiente
  CMP  r7, r2  ;Comprobamos si podemos seguir dividiendo
  BGE  MITAD   ;salta mientras r7 sea mayor o igual que 2.
  MOV r8, #2  ;r8 contendrá los candidatos a divisor
  MOV  r7, r1  ;Volvemos a introducir el número leído en r7
  MOV r6, #1  ;r6 Acumulará la suma de los divisores del número
              ;introducido
 
COMPROBAR 
     ;Para comprobar si los candidatos a divisor lo son realmente
  SUB  r7, r7, r8 ;Restamos el candidato a divisor al número
                  ;introducido
  ADD r4, r4, #1 ;r4 irá almacenando el cociente
  CMP  r7, r8  ;Comparamos dividendo con divisor
  BGE COMPROBAR ;Salta mientras el dividendo no sea menor que el
                ;divisor
  CMP  r7, #0  ;Comprueba si el resto es cero
  BNE SIGUIENTE ;Si el resto es distinto de 0, salta a SIGUIENTE
  ADD  r6, r6, r8 ;Si el resto es 0, sumamos al registro r6 el divisor
                  ;encontrado

SIGUIENTE CMP r8, r3  ;Comprobamos si ya hemos probado con todos los
                      ;posibles divisores
  BEQ RESULTADO ;Salta cuando hayamos realizado todas las iteraciones
                ;previstas.
  ADD  r8, r8, #1 ;Incrementamos en 1 para tener un nuevo candidato a
                  ;divisor.
  MOV r7, r1  ;Reiniciamos el dividendo
  B COMPROBAR ;Volvemos para comprobar el siguiente candidato a divisor

 
RESULTADO CMP r1, r6  ;Comprobamos si la suma de los divisores es igual
                      ;al número introducido
  BNE  NO_PERFECTO ;Si son distintos saltamos a NO_PERFECTO
  ADR  r0, cad2  ;Obtenemos dirección de la cadena
  SWI  SWI_write0  ;interrupción para mostrar cadena
  B FIN
    

NO_PERFECTO ADR r0, cad3   ; Obtenemos dirección de la cadena
  SWI SWI_write0   ;interrupción para mostrar cadena

FIN  ADR  r0, cad4  ;Para volver a ejecutar el programa
  SWI  SWI_write0  ;Interrupción para mostrar cadena
  SWI  SWI_ReadC ;Punto de ruptura para introducir el dato en R0
  CMP r0, #49  ;Comprobamos si desea volver a ejecutar el programa
  BEQ INICIO  ;Si el usurario ha introducido un 1 repetimos el programa

   
  SWI SWI_Salir  ;Interrupción para salir


cad1 = "Introduzca un número entre 1 y 9", &0a, &0d, 0
cad2 = "El numero introducido es perfecto", &0a, &0d, 0
cad3 = "El numero introducido no es perfecto", &0a, &0d, 0
cad4 = "Para volver a ejecutar el programa introduzca 1", &0a, &0d, 0

 END
Programa x86
.Const

.Data
NUM DQ 0


.Code

start:
;Inicio del programa principal.

 invoke puts, "----- Programa para comprobar si un numero es perfecto -----"
 invoke puts, " "
 invoke printf, "----- Introduzca un numero entero positivo :  "
 invoke scanf, "%d", Addr NUM
 invoke puts, " "
 mov ebx, 2   ;Para dividir el número entre dos y así no comprobar números superiores a su mitad
 mov eax, [NUM]  ;Introducimos el número en eax
 mov edx, 0   ;Para poder usar DIV sin problemas
 div ebx    ;Lo dividimos entre dos
 mov ecx, eax  ;Almacenamos el cociente en ecx para que sirva de contador para LOOP
 mov edi, 1   ;Contendrá los candidatos a divisores
 mov esi, 0   ;Para ir sumando los divisores

comprobar:
 mov eax, [NUM] ;Introducimos el numero en eax para DIV
 div edi   ;Dividimos el número entre el candidato a divisor
 cmp edx, 0  ;Comprobamos si el resto es cero
 jne > siguiente ;Salta si el resto no es cero
 add esi, edi ;Sumamos el divisor encontrado
siguiente:
 inc edi   ;Incrementamos en uno el candidato a divisor
 mov edx, 0  ;Eliminamos el posible resto almacenado para poder utilizar DIV
 loop comprobar ;Iteramos mientras no se comprueben todos los números entre 1 y NUM/2.

 cmp [NUM], esi  ;Comprobamos si la suma de los divisores es igual al número introducido
 jne > no_perfecto ;Saltamos si no son iguales
 invoke puts, "----- El numero introducido es perfecto "
 jmp > fin
no_perfecto:
 invoke puts, "----- El numero introducido no es perfecto "

fin:
 invoke puts, " "
 Invoke system, "pause"
 Xor Eax, Eax
 Invoke ExitProcess, Eax

;Fin del programa principal

;Subprogramas: