Ya en la lección anterior aprendimos que los subalgoritmos o subprogramas son una forma efectiva de atacar un problema complejo dividiéndolo en varios problemas más sencillos de resolver. En esta lección vamos a aprender una manera de lograr esta subdivisión a través del uso de funciones.
Si nos vamos a la definición matemática, una función es una operación que toma uno o más valores llamados argumentos y produce un valor determinado llamado resultado, que es el valor de la función para los argumentos dados. En la octava lección de este curso, aprendimos que en programación existen algunas funciones predeterminadas diseñadas para llevar a cabo cierta tarea o algún cálculo específico; para usarlas, sólo tenemos que "invocarlas" y pasarles algunos argumentos para obtener el resultado buscado. Por ejemplo, aprendimos que la función potencia(b,e) requiere de dos parámetros: base (b) y exponente (e), para regresar el resultado de elevar la base al exponente dado. Todas las funciones que aprendimos en aquella lección se llaman funciones internas porque ya están predefinidas en la mayoría de los lenguajes de programación. Sin embargo, también podemos desarrollar e invocar nuestras propias funciones, a las cuales se les conoce como funciones externas.
Cuando las funciones estándar no permiten realizar la función o cálculo deseado es necesario recurrir a las funciones externas que pueden ser definidas mediante una declaración de función, la cual tiene esta sintaxis:
<tipo_de_resultado> función <nombre_funcion> (lista de parametros o argumentos)
[declaraciones locales]
inicio
<acciones> //cuerpo de la función
devolver (<expresion>)
fin_función
En esta sintaxis vemos que debemos especificar varios componentes importantes:
- El tipo de resultado que nos devuelve la función (si es entero, real, cadena, etc)
- El nombre de la función con la que la vamos a invocar en nuestro algoritmo
- La lista de parámetros o argumentos necesarios para la función. Esta lista debe tener un formato similar a este: (tipo_de_dato: argumento1, tipo_de_dato: argumento2...)
- Las acciones que va a realizar la función con esos argumentos
- La sentencia devolver, en la cual indicamos cuál es el resultado que va a entregar la función. Esta sentencia termina inmediatamente la función en la cual se ejecuta, por lo que siempre debe estar situada al final, justo antes del fin de la función. Es importante recordar también que una función sólo debe regresar un valor único.
Vamos a imaginar que la función potencia(b,e) no existe y tenemos que programarla nosotros mismos. El algoritmo completo de un programa que solicita al usuario los valores de la base y el exponente y luego muestra el resultado del cálculo, debería verse algo así:
var
real: base, exponente, res
inicio
escribir("Introduce el valor de la base: ")
leer(base)
escribir("Introduce el exponente: ")
leer(exponente)
res <- potencia(base,exponente)
escribir("El resultado calculado es: ", res)
fin
real función potencia(real b, real e)
var
real: resultado
entero: i
inicio
resultado <- 1
desde i<-1 hasta e hacer
resultado <- resultado * b
fin_desde
devolver (resultado)
fin_función
Como puedes observar, el pseudocódigo correspondiente a la función potencia se encuentra localizado fuera del cuerpo del algoritmo principal (calcular_potencia). Sin embargo, ese código es ejecutado en el momento que se llama a la función por su nombre y se le pasan los parámetros correspondientes. Observa también que no es necesario que los nombres de las variables que se pasan como argumentos (base, exponente) sean iguales a las variables que recibirán dichos datos en la función (b,e). Cuando hagamos la invocación a la función, los valores se corresponderán en el mismo orden que los pasemos, es decir, el valor de base se asignará a b y el valor de exponente se asignará a e. Por supuesto, si queremos evitar usar tantos nombres distintos, podemos usar los mismos nombres para las variables tanto en la declaración de la función como en su llamada desde el programa principal. En ambos casos el resultado será el mismo. Finalmente, observa que una vez que se ejecuta el cuerpo de la función, se devuelve el valor almacenado en la variable resultado, el cual, al regresar al algoritmo principal, se almacena en la variable res, que es la que finalmente mostramos al usuario. En cierto sentido, para el programa principal, el funcionamiento de la función potencia es una caja negra, pues sólo le interesa que devuelva el resultado del cálculo sin importar cómo se hace.
Mira cómo se ve este ejemplo corriendo en C#:
Ahora veamos otro ejemplo. En el siguiente algoritmo, creamos un programa que utiliza una función para calcular el factorial de un número dado por el usuario. Por si no lo recuerdas, el factorial de un número n, representado como n!, es igual al producto de todos los números que están por debajo de n, incluyendo a este último. Es decir: n! = n * (n-1) * (n-2) * (n-3) ...
entero función factorial (entero n)
var
entero: i, f
inicio
f <- 1
desde i<-1 hasta n hacer
f <- f * i
fin_desde
devolver (f)
fin_función
algoritmo calcular_factorial
var
entero: n
inicio
escribir("Dame un número entero: ")
leer(n)
escribir("El factorial de ", n, " es igual a ", factorial(n))
fin
Si te fijas bien, en este listado el código de la función está antes del algoritmo principal. Esto también es perfectamente válido (de hecho, algunos lenguajes de programación exigen que se declaren primero las funciones, antes del programa principal). También observa que en este caso no asignamos el resultado de la invocación de la función a una variable, sino que directamente estamos escribiendo el resutlado sin usar una variable intermedia. El usuario nunca verá en pantalla el texto "factorial(n)", sino que verá el resultado del cálculo junto con el resto del mensaje que le estamos mostrando.
Mira cómo funciona este programa en C#:
En este último ejemplo creamos no una sino dos funciones que se llaman mutuamente y trabajan en conjunto para calcular el área de un polígono de n lados.
algoritmo area_poligono
var
real: n, lado, ap, area
inicio
escribir("¿Cuántos lados tiene el polígono? ")
leer (n)
escribir("¿Cuál es la medida de esos lados? ")
leer(lado)
escribir("¿Cuánto mide el apotema? ")
leer(ap)
area = area_poligono(n, lado, ap)
escribir("El área del polígono es de ", area)
fin
real función area_poligono(real n, real lado, real ap)
var
real: area
inicio
area = perimetro(n, lado) * ap
devolver (area)
fin_función
real función perimetro(real n, real lado)
inicio
devolver n * lado
fin_función
Observa cómo funciona este código en C#:
real: n, lado, ap, area
inicio
escribir("¿Cuántos lados tiene el polígono? ")
leer (n)
escribir("¿Cuál es la medida de esos lados? ")
leer(lado)
escribir("¿Cuánto mide el apotema? ")
leer(ap)
area = area_poligono(n, lado, ap)
escribir("El área del polígono es de ", area)
fin
real función area_poligono(real n, real lado, real ap)
var
real: area
inicio
area = perimetro(n, lado) * ap
devolver (area)
fin_función
real función perimetro(real n, real lado)
inicio
devolver n * lado
fin_función
Observa cómo funciona este código en C#:
En estos ejemplos ha quedado en evidencia la utilidad de las funciones como un medio para dividir un problema complejo en pequeños problemas más fáciles de resolver y así llegar a una solución a dicho problema. Sin embargo, las funciones tienen una limitación importante: sólo pueden devolver un valor a la vez. ¿Qué pasa si necesito devolver dos o más valores? Para eso existen los procedimientos, los cuales vamos a estudiar en la siguiente lección. ¡Hasta la próxima!
ACTIVIDADES DE APRENDIZAJE
- Escribe un algoritmo que use una función creada por tí para encontrar el mayor de dos números enteros dados por el usuario.
- Diseña una función booleana llamada Digito que determine si un caracter dado por el usuario es uno de los dígitos del 0 al 9
- Escribe una función que transforme un número entero dado en su correspondiente número romano (nota: limita los números a convertir al rango de 1 a 3999 únicamente)
Enlace: Índice del curso
0 comentarios:
Publicar un comentario