Diferencia entre revisiones de «PrInf13: Interrumpir bucles»

De MateWiki
Saltar a: navegación, buscar
(Ejemplo real de uso de break: encontrar si un número es primo)
(Ejemplo real de uso de break: encontrar si un número es primo)
Línea 79: Línea 79:
 
Los dos últimos casos muestran la utilidad de ''break''. ¿Por qué al comprobar el número ''1046527'' nuestro programa tarda mucho más que al comprobar ''1046529''?
 
Los dos últimos casos muestran la utilidad de ''break''. ¿Por qué al comprobar el número ''1046527'' nuestro programa tarda mucho más que al comprobar ''1046529''?
 
{{ Tarea | Modifica el programa anterior para que muestre un mensaje después del bucle diciendo cuántas iteraciones ha realizado el bucle. ¿Cuántas iteraciones hace con el número ''1046529''? ¿Y con el número ''1046529''? ¿Por qué? Pista: el número 1046529 es divisible por 3}}
 
{{ Tarea | Modifica el programa anterior para que muestre un mensaje después del bucle diciendo cuántas iteraciones ha realizado el bucle. ¿Cuántas iteraciones hace con el número ''1046529''? ¿Y con el número ''1046529''? ¿Por qué? Pista: el número 1046529 es divisible por 3}}
 +
Para encontrar un número primo, es necesario probar todos los divisores menores que el número. Estamos probando todos los divisores entre ''2'' y ''n-1''. Sin embargo, es obvio que ningún divisor puede ser mayor que ''n/2'', ya que entonces no hay posibilidad de división entera.
 +
{{ Tarea | Modifica el programa para ajustar más la cantidad de divisores que se prueban, y reducir las iteraciones que tiene que realizar el programa. Comprueba todos los casos anteriores para ver que el programa sigue funcionando correctamente.}}
  
 
== Ejercicio post-práctica ==
 
== Ejercicio post-práctica ==

Revisión del 13:14 2 ago 2013

Práctica de Informática
Cómo interrumpir bucles
Práctica anterior Siguiente práctica
Este artículo es un guión de prácticas de Informática


Warning.png Este artículo está en versión beta. El autor de este artículo no lo ha terminado todavía, por favor no lo edites hasta que elimine este mensaje.

Algunos métodos numéricos intentan buscar la solución a un problema entre los elementos de una matriz y un vector, que contienen todas las posibles soluciones. Una vez que se ha encontrado la solución, el bucle continuará inspeccionando el resto de los elementos que todavía no hayan sido evaluados. Pero si solo hay una solución, estas iteraciones del bucle son innecesarias, ya que sabemos que la solución no estará en esos valores. En este tipo de programas, es mejor interrumpir el bucle y dejar de hacer iteraciones. El uso de interrupciones de bucles debería ser minoritario. Los programas que abusan del uso de interrupciones son más difíciles de entender, y más propensos a contener fallos.

1 Requisitos previos

Es importante haber realizado las dos prácticas sobre bucles con anterioridad a esta práctica:

2 Vídeos posteriores

Tras realizar esta práctica, el siguiente vídeo te ayudará a afianzar conocimientos:

3 Comandos que se aprenderán en esta práctica

break continue

4 Contenido de la práctica

4.1 Primeros pasos con break

Vamos a ver primero un pequeño ejemplo de un programa que usa un bucle con interrupción, para ilustrar su uso. Primero, creamos un vector aleatorio con 20 elementos, entre 0 y 10 y sin parte decimal. Luego usamos un bucle para recorrer el vector y buscar la primera posición que contiene un número impar. Mientras el bucle no encuentre un número impar, sigue funcionando, escribiendo los números que va encontrando en la pantalla:
v = fix(rand(1,20)*10); % Vector con 20 elementos entre 0 y 10
n = length(v); % Número de elementos del vector

for k=1:n
  disp(v(k));
  if rem(v(k),2) ~= 0
    fprintf('He encontrado el primer número impar en la posición %d\n', k);
    break; % El bucle termina aquí
  end
end

Si ejecutamos este programa muchas veces, cada vez obtendremos un resultado diferente. Es muy importante entender que esto solo es un ejemplo de cómo funciona break. Este programa tendría un mejor diseño si se realizara con un bucle while (mientras no encuentres un impar, sigue recorriendo el vector).

Lapiz.png Tarea: Transforma el programa anterior para que use while, y no use ni for ni break


4.2 Primeros pasos con continue

