Introducción a la programación con MATLAB
46 ejercicios resueltos con varias soluciones, todas claramente explicadas
Macario Polo Usaola Profesor Titular de Lenguajes y Sistemas Informáticos en la
Universidad de Castilla-‐La Mancha
1
ÍNDICE DE EJERCICIOS
Ejercicio 1. Factorial iterativo ........................................................................................................ 1
Ejercicio 2. Número combinatorio ............................................................................................... 7
Ejercicio 3. ex por Taylor .................................................................................................................. 9
Ejercicio 4. seno(x) por Taylor .................................................................................................... 13
Ejercicio 5. Factorial recursivo ................................................................................................... 14
Ejercicio 6. Fibonacci ...................................................................................................................... 16
Ejercicio 7. La divina proporción ............................................................................................... 19
Ejercicio 8. Conversión de entero a binario .......................................................................... 20
Ejercicio 9. Contador de apariciones ....................................................................................... 25
Ejercicio 10. Producto escalar .................................................................................................... 28
Ejercicio 11. Fibonacci en un vector ........................................................................................ 31
Ejercicio 12. Distancia al primero ............................................................................................. 33
Ejercicio 13. Números primos .................................................................................................... 41
Ejercicio 14. Vector con los n primeros números primos ............................................... 44
Ejercicio 15. Vector con los n primeros números primos ordenados de mayor a menor 46
Ejercicio 16. Calcular el enésimo número primo ................................................................ 48
Ejercicio 17. Contar números distintos en un vector ....................................................... 49
Ejercicio 18. Descomposición en factores primos (I) ....................................................... 50
Ejercicio 19. Descomposición en factores primos (II) ...................................................... 52
Ejercicio 20. Máximo común divisor ........................................................................................ 54
Ejercicio 21. Tablero de ajedrez ................................................................................................. 56
Ejercicio 22. Alfil ............................................................................................................................... 57
Ejercicio 23. El caballo de ajedrez ............................................................................................. 61
Ejercicio 24. Matriz identidad ..................................................................................................... 68
Ejercicio 25. Diagonal principal ................................................................................................. 70
Ejercicio 26. Traza de una matriz .............................................................................................. 73
Ejercicio 27. Unos y ceros alternados ...................................................................................... 75
Macario Polo Usaola
2
Ejercicio 28. Matriz de Vandermonde ..................................................................................... 81
Ejercicio 29. Matriz de Fibonacci ............................................................................................... 83
Ejercicio 30. Producto de matrices. .......................................................................................... 85
Ejercicio 31. Triángulo de Tartaglia ......................................................................................... 87
Ejercicio 32. Triángulo equilátero ............................................................................................. 90
Ejercicio 33. Matriz triangular superior ................................................................................. 95
Ejercicio 34. Diagonales que se incrementan (I) ................................................................ 99
Ejercicio 35. Diagonales que se incrementan (II) ............................................................. 102
Ejercicio 36. Números ordenados ........................................................................................... 103
Ejercicio 37. Números ordenados descendentemente .................................................. 105
Ejercicio 38. Zigzag ........................................................................................................................ 106
Ejercicio 39. Distancias ................................................................................................................ 107
Ejercicio 40. Distancia en letras ............................................................................................... 111
Ejercicio 41. Buscador de cadenas .......................................................................................... 113
Ejercicio 42. Detección de palíndromos ............................................................................... 115
Ejercicio 43. El monte ................................................................................................................... 124
Ejercicio 44. Cálculo de pi (π) ................................................................................................... 129
Ejercicio 45. La salida del laberinto ....................................................................................... 133
Ejercicio 46. Búsqueda binaria ................................................................................................. 137
46 ejercicios resueltos de MATLAB
1
Ejercicio 1. Factorial iterativo
Realizar una función que, recibiendo como argumento de entrada un número entero n, devuelva el factorial de dicho número.
Si no se recibiese ningún argumento de entrada se deberá devolver un -‐1 y mostrar un mensaje de aviso por pantalla. Si n fuera menor que cero se deberá devolver también un -‐1 y mostrar un mensaje de aviso por pantalla. Si n no fuera entero se deberá redondear hacia +∞ .
El factorial de un número natural n es el producto de todos los números naturales desde 1 hasta ese número n. El factorial de 5, por ejemplo, es 1·2·3·4·5=120. Además, el factorial de 0 es 1. La función factorial se representa con una admiración: n!=n·(n-‐1)·…3·2·1.
• Solución 1.
En una primera solución supondremos que el número que se pasa como argumento a la función es natural y positivo. Para computar el resultado necesitamos únicamente un bucle for que vaya desde 1 hasta n de 1 en 1 (Función 1): a la función la hemos llamado factorial1 y toma un argumento1 n.
function result = factorial1( n ) result=1; for i=1:1:n result=result*i; end end Función 1. Un factorial sencillo, sin comprobación de parámetros y con un for que incrementa
El bucle for i=1:1:n inicializa la variable contador i a 1 y la va incrementando de 1 en 1 hasta n (el valor del argumento pasado). En el cuerpo del bucle se utiliza una variable acumuladora result (puede llamarse de cualquier manera, pero utilizaremos habitualmente result para hacer referencia al resultado que debe devolver la función) en la que iremos guardando el resultado de calcular el valor anterior de result multiplicado por el valor de i. Con objeto de que result vaya almacenando correctamente los valores, es necesario inicializarla a 1 antes de empezar el bucle.
La Tabla 1 muestra una traza de ejecución de la función cuando pasamos 5 como valor del parámetro n: al entrar a la función, ni result ni i tienen valor, y lo único que está definido es el parámetro n. En la asignación result=1 que hay antes del bucle, result toma el valor 1 pero i sigue sin estar definida. Al entrar al bucle por primera vez, result sigue valiendo 1 e i toma ya valor 1.
1 argumento y parámetro significan lo mismo. Utilizaremos ambas palabras indistintamente.
Macario Polo Usaola
2
En la segunda vuelta al bucle, i se ha incrementado en 1, con lo que vale 2, y a result le asignamos el valor que tenía (1) multiplicado por el valor de i: la aparición de la palabra result en el lado derecho de la instrucción result=result*i hace referencia al valor actual de result; la aparición de result en el lado izquierdo hace referencia al valor que le vamos a asignar.
Se continúa de esta manera, haciendo ese cómputo, hasta que i alcance el valor 5, que es el valor de n que pasamos como parámetro y que es la condición de parada en el bucle for: for i=1:1:n
Comentarios n result i Al entrar a la función 5 Al ejecutar result=1 5 1 La primera vez que entramos al bucle 5 result=result*i
result=1*1=1 1
Segunda vuelta al bucle 5 result=result*i result=1*2=2
2
5 result=2*3=6 3 5 result=6*4=24 4 5 result=24*5=120 5
Tabla 1
Si ejecutamos la función desde la línea de comando, obtenemos esto:
>> factorial1(5) ans = 120 Figura 1
La palabra ans que escribe MATLAB es la answer (la respuesta) al cálculo que le hemos solicitado. Muestra un 120 porque, en la cabecera de la función asignábamos a result el resultado de la función, y precisamente es result la variable en la que vamos, iteración a iteración, almacenando el resultado que deseamos.
function result = factorial1( n )
• Solución 2.
Otra forma de implementar exactamente lo mismo es utilizar también un bucle for, pero que vaya desde n hasta 1, de -‐1 en -‐1. Observa (Función 2) que el bucle for ha cambiado:
function result = factorial2( n ) result=1; for i=n:-1:1 result=result*i; end end Función 2. Un factorial sencillo, sin comprobación de parámetros y con un for que decrementa
46 ejercicios resueltos de MATLAB
3
• Solución 3.
En el enunciado del problema nos piden que, si no pasamos ningún argumento, se muestre un mensaje de aviso por pantalla. Ahora mismo se muestra el mensaje de error por defecto de MATLAB, que es bastante feo:
>> factorial2() ??? Input argument "n" is undefined. Error in ==> factorial2 at 3 for i=n:-‐1:1 Figura 2
Modificaremos ligeramente la función para que se compruebe que se pasan argumentos y que, en caso de que no sea así, se muestre un mensaje de error personalizado, la función devuelva 1 y el programa termine: en la Función 3 hemos añadido unas líneas de código en las que usamos la palabra reservada nargin (que indica el número de valores pasados a la función como parámetros) para comprobar que, si es 0, el resultado de la función sea -‐1 (nos lo pide el enunciado), se muestre un mensaje de error (uso de la función disp de MATLAB) y el programa termine (uso de return).
function result = factorial2( n ) if (nargin==0) result=-1; disp('Debes dar un argumento a la función'); return; end result=1; for i=n:-1:1 result=result*i; end end Función 3. El factorial con comprobación del número de parámetros
Ahora, el resultado de llamar a la función sin argumentos es:
>> factorial2() Debes dar un argumento a la función ans = -‐1 Figura 3
• Solución 4.
El enunciado también nos dice que, si n es menor que cero, se dé un mensaje de aviso y se devuelva también -‐1. Una forma de hacerlo es añadir otro if después del if que ya añadimos a la Función 3, de manera que el código quede como en la Función 4:
Macario Polo Usaola
4
function result = factorial2( n ) if (nargin==0) result=-1; disp('Debes dar un argumento a la función'); return; end if (n<0) result=-1; disp('El parámetro debe ser positivo'); return; end result=1; for i=n:-1:1 result=result*i; end end Función 4
Si intentamos calcular, por ejemplo, el factorial de -‐5, se muestra la siguiente respuesta:
>> factorial2(-‐5) El parámetro debe ser positivo ans = -‐1 Figura 4
• Solución 5.
Otra forma de conseguir lo mismo que en la solución anterior es colocar las dos comprobaciones (existencia de un argumento y que éste sea positivo) en un solo if: en la Función 5 unimos ambas condiciones con un or (símbolo |, la barra vertical), de manera que si el número de argumentos es 0 o n es menor que cero, la función devuelva -‐1, se muestre un mensaje de error y se termine el cálculo.
46 ejercicios resueltos de MATLAB
5
function result = factorial2( n ) if (nargin==0 | n<0) result=-1; disp('Debes dar un argumento positivo a la función'); return; end result=1; for i=n:-1:1 result=result*i; end end Función 5
• Solución 6.
Nos piden en el enunciado, por último, que si n no fuera entero se redondee hacia +∞: es decir, si queremos calcular el factorial de 7.85, devolveremos el factorial de 8.
Una vez comprobado que hay un argumento positivo, utilizaremos la función ceil(x) de MATLAB: si x tiene decimales, ceil(x) redondea el valor de x hacia el entero superior más próximo; si no los tiene, deja el valor de x como está.
function result = factorial2( n ) if (nargin==0 | n<0) result=-1; disp('Debes dar un argumento positivo a la funciÛn'); return; end n=ceil(n); result=1; for i=n:-1:1 result=result*i; end end Función 6
Ahora, la función se comporta correctamente:
Macario Polo Usaola
6
>> factorial2(4.5) ans = 120 >> factorial(5) ans = 120 Figura 5
46 ejercicios resueltos de MATLAB
7
Ejercicio 2. Número combinatorio
Escribir una función que calcule el número combinatorio !! , sabiendo que
n>=m, !! = !! = ! y que !! = !!
!!· !!! !. Los valores de n y m serán
argumentos de entrada y el resultado del cálculo se devolverá como argumento de salida.
• Solución 1.
Escribiremos primero una solución algo larga, pero en la que se realiza todo el cálculo: en los primeros tres if (marcados en amarillo) hacemos una comprobación de los argumentos. En el siguiente comprobamos si m es 0 o si n==m, con lo que debemos devolver 1 como resultado.
En los siguientes tres bloques calculamos los factoriales de n, m y de n-‐m usando tres bucles for como los que ya utilizamos en la primera solución a la función factorial (página 1). Estos factoriales los guardamos en tres variables llamadas factorialN, factorialM y factorialNmenosM. Finalmente, asignamos a la variable de resultado (result) el cálculo solicitado.
function result = numeroCombinatorio1( n, m ) if (nargin~=2) disp('Se necesitan dos argumentos'); return; end if (n<0 | m<0) disp('Los argumentos deben ser positivos'); return; end if (n<m) disp('n debe ser mayor o igual que m'); return; end if (n==m | m==0) result=1; return; end factorialN=1; for i=1:1:n factorialN=factorialN*i; end factorialM=1; for i=1:1:m factorialM=factorialM*i; end factorialNmenosM=1; for i=1:1:(n-m) factorialNmenosM=factorialNmenosM*i;
Macario Polo Usaola
8
end result=factorialN/(factorialM*factorialNmenosM); end Función 7
• Solución 2.
En una solución menos complicada podemos utilizar cualquiera de las funciones factorial que escribimos como soluciones del ejercicio 1. Basta con escribir una nueva función en la que las llamamos:
function result = numeroCombinatorio2( n, m ) result=factorial1(n)/(factorial1(m)*factorial1(n-m)) end Función 8
• Solución 3.
En las dos soluciones anteriores repetimos cálculos. Supongamos que nos piden calcular !"! : calculamos primero factorialN=10·9·8·7·6·5·4·3·2·1 y luego computamos factorialM=5·4·3·2·1, con lo que estamos repitiendo parte del cálculo del factorialN.
Si debiéramos hacer este cálculo a mano, probablemente calcularíamos primero el factorial de m y luego, al calcular el de n, nos detendríamos al llegar al valor de m. Es decir, que factorialN=10·9·8·7·6·factorialM. Esto es lo que hacemos en esta solución (Función 9), que requiere menos tiempo de cómputo: en la primera línea se calcula el factorial de m; luego, en el bucle for resaltado en amarillo, vamos guardando en factorialN el valor de multiplicar i desde n hasta el valor de m+1. En la instrucción siguiente, multiplicamos el valor de factorialN por el valor de factorialM que hemos calculado antes, de manera que nos ahorramos unas cuantas vueltas de bucle. Finalmente calculamos (n-‐m)! por el método tradicional y calculamos el resultado final del número combinatorio. Se han omitido las comprobaciones de argumentos para facilitar la lectura del código.
function result = numeroCombinatorio3( n, m ) factorialM=factorial1(m); factorialN=1; for i=n:-1:m+1 factorialN=factorialN*i; end factorialN=factorialN*factorialM; factorialNmenosM=factorial1(n-m); result=factorialN/(factorialM*factorialNmenosM); end Función 9
46 ejercicios resueltos de MATLAB
9
Ejercicio 3. ex por Taylor
Realizar una función que recibiendo como argumento de entrada un número real x devuelva el valor de la exponencial de dicho número, que deberá calcularse mediante su serie de Taylor truncada en n de tal forma que el error absoluto entre la serie en el término n-‐1 y n sea menor de 10-‐7. La serie de Taylor de la exponencial viene dada por la expresión:
!! =!!
!! ,∀!!
!!!
• Solución 1.
Antes de implementar la función es conveniente plantear un ejemplo para ver cómo podemos abordar la solución. Al programar funciones de cálculo, en muchos casos, debemos intentar imitar nuestro propio razonamiento.
Supongamos que deseamos calcular e5 (cuyo valor es 148,4131591025764) mediante la aproximación de Taylor:
!! =!!
!! =!!
!! +!
!!!
!!
!! +!!
!! +!!
!! +⋯
Pararemos cuando la diferencia entre el término n-‐1 y el n sea menor que 0.0000001.
Para una primera solución no tendremos en cuenta esta consideración del error absoluto, y lo que haremos será iterar, por ejemplo, 100 veces. Es decir:
!! =!!
!! =!!
!! +!""
!!!
!!
!! +!!
!! +!!
!! +⋯+!!!
!!! +!!""
!""!
Una forma de implementar esta solución es la siguiente:
function result = exponencialPorTaylor1( x ) result=0; for n=0:1:100 result=result+(x^n)/factorial(n); end end Función 10
El resultado de calcular exponencialPorTaylor1(5) es:
>> exponencialPorTaylor1(5) ans = 148.4132 Figura 6
Macario Polo Usaola
10
• Solución 2.
Podemos escribir una solución parecida a la anterior, pero utilizando un while en lugar de un for. Diremos entonces que mientras n (que es la variable contador del bucle) sea menor o igual a 100, realice el cálculo:
function result = exponencialPorTaylor2( x ) result=0; n=0; while (n<=100) result=result+(x^n)/factorial(n); n=n+1; end end Función 11
• Solución 3.
Con objeto de ir acercándonos a lo que nos pide el enunciado, vamos a modificar ligeramente el código anterior para que la función nos muestre la diferencia entre el valor calculado para n y para n-‐1. Más adelante, en otra solución, utilizaremos este valor (el error absoluto) como condición de parada para devolver el resultado solicitado.
En la Función 12 hemos añadido unas líneas al código anterior: ya que necesitamos comparar, en cada iteración del bucle, el resultado que se acabe de calcular con el anterior, creamos antes del while una variable ultimoResultado a la que asignamos el valor infinito (función Inf() de MATLAB). Luego, en cada vuelta del bucle, asignamos a una variable error la diferencia entre el último resultado calculado (almacenado en la variable ultimoResultado que hemos creado ex profeso para esto) y el resultado que se acaba de calcular. Mostramos el error por la consola (disp(error)) y, por último, actualizamos el valor de ultimoResultado al valor que se acaba de calcular.
function result = exponencialPorTaylor3( x ) result=0; n=0; ultimoResultado=Inf(); while (n<=24) result=result+(x^n)/factorial(n); error=ultimoResultado-result; ultimoResultado=result; disp(error); n=n+1; end end Función 12
Si ejecutamos exponencialPorTaylo3(5), MATLAB muestra lo siguiente:
>>exponencialPorTaylor3(5)
46 ejercicios resueltos de MATLAB
11
Inf -‐5 -‐12.5 -‐20.8333333333333 -‐26.0416666666667 -‐26.0416666666667 -‐21.7013888888889 -‐15.5009920634921 -‐9.68812003968253 -‐5.38228891093473 -‐2.69114445546737 -‐1.2232474797579 -‐0.509686449899135 -‐0.196033249961204 -‐0.070011874986136 -‐0.0233372916620453 -‐0.00729290364438384 -‐0.00214497166010119 -‐0.000595825461147115 -‐0.000156796173996554 -‐3.91990434991385e-‐05 -‐9.33310559503298e-‐06 -‐2.12116034958854e-‐06 -‐4.61121828720934e-‐07 -‐9.60670547556219e-‐08 0 0 ... 0 ans= 148.413159078837 Figura 7
La larga lista de números que muestra (hemos omitido bastantes ceros al final) se corresponde con los valores de error calculados en cada iteración del bucle while.
• Solución 4.
Para cumplir con el enunciado, el cómputo debe detenerse en el momento en que el valor absoluto del error sea menor que 10-‐7. Como lo vamos calculando en cada vuelta del bucle, basta con que modifiquemos la condición de parada del while para que, en lugar de dar 100 vueltas fijas, esté dando vueltas mientras el valor absoluto de error sea mayor o igual a 10-‐7. Es decir, que modificamos el código para que quede como sigue:
Macario Polo Usaola
12
function result = exponencialPorTaylor4( x ) result=0; error=Inf(); ultimoResultado=Inf(); n=0; while (abs(error)>=10e-7) result=result+(x^n)/factorial(n); error=ultimoResultado-result; ultimoResultado=result; n=n+1; end end Función 13
46 ejercicios resueltos de MATLAB
13
Ejercicio 4. seno(x) por Taylor
Escribir una función que recibiendo como argumento de entrada un número real x devuelva el seno de dicho número, que deberá calcularse mediante su serie de Taylor truncada en n de tal forma que el error absoluto entre la serie en el término n-‐1 y n sea menor de 10e-‐7. La serie de Taylor del seno viene dada por la expresión:
!"#$ ! =(−!)!
!"+ ! !!!"!!,∀!
!
!!!
• Solución 1.
La solución a este ejercicio es muy parecida a la del anterior: ya que no sabemos exactamente cuántas iteraciones debemos hacer, sino sólo la condición de parada, lo haremos, como antes, con un bucle while. La condición de parada será la misma, y la forma de cálculo también muy similar. Cambiará únicamente la fórmula de asignación del resultado.
function result = senoTaylor(x) result=0; error=Inf(); resultAnterior=Inf(); n=0; while (abs(error)>=10e-7) result=result+((-1)^n/factorial(2*n+1))*(x^(2*n+1)); error=abs(result-resultAnterior); n=n+1; resultAnterior=result; end end Función 14
Macario Polo Usaola
14
Ejercicio 5. Factorial recursivo
Escribir una función que calcule el factorial de manera recursiva.
• Solución 1.
Una función recursiva es una función que, en su implementación, contiene una llamada a sí misma. La función factorial se describe recursivamente de forma muy natural, ya que:
n!=n·(n-‐1)!
Es decir, el factorial de n es n multiplicado por el factorial de n-‐1. En efecto, 5!=5·4·3·2·1 o, lo que es lo mismo, 5!=5·4!, ya que 4!=4·3·2·1.
En las funciones debe haber siempre, al menos, un caso base, que haga que las sucesivas llamadas a la función se detengan. En el caso del factorial, el caso base se alcanza cuando n=0, ya que 0!=1.
En la Función 15 preguntamos que si el argumento que se está pasando es 0: en caso afirmativo, asignamos a result el valor 1 y la llamada a la función termina; en caso negativo, asignamos a result el resultado de multiplicar n por el factorial de n-‐1, tal y como hacíamos arriba al escribir n!=n·(n-‐1)!
function result = factorialRecursivo( n ) if (n==0) result=1; return else result=n*factorialRecursivo(n-1); return end end Función 15
Supongamos que deseamos calcular recursivamente el factorial de 5. La siguiente tabla muestra una traza de lo que va sucediendo al escribir en la línea de comando de MATLAB factorialRecursivo(5):
Comentarios n result 1ª llamada a la función. Se ejecuta factorialRecursivo(5)
5
Como n no es 0, se entra al else 5 result=5*factorialRecursivo(4) 2ª llamada. Se ejecuta factorialRecursivo(4). n toma ahora el valor 4
4
Como n no es 0, se entra al else 4 result=4* factorialRecursivo(3) 3ª llamada. Se ejecuta factorialRecursivo(3). n entra valiendo 3
3
46 ejercicios resueltos de MATLAB
15
Comentarios n result Como n no es 0, se entra al else 3 result=3* factorialRecursivo(2) 4ª llamada. Se ejecuta factorialRecursivo(2). El valor de n es 2
2
Como n no es 0, se entra al else 2 result=2*factorialRecursivo(1) 5ª llamada. Se ejecuta factorialRecursivo(1). n llega valiendo 1
1
Como n no es 0, se entra al else 1 result=1*factorialRecursivo(0) 6ª llamada. Se ejecuta factorialRecursivo(0). n vale 0
0
n es ahora 0, por lo que es cierta la condición del if (n==0)
0 result=1
En este punto se ha alcanzado el caso base, por lo que no hay más llamadas recursivas. Ahora, el valor calculado en la 6ª llamada se utiliza para calcular el valor
de la 5ª llamada, que a su vez se utiliza para calcular el de la 4ª, etcétera. Regreso a la 5ª llamada. 1 result=1*factorialRecursivo(0)=1*1=1 Regreso a la 4ª llamada. 2 result=2*factorialRecursivo(1)=1*2=1 Regreso a la 3ª llamada. 3 result=3*factorialRecursivo(2)=3*2=6 Regreso a la 2ª llamada. 4 result=4*factorialRecursivo(3)=4*6=24 Regreso a la 1ª llamada. 5 result=5*factorialRecursivo(5)=5*24=120 Tabla 2