Skip to content

L11: Practica 4

Miguel edited this page Dec 9, 2024 · 69 revisions

Sesión Laboratorio 11: Práctica 4-3

  • Tiempo: 2h
  • Objetivos de la sesión:
    • Comprender los mecanismos para implementar funciones recursivas
    • Aprender a implementar funciones recursivas
    • Practicar, practicar, practicar

Vídeos

  • Fecha: 2019/Dic/27

Vídeo 1/5: Algoritmos y recursividad

Haz click en la imagen para ver el vídeo en Youtube

Click to see the youtube video

Vídeo 2/5: Factorial, mediante subrutinas anidadas

Haz click en la imagen para ver el vídeo en Youtube

Click to see the youtube video

Vídeo 3/5: Factorial, mediante subrutina recursiva

Haz click en la imagen para ver el vídeo en Youtube

Click to see the youtube video

Vídeo 4/5: Recursividad en cadenas

Haz click en la imagen para ver el vídeo en Youtube

Click to see the youtube video

Vídeo 5/5: Ejercicio recursivo resuelto: Longitud de una cadena

Haz click en la imagen para ver el vídeo en Youtube

Click to see the youtube video

Contenido

Introducción

La recursividad nos permite modelar patrones que se repiten a diferentes niveles. Estos patrones pueden ser funcionales, en los que se define cómo funciona algo usando la propia función. Por ejemplo la función factorial: Para calcular el factorial de n, debes multiplicar n por el factorial de n-1

También pueden ser estructurales: estructuras similares dentro de una estructura, como por ejemplo las muñecas rusas. O las cadenas de caracteres: dentro de una cadena de caracteres podemos tomar una subcadena, que también será una cadena de caracteres

En informática la recursividad se utiliza un montón, especialmente en el área de compiladores. Cuando escribimos el código fuente de un programa, hay muchas estructuras que se repiten a diferentes niveles: en un bloque puede haber una sentencia if, que tiene en su interior otro bloque puede contener a su vez otras sentencias if... Estos patrones de estructuras recurrentes se modelan de manera muy natural con funciones recursivas

Aprenderemos los mecanismos que tenemos a nivel de procesador para implementar la recursividad

Funciones recursivas

Las funciones recursivas son las que se llaman a sí mismas para realizar un cálculo. El ejemplo clásico es el cálculo del factorial de un número. Si fact(n) es la función que calcula el factorial del número n, sabemos que esta función se define de esta forma:

fact(n) = n * fact(n-1), con n>=2 y fact(1) = 1

¡Utilizamos la propia función fact() para definir el comportamiento de la función fact()!

Estas funciones las implementamos en el RISC-V usando subrutinas. Son un caso particular de las subrutinas encadenadas que vimos en la sesión anterior, por lo que tendremos que usar la pila para guardar las direcciones de retorno y los registros que se pasan como argumentos

Factorial de 3 con subrutinas encadenadas

Antes de aprender a hacer subrutinas recursivas en ensamblador vamor a hacer un ejemplo del cálculo del factorial de 3 usando subrutinas encadenadas. Así, el programa principal llamará a la función fact3() que calcula el factorial de 3. No tiene ningún parámetro de entrada, y devolverá 6

La función fact3(), a su vez, llamará a la función fact2() que tiene los mismos parámetros que fact3() pero devuelve el factorial de 2:

fact3() = 3 * fact2()

Por último, la función fact2() llamará a la función fact1():

fact2() = 2 * fact1()

La función fact1() devolverá 1, ya que el factorial de 1 es 1. Si representamos los niveles de profundidad tenemos lo siguiente:

En todos los niveles, excepto el último, se multiplica un número constante por lo que devuelve la función de nivel inferior. En el último caso sólo se devuelve la constante 1

Haremos que cada función imprima un mensaje para comprobar que se están ejecutando.

  • Función fact1()

La función fact1() es la última (hoja), y no llama a ninguna otra, por lo que no será necesario crear una pila para guardar su dirección de retorno. La dirección de retorno está en ra

#----------------------------------------------------
#-- Subrutina que calcula el factorial del 1
#-- ENTRADAS:
#--   Ninguna
#-- SALIDAS:
#--   Devuelve 1
#----------------------------------------------------

	.include "servicios.asm"

	#-- Punto de entrada
	.globl fact1
	
	.data