Otro comando que se puede usar con un bucle es continue. Este comando termina la iteración actual, y hace que el bucle pase a la siguiente. Veamos un ejemplo: vamos a mostrar todos los números pares de un vector, e ignorar los impares. Primero, programaremos el bucle que muestra por la pantalla los elementos de un vector:

v = fix(rand(1,20)*10); % Vector con 20 elementos entre 0 y 10 sin decimales
n = length(v);

for k=1:n
 disp(v(k));
end

Este programa simplemente muestra cada elemento del vector en una línea. Vamos a modificarlo para que no se ejecute si el número es impar:

v = fix(rand(1,20)*10); % Vector con 20 elementos entre 0 y 10 sin decimales
n = length(v);

for k=1:n
 if rem(v(k), 2) ~= 0
   continue; % Termina la iteración y pasa al siguiente elemento
 end
 disp(v(k));end

De nuevo, es mejor no abusar del comando continue. El mismo efecto se puede lograr usando un if que bifurque cada iteración. En ocasiones, si hay mucho código, puede ser más limpio usar continue que bifurcar una iteración con if. Pero si nos encontramos con un programa que usa muchas veces continue, es probablemente síntoma de un mal diseño, que conducirá a un programa difícil de entender, y por tanto propenso a contener fallos. En esos casos, es mejor volver a pensar el bucle, e intentar usar while con las condiciones adecuadas, para ver si el código es más sencillo y limpio.

Lapiz.png Tarea: Ejecuta el programa anterior y comprueba que solo muestra por pantalla los elementos pares del vector v


4.3 Ejemplo real de uso de break: encontrar si un número es primo

Una vez que hemos entendido cómo funciona break, vamos a aplicarlo a un caso real. Se trata de averiguar si un número es primo. Recordemos que un número es primo si solo se puede dividir por 1 y por sí mismo. Los divisores de un número tienen que ser necesariamente menores que ese número. Por tanto, nuestro programa probará todos los números más pequeños que nuestro número, y si encuentra alguno que lo divida, entonces resulta que el número no es primo. Veamos el código:
n = input('Introduce el número para probar si es primo: ');

for k=2:(n-1)
  % Si el número k divide a n, no es primo
  if rem(n,k) == 0
    fprintf('El número %d no es primo\n', n);
    break; % No hace falta seguir buscando números
  end
end

Si hay algún número k entre 2 y n-1 que divide a n, entonces el número n no puede ser primo. En el momento que hemos encontrado ese número k ya no es necesario probar más divisores, por eso paramos el bucle usando break. Ejecuta el programa anterior con los siguientes valores de entrada, para comprobar que funciona correctamente:

  • 10 (no es primo)
  • 17 (es primo, y no mostrará nada)
  • 101 (no es primo)
  • 1046527 (es primo, y no mostrará nada, tardará un buen rato)
  • 1046529 (no es primo, y lo encontrará de manera instantánea)

Los dos últimos casos muestran la utilidad de break. ¿Por qué al comprobar el número 1046527 nuestro programa tarda mucho más que al comprobar 1046529?

Lapiz.png Tarea: Modifica el programa anterior para que muestre un mensaje después del bucle diciendo cuántas iteraciones ha realizado el bucle. ¿Cuántas iteraciones hace con el número 1046529? ¿Y con el número 1046529? ¿Por qué? Pista: el número 1046529 es divisible por 3


Para encontrar un número primo, es necesario probar todos los divisores menores que el número. Estamos probando todos los divisores entre 2 y n-1. Sin embargo, es obvio que ningún divisor puede ser mayor que n/2, ya que entonces no hay posibilidad de división entera.

Lapiz.png Tarea: Modifica el programa para ajustar más la cantidad de divisores que se prueban, y reducir las iteraciones que tiene que realizar el programa. Comprueba todos los casos anteriores para ver que el programa sigue funcionando correctamente.


5 Ejercicio post-práctica

El programa anterior no se ajusta bien a la estructura entrada-algoritmo-salida. Modifica el programa anterior para usar una variable bandera, de nombre esPrimo. Inicialmente esta variable valdrá true, y cambiará su valor si se encuentra un divisor de n. Si no se encuentra ningún divisor, esPrimo no cambiará de valor, y tendrá el valor true, que era el valor inicial. En la salida de datos, según esPrimo sea verdadero o falso, el programa debe mostrar que el número es primo o no.

Una vez que hayas realizado el programa con la variable bandera esPrimo, aprovecha esa variable para transformar el programa anterior, y que use while sin necesidad de usar break.