Miércoles 31 de Marzo

Patrones de programación

Objetivos: Mostrar que en los programas existen patrones de instrucciones que se repiten una y otra vez, y que son útiles para resolver problemas típicos de codificación de los programas.

Temas:


Patrones de programación

Programar no significa colocar líneas al azar y ver si se obtienen los resultados requeridos. Tampoco significa concebir una solución partiendo desde cero. Siempre se reutilizan elementos de programas conocidos. Es así como al estudiar los programas se pueden observar patrones de organización de las instrucciones que se repiten una y otra vez. Estas instrucciones rara vez son idénticas, pero exhiben ciertas similitudes, que denominaremos patrones de programación.

Es importante conocer estos patrones de programación porque son muy útiles para concebir nuevos programas. Ellos resuelven problemas conocidos sin tener que re-inventar soluciones para esos problemas una y otra vez.

Un ejemplo de estos patrones de programación es la acumulación. Este patrón se usa para realizar cálculos como la suma de varios valores calculados en las iteraciones de un ciclo:

suma= val1 + val2 + val3 + ... + valn
producto= fac1 * fac2 * fac3 * ... * facn

La forma general de este patrón es:

    ``tipo'' ``variable'' = ``valor inicial'';
    ...
    while ( ... ) {
      ...
      ``variable'' = ``variable'' ``operador'' ``expresión'';
      ...
    }
Ejemplos:
  1. Contar cuantos números ingresa el usuario, hasta que ingrese el 0:

        ? 4.0
        ? 5.0
        ? 6.0
        ? 0.0
        Contador= 3
    
    Solución:

        int cont= 0;            double suma= 0.0;
        double nota; 
        print("? ");
        nota= readDouble();
        while (nota!=0.0) {
          cont= cont+1;         suma= suma + nota;
          print("? ");
          nota= readDouble();
        }
        print("Contador= ");    print("Suma= ");
        println(cont);          println(suma);
    
    Observe la similitud de esta solución con la que calcula la suma de las notas.

  2. Calcular el promedio de notas:

        ? 4.0
        ? 5.0
        ? 6.0
        ? 0.0
        Promedio= 5.0
    
    Solución: la idea es condensar ambos programas en uno solo. El programa cuenta cuantas notas se han ingresado y suma las notas que se han ingresado en cada iteración.

        double suma= 0;
        int cont= 0;
        double nota;
        print("? ");
        nota= readDouble();
        while (nota!=0.0) {
          suma= suma+nota;
          cont= cont+1;
          print("? ");
          nota= readDouble();
        }
        print("Promedio= ");
        println(suma/cont);
    
    En este programa se presenta también el patrón de lectura de datos. Su forma general es:

        ``tipo'' ``variable'';
        ...
        ``variable''= read``tipo''();
        while ( ... ) {
          ...
          ``variable''= read``tipo''();
        }
    
    Típicamente marcaremos el fin de los datos con un cero o -1.

  3. Desplegar los números enteros de 1 a n:

        ? 4
        1
        2
        3
        4
    
    Solución: nuevamente usamos el patrón de acumulación.
        print("? ");
        int n= readInt();
        int i= 1;
        while (i<=n) {
          println(i);
          i= i+1;
        }
    
    Acá, el programa termina cuando la variable i excede en valor a n. En realidad, estamos acá en presencia de otro patrón muy utilizado: recorrido de un intervalo de enteros. Su forma general es:

        int i= ``valor inicial'';
        while ( i <= ``valor final'' ) {
          ...
          i= i + 1;
        }
    
    La variable i toma valores entre [``valor inicial'',``valor final''], incrementándose en 1 en cada iteración.

  4. Calcular el factorial de un número:

    Definición matemática:

    0! = 1
    n! = (n-1)! cuando n>=1

    O informalmente:

    fact= 1 * 2 * 3 * ... * (n-1) * n

    Solución: al programa anterior le agregamos el producto de los valores sucesivos que toma la variable i en cada iteración. Para hacer el cálculo usamos el patrón acumulación con el operador *.

        print("? ");
        int n= readInt();
        double fact= 1.0;
        int i= 1;
        while (i<=n) {
          fact= fact*i;
          i= i+1;
        }
        print("El factorial es ");
        println(fact);
    
Ejercicio: ejecute paso a paso el programa anterior. Suponga que el usuario ingresa el número 3.


Ejercicio: Calcular exp(x) por medio de la siguiente aproximación.

exp(x)= 1 + x + x^2/2! + x^3/3! + ... + x^i/i! + ... + x^n/n!

El siguiente programa calcula i! al mismo tiempo que calcula x^i.

    double xi= 1.0;
    double facti= 1.0;
    int i= 1;
    while (i<=n) {
      xi= xi*x;
      facti= facti*i;
      i= i+1;
    }
Observe que en la i-ésima iteración, la variable xi es x^i y facti es i!.

A este programa podemos agregarle una acumulación de xi/facti:

    double x= ...; // Obtener x y n
    int n= ...;
    double xi= 1.0;
    double facti= 1.0;
    double expx= 1.0;
    int i= 1;
    while (i<=n) {
      xi= xi*x;
      facti= facti*i;
      expx= expx + xi/facti;
      i= i+1;
    }
Ahora basta desplegar el resultado final con la instrucción:

    println(expx);

Tarea:

Haga un programa que lea varios números positivos (terminados con un -1) e indique en qué rango se encontraban (exceptuando el -1). El diálogo debe ser:

    ? 5
    ? 3
    ? 20
    ? 10
    ? -1
    El rango es [3,20]