msg:	.string "\n> Fact1: 1"
	
	.text
	
fact1:

	#-- NO necesitamos pila
	#-- La direccion de retorno está en ra
	
	#-- Imprimir mensaje
	la a0, msg
	li a7, PRINT_STRING
	ecall

	#-- Devolver 1
	li a0, 1	
	ret
  • Función fact2()

Se calcula el factorial de 2 multiplicando 2 por el resultado de llamar a fact1(): 2 * fact(1). En esta función necesitamos crear la pila para guardar la dirección de retorno. También se imprime un mensaje para saber por donde va la ejecución

#----------------------------------------------------
#-- Subrutina que calcula el factorial del 2
#-- ENTRADAS:
#--   Ninguna
#-- SALIDAS:
#--   Devuelve 2 * fact1()
#----------------------------------------------------

	.include "servicios.asm"

	#-- Punto de entrada
	.globl fact2
	
	.data
msg:	.string "\n> Fact2: "
	
	.text
	
fact2:

	#-- Necesitamos pila para guardar
	#-- la direccion de retorno
	addi sp, sp, -16
	sw ra, 12(sp)

	#-- Calcular el factorial de 1
	jal fact1
	
	#-- Calcular 2 * fact1
	li t0, 2
	mul t1, a0, t0 
	
	#-- t1 contiene el resultado
	
        #-- Imprimir mensaje
	la a0, msg
	li a7, PRINT_STRING
	ecall
	
	#-- Imprimir el valor de factorial
	mv a0, t1
	li a7, PRINT_INT
	ecall
	
	#-- Recuperar direccion de retorno
	lw ra, 12(sp)
	addi sp, sp, 16
	
	#-- Terminar
	ret
  • Función fact3()

Igual que fact2(), pero calculando el producto de 3 * fact2(). También es necesaria la pila para guardar la dirección de retorno

#----------------------------------------------------
#-- Subrutina que calcula el factorial del 3
#-- ENTRADAS:
#--   Ninguna
#-- SALIDAS:
#--   Devuelve 6
#----------------------------------------------------

	.include "servicios.asm"

	#-- Punto de entrada
	.globl fact3
	
	.data
msg:	.string "\n> Fact3: "
	
	.text
	
fact3:

	#-- Necesitamos pila para guardar
	#-- la direccion de retorno
	addi sp, sp, -16
	sw ra, 12(sp)

	#-- Calcular el factorial de 2
	jal fact2
	
	#-- Calcular 3 * fact2
	li t0, 3
	mul t1, a0, t0 
	
	
	#-- Imprimir mensaje
	la a0, msg
	li a7, PRINT_STRING
	ecall
	
	#-- Recuperar a0
	mv a0, t1
	
	#-- Imprimir el valor de factorial
	li a7, PRINT_INT
	ecall
	
	#-- Recuperar direccion de retorno
	lw ra, 12(sp)
	addi sp, sp, 16
	
	ret
  • Programa principal

Se llama a fact3() para calcular el factorial. Luego se imprime el resultado

#----------------------------------------------------------
#-- PROGRAMA PRINCIPAL
#--
#--  Calculo del factorial de 3, llamando a subrutinas
#-- de niveles inferiores
#----------------------------------------------------------

	.include "servicios.asm"
	
	#-- Constante. Queremos calcular el factorial de N
	.eqv N 3
	
	.data
msg1:	.string "\n\nFactorial de "	
msg2:   .string ": "
		
	.text 
	
	
	#-- Calcular el factorial
	jal fact3
	
	#-- a0 contiene el factorial de 3 
	#-- Lo guardamos en s0 para no perderlo
	mv s0, a0
	
	#-- Imprimir mensaje:
	la a0, msg1
	li a7, PRINT_STRING
	ecall
	
	#-- Imprimir N
	li a0, N 
	li a7, PRINT_INT
	ecall
	
	#-- Fin del mensaje
	la a0, msg2
	li a7, PRINT_STRING
	ecall
	
	#-- Recuperar a0
	mv a0, s0
	
	#-- Imprimir el resultado
	li a7, PRINT_INT
	ecall
	
	#-- Imprimir \n
	li a0, '\n'
	li a7, PRINT_CHAR
	ecall
	
	#-- Terminar
	li a7, EXIT
	ecall

Al ensamblar y ejecutar el programa (hay 4 ficheros en total), en la consola veremos lo siguiente:

Factorial de 3 con subrutina recursiva

El cálculo del factorial lo podemos simplificar mucho usando una subrutina recursiva. Ahora sólo hay una función: fact(), que tiene un argumento de entrada y retorna un valor de salida. El prototipo de la función es:

  • int fact(int n)

Esta función se llama a sí misma para realizar el cálculo, pero es como si la hubiésemos implementado con varias subrutinas encadenadas, como en el ejemplo anterior. Dentro de ella hay que distinguir dos casos:

  • Si n es 1, entonces la función simplemente deberá devolver el factorial de 1, que es 1
  • Si n es mayor a 1, entonces deberá devolver el producto de n por el resultado de calcular fact(n-1): n * fact(n-1)

Puesto que la función recibe por a0 el número n, y tiene que llamar a una subrutina con n-1, será necesario guardar el valor n en la pila, para no perderlo, y respetar el convenio

Exactamente igual que en el ejemplo anterior, para calcular fact(3) se realizan dos llamadas a subrutinas. Una para calcular fact(2) y la última a fact(1)

  • Función fact(n)
#-----------------------------------------------------
#-- Subrutina fact(n)
#-- Calcula el factorial de n, de forma recursiva
#-- ENTRADAS:
#--   a0: n
#-- DEVUELVE:
#--   a0: n * fact(a0-1)
#----------------------------------------------------

	.include "servicios.asm"
	
	.globl fact
	
	.data
msg:	.string "\n> Factorial "
	
	.text
fact:

	#-- En las funciones recursivas hay que comprobar
	#-- primero en que nivel estamos: ¿El ultimo? ¿Intermedio?
	
	#-- Si a0 > 1 no estamos en el nivel más profundo
	li t0, 1
	bgt a0, t0, fact_rec 
	
	#-- Estamos en el nivel mas profundo
	#-- Es una subrutina Hoja
	#-- No hace falta guardar direccion de retorno en la pila
	
	#-- Imprimir mensaje
	la a0, msg
	li a7, PRINT_STRING
	ecall
	
	#-- El factorial de 1 es 1
	li a0, 1
	
	#-- Imprimir a0
	li a7, PRINT_INT
	ecall
	
	#-- Ir al punto de salida
	b fin


	#--- Estamos en un nivel intermedio
fact_rec:

	#-- Hay que crear la pila para guardar la direccion de retorno
	addi sp, sp, -16
	
	#-- Guardar direccion de retorno
	sw ra, 12(sp)

	#-- Guardar n en la pila
	sw a0, 8(sp)
	
	#-- Calcular fact(n-1)
	addi a0, a0, -1
	jal fact
	
r1:     #-- Direccion de retorno
        #-- (Para depurar)
	
	#-- a0 = fact(n-1)
	#-- Recuperar n
	lw t0, 8(sp)
	
	#-- Calcular t1 = n * fact(n-1)
	mul t1, t0, a0
	
	#-- Imprimir mensajes
	la a0, msg
	li a7, PRINT_STRING
	ecall
	
	#-- Imprimir n
	mv a0, t0
	li a7, PRINT_INT
	ecall
	
	#-- Colocar en a0 el resultado a devolver
	mv a0, t1

	#-- Recuperar direccion de retorno
	lw ra, 12(sp)

	addi sp, sp, 16
	#-- Punto de salida
fin:
	#-- Terminar	
	ret
  • Programa principal:
#-----------------------------------------------------------------
#-- Programa principal: Calculo del factorial de un numero N 
#-----------------------------------------------------------------

	.include "servicios.asm"
	
	#-- Numero del que queremos calcular el factorial
	.eqv N 3

	.data
msg1:   .string "\n\nFactorial de "	
msg2:   .string ": "
	
	.text 
	
	#-- Llamar a fact(N)
	li a0, N
	jal fact
	
r0:	#-- Direccion de retorno al principal
        #-- (para depurar)
	
	#-- En a0 esta el resultado
	#-- Guardarlo en s0
	mv s0, a0
	
	#-- Imprimir mensaje 1
	la a0, msg1
	li a7, PRINT_STRING
	ecall
	
	#-- Imprimir N
	li a0, N
	li a7, PRINT_INT
	ecall
	
	#-- Imprimir mensaje 2
	la a0, msg2
	li a7, PRINT_STRING
	ecall
	
	#-- Imprimir el resultado
	mv a0, s0
	li a7, PRINT_INT
	ecall
	
	#-- Imprimir \n
	li a0, '\n'
	li a7, PRINT_CHAR
	ecall
	
	#-- Terminar
	li a7, EXIT
	ecall

Cuando se ejecuta para N=3, el comportamiento es exactamente igual que en el ejemplo anterior. En los niveles 1 y 2 se crea pila para almacenar las direcciones de retorno a los niveles 0 y 1 respectivamente, así como los argumentos recibidos: 3 y 2

En la consola podemos ver lo que ha ocurrido. Si nos fijamos en la ventana del segmento de datos, si cambiamos la dirección a la de la pila, podemos ver todos los elementos que se han almacenado en ella: las dos direcciones de retorno y los argumentos

Recursividad en cadenas

Las cadenas de caracteres que estamos utilizando las definimos como secuencias de caracteres que terminan con el carácter '\0'. Bien, dentro de cualquier cadena de caracteres encontramos a su vez más cadenas de caracteres. Es por tanto un ejemplo de estructura en la que podemos aplicar funciones recursivas.

Por ejemplo, si tenemos la cadena "Hola", en su interior encontramos la cadena "ola", que a su vez tiene la cadena "la", que a su vez tiene la cadena "a"

Puesto que para acceder a una cadena usamos el puntero a su primer carácter, basta con incrementar este puntero en una unidad para seleccionar la siguiente subcadena

Como las cadenas son estructuras recursivas, podemos definir funciones recursivas que trabajen con ellas. Así por ejemplo, para calcular la longitud de la cadena, basta con sumar 1 a la longitud de su primera subcadena (aquella que se obtiene al incrementar su puntero en una unidad)

En el lenguaje python, si cad es una cadena, cad[1:] representa la subcadena formada por todos los caracteres menos el primero. La función recursiva para calcular la longitud de una cadena se puede definir así:

def len(cad):
  if cad=="":
    return 0
  else:
    return 1 + len(cad[1:])

Usamos la propia función len() para implementar la función len()

La parte recursiva representa el caso general: el patrón que se repite en los diferentes niveles. Siempre hay un caso particular, final, que es diferente al general, donde la recursividad deja de existir. En el ejemplo de la longitud de la cadena es la cadena nula: '\0'. En ella ya no hay otra sub-cadena dentro. Por eso NO es recursiva. Hay que definir el valor de su longitud, que es 0

Actividades NO guiadas

Los programas recursivos hay que tratarlos igual si fuesen llamadas a subrutina a funciones diferentes, que están en niveles inferiores. Hay que aplicar el mismo convenio de uso de los registros. La única diferencia es que se llama a una función con el mismo nombre. Pero no hay que olvidar que es una llamada a una subrutina en el nivel inferior, aunque tenga el mismo nombre.

La única forma de dominar la recursividad es practicarla. Haz los ejercicios. Practica. Si dominas esto, dominas todo lo que hemos hecho hasta ahora

Ejercicio 1

Escribe un programa principal que calcule la longitud de una cadena introducida por el usuario y la imprima en la consola. Debe llamar a la función len(pcad) que recibe como argumento de entrada un puntero a la cadena y devuelve su longitud. Esta función se debe implementar de forma recursiva, siguiendo este algoritmo escrito en pseudocódigo python:

def len(cad):
  if (cad[0] == "\n"):
    return 0
  else:
    return len(cad[1:]) + 1

Donde cad([1:) es la cadena sin el primer carácter

La subrutina len() debe estar en un fichero separado

Ejercicio 2

Escribe un programa principal que pida al usuario una cadena y la imprima del revés. Ej. Si el usuario introduce "Hola", se imprimirá "aloH". El programa principal llamará a la función print_reverse(pcad) que tiene como parámetro de entrada el puntero a la cadena a imprimir al revés. No devuelve ningún valor

La función print_reverse(pcad) se debe implementar de manera recursiva, siguiendo este algoritmo, dado en pseudocódigo python

def print_reverse(cad):
  if (cad == “”):
    return
   else:
     print_reverse(cad[1:])
     print(cad[0])

La subrutina print_reverse() debe estar en un fichero separado

Ejercicio 3

Escribir un programa principal que pida al usuario una cadena y luego un carácter. Se debe imprimir el número de esos caracteres que hay en la cadena. Para ello el programa principal deberá llamar a la función int count_char(pcad, car), cuyo primer argumento es un puntero a la cadena y el segundo es el carácter a contar. La función devuelve el número esos caracteres que hay en la cadena

La función int count_char(pcad, car) se debe implementar usando el siguiente algoritmo RECURSIVO, descrito mediante este pseudocódigo en python:

def count_char(cad, car):
  if (cad==""):
    return 0
  else:
    #-- Contar los caracteres de la subcadena
    count = count_char(cad[1:], car)
    #-- Sumar uno si el primer caracter es el pedido   
    if cad[0]==car:
      count += 1
    return count

En esta animación se muestra en funcionamiento:

Ejercicio 4

Escribe un programa principal que pida al usuario un número, como cadena de caracteres, que lo convierta a su correspondiente número entero y que lo imprima. Se supondrá que el usuario sólo introduce los caracteres '0'-'9', de forma que NO hay que gestionar errores

El programa principal deberá llamar a la función conv(pcad) que realiza la conversión. Esta función devuelve 2 parámetros de salida. El primero es el número convertido. Y el segundo es el peso del dígito de mayor peso: 1, 10, 100, 1000, etc. Como parámetro de entrada tiene el puntero a la cadena

La función conv(pcad) se debe implementar usando el siguiente algoritmo RECURSIVO, descrito mediante este pseudocódigo en python:

def conv(cad): 
    if cad=="": 
       return 0,0 
    n,p = conv(cad[1:]) 
    dig = ord(cad[0]) - ord('0') 
    if p == 0: 
      return dig, 1 
    else: 
      return dig*p*10+n, p*10 

En esta animación se muestra en funcionamiento:

La subrutina conv() debe estar en un fichero separado

Ejercicio 5

Escribir un programa principal para cifrar y descifrar una cadena introducida por el usuario. Primero se pide la cadena, luego la clave y se llama a la función cifrar(pcad1, pcad2, K) para cifrarla. Se imprime la cadena cifrada, se descifra llamando a la función cifrar con el parámetro -K y se imprime

En total debe haber 3 cadenas definidas en tiempo de ejecución:

  • cad1: Contiene la cadena inicial introducida por el usuario
  • cad2: Contiene la cadena cifrada
  • cad3: Contiene la cadena descifrada a partir de cad2. Si todo ha ido bien, debe ser igual que la cadena cad1

La función cifrar(pcad1, pcad2, K) tiene 3 parámetros de entrada. El primero es el puntero a la cadena origen. El segundo es el puntero a la cadena destino, donde almacenar la cadena cifrada. El tercer parámetro es la clave: es el número que se suma a todos los caracteres para cifrarlos. Esta función NO devuelve ningún valor de retorno. Se debe implementar usando el siguiente algoritmo RECURSIVO, descrito mediante este pseudocódigo:

función cifrar(cad1, cad2, K): 
    Si el primer elemento de cad1 es '\n':
      Almacenar en cad2[0] '\n' y en cad2[1] '\0'
      Terminar
    Si no:
      Almacenar en cad2[0] el valor de cad1[0] + K (caracter cifrado)
      llamar a cifrar(cad1[1:], cad[1:], K) para cifrar las subcadenas

En esta animación se muestra en funcionamiento:

La subrutina cifrar() debe estar en un fichero separado

Ejercicio 6

Escribe un programa principal que calcule el valor máximo de una serie de bytes almacenados en memoria de forma consecutiva. En el programa principal se define esta serie en tiempo de compilación usando la directiva .byte. El último byte de la serie debe ser el 0, que indica el final. Por ejemplo:

num:    5,8,112,30,42,0

El programa principal llama a la función maximo(pdatos) a la que le pasa un puntero al primer byte de la serie. Esta función devuelve el máximo. El programa principal lo imprimirá en la consola

La función maximo(pdatos) se debe implementar usando el siguiente algoritmo RECURSIVO, descrito mediante este pseudocódigo en python:

def maximo(pdat): 
    if pdat[0]==0: 
      return 0 
    else: 
      m = maximo(pdat[1:]) 
      if pdat[0] > m: 
        return pdat[0] 
      else: 
        return m                              

La subrutina maximo() debe estar en un fichero separado

Ejercicio 7

Escribe un programa principal que pida al usuario el número del término de Fibonacci (n) a calcular y que imprima su valor. Para ello deberá llamar a la función Fibo(n), que tiene un argumento con el término a calcular y devuelve su valor. Esta función se debe implementar siguiente este algoritmo recursivo, descrito en pseudocódigo python:

def fibo(n): 
  if n <=2: 
    return 1 
  else: 
    return fibo(n-1) + fibo(n-2) 

Así, por ejemplo, si se introduce n=10, el resultado deberá ser 55

La subrutina fibo() debe estar en un fichero separado

Ejercicio 8

El objetivo es hacer un programa principal para evaluar expresiones que sean sumas de números de un único dígito (para hacerlo más sencillo), como por ejemplo esta:

1+3+4+5+6+7+2+3+2+0

Se detectarán errores sencillos: Si donde debería haber un dígito hay otra cosa: se notificará un error. Si donde debería haber un simbolo '+' hay otra cosa, también se notificará el error

Primero crearemos la función is_digit(car), que comprueba si car es un número decimal de un dígito: '0'-'9'. La función devuelve 2 parámetros: el primer es el valor entero (car - '0') y el segundo será 0 si car es un dígito y 1 en caso de error

def is_digit(car): 
  if car < '0' or car > '9': 
    return (0, 1) 
  else: 
    return (car - '0', 0) 

Para evaluar la expresión usaremos la función evaluar(pcad), que tiene como parámetro un puntero a la expresión y devuelve dos parámetros: El primero con el valor de la expresión, si no ha habido errores, y el segundo indicando si ha habido error: 1 indica error, y 0 indica que todo ok

La función evaluar(pcad) se deberá implementar usando un algoritmo recursivo, siguiendo este pseudocódigo:

def evaluar(cad): 
   #-- Leer el primer digito 
   val1, err = is_digit(cad[0]) 

   #-- Comprobar si hay error 
   if err: 
      return 0,1 

   #-- Comprobar si es el ultimo numero 
   if cad[1] == '\n': 
     return val1, 0
 
   #-- Comprobar si tras el numero hay un + 
   if cad[1] != '+': 
     return 0,1 

    #-- Calcular la subexpresion 
    val, err = evaluar(cad[2:]) 

    #-- Si hay error retornar
    if err: 
       return 0,1
 
    #-- Devolver la suma del primer digito + la subexpresion 
    return val1 + val, 0 

Asi, por ejemplo, si se prueba con la siguiente expresión:

expr:	.string "1+5+3+4+5+8+9+0+1+0+0+0+0+0+0+0\n"

El programa principal imprimirá en la pantalla el valor: 36. Todas las funciones se harán en ficheros separados

Ejercicio 9

Queremos programar un contador ascendente, que vaya desde 1 hasta 9 en el display de 7 segmentos derecho (que se encuentra mapeado en la dirección 0xFFFF0010). Para ello necesitamos crear la función print_display(n) a la que se le pasa el número entero a mostrar en el display (0 - 9). No devuelve nada

Para implementar esta función usar una tabla de bytes en memoria, con los valores a enviar para encender los segmentos correspondientes a los dígitos 0 - 9. El primer byte contiene el valor para el dígito 0, el siguiente para el 1, etc. Si n es el número a mostrar, y base es la dirección del primer elemento de esta tabla, en base + n se encuentra el valor para representar el dígito n. Basta con hacer la suma y leer el valor de esa dirección

La función contar_up(n) realiza la cuenta hasta el número n. Tiene un parámetro de entrada, n, que indica el número al que llegar y no devuelve nada. La cuenta actual se imprimirá tanto en la consola como en el display de 7 segmentos. Se implementará usando un algoritmo recursivo, cuyo pseudocódigo es:

def contar_up(n): 
    if n > 1: 
       #-- Realizar la cuenta hasta n-1
       contar_up(n-1) 

    #-- Mostrar la cuenta actual      
    print(n) 
    print_display(n) 

El programa principal inicializa el display a 0 llamando a la función display_print(0), luego llamará a contar_up(9) y terminará. Todas las funciones se implementarán en ficheros separados

Ejercicio 10

Queremos hacer ahora una cuenta descendente, desde 9 hasta 1, modificando el programa del ejercicio 9. La función para realizar la cuenta descendente la hace ahora la función count_down(n), donde n indica el número desde el que comienza la cuenta. Esta función se debe implementar también de forma recursiva.

Su algoritmo recursivo es muy parecido al ascendente, pero con algún cambio. Piensa primero cómo sería el pseudo-código. Una vez que tengas claro cómo sería, programa la función en ensamblador

La función count_down(n) muestra la cuenta actual en el display de 7 segmentos llamando a la misma función print_display(n) del ejercicio anterior

El programa principal llama a count_down(9) y termina. Todas las funciones se implementarán en ficheros separados

Autores

Licencia

Enlaces

Página principal


Sesiones de Prácticas

P1: Simulador RARs

L1: Práctica 1-1. RARs
L2: Práctica 1-2. Ensamblador
L3: Práctica 1-3. Variables

P2: E/S mapeada. Llamadas al sistema

L4: Pract 2-1. E/S mapeada
L5: Práctica 2-2: Inst. ecall
L6: Prác 2-3: Cadenas

P3: Bucles y Saltos condicionales

L7: Práct 3-1: Bucles y saltos
L8: Práct 3-2: Cadenas II

P4: Subrutinas

L9: Pract 4-1: Subrut. Nivel-1
L10: Pract 4-2: La pila
L11: Pract 4-3: Recursividad

P5: Memoria Dinámica

L12: Pract 5-1. Heap. Listas

VÍDEO DE DESPEDIDA

Ejercicios de examen

Simulacro examen 1
GISAM. Ordinario. 2019-Dic-11
GISAM. Extra. 2020-Jul-03
GISAM. Ordinario. 2021-Ene-21
GISAM. Ordinario. 2022-Ene-10
GISAM. Extra. 2022-Jun-29
GISAM. Parcial 1. 2022-Oct-26
GISAM. Parcial 2. 2022-Nov-30
GISAM. Parcial 3. 2022-Dic-21
GISAM. Parcial 1. 2023-Oct-09
GISAM. Parcial 2. 2023-Nov-11
GISAM. Parcial 3. 2023-Dic-20
GISAM. Extra. 2024-Jun-17
GISAM. Parcial 1. 2024-Oct-14
GISAM. Parcial 2. 2024-Nov-13
GISAM. Parcial 3. 2024-Dic-16
TELECO. Ordinario. 2019-Dic-13
TELECO. Extra. 2020-Jul-07
TELECO. Ordinario. 2021-Ene-21
TELECO. Extra. 2021-Jul-02
TELECO. Ordinario. 2022-Ene-10
TELECO. Extra. 2022-Jun-29
TELECO. Ordinario. 2023-Ene-10
TELECO. Extra. 2023-Jun-29
TELECO. Parcial 1. 2023-Oct-20
TELECO. Parcial 2. 2023-Nov-17
TELECO. Parcial 3. 2023-Dic-22
TELECO. Extra. 2024-Jun-17
TELECO. Parcial 1. 2024-Oct-10
TELECO. Parcial 2. 2024-Nov-21
TELECO. Parcial 3. 2024-Dic-19
Robótica. Ordinario. 2020-Jun-1
Robótica. Extra. 2020-Jul-13
Robótica. Ordinario. 2021-Mayo-20
Robótica. Extra. 2021-Junio-16
Robótica. Parcial 1. 2022-Feb-25
Robótica. Parcial 2. 2022-Abril-1
Robótica. Parcial 3. 2022-Mayo-6
Robótica. Parcial 1. 2023-Feb-27
Robótica. Parcial 2. 2023-Mar-27
Robótica. Parcial 3. 2023-May-08
Robótica. Parcial 1. 2024-Feb-26
Robótica. Parcial 2. 2024-Mar-20
Robótica. Parcial 3. 2024-May-06
Robótica. Extra. 2024-Junio-24
Datos. Parcial 1. 2023-Oct-09
Datos. Parcial 2. 2023-Nov-15
Datos. Parcial 3. 2023-Dic-20
Datos. Parcial 1. 2024-Oct-09
Datos. Parcial 2. 2024-Nov-13

SOLUCIONES

Práctica 1: Sesiones 1,2 y 3
Práctica 2: Sesiones 4, 5 y 6
Práctica 3: Sesiones 7 y 8
Práctica 4: Sesiones 9, 10 y 11
Práctica 5: Sesión 12

Clone this wiki locally