Universidad Carlos III de Madrid

Grado en Ingeniería Telemática/Grado en Ingeniería de Sistemas de Comunicaciones

Enero-Mayo 2014

Repaso: Fundamentos de Java

Lab Section1. Sesión 2 (laboratorio): Ejercicios de Repaso

Recomendamos a los estudiantes programar con un estilo que siga las convenciones habituales del lenguaje Java. El documento Directrices de Programación para Java presenta de forma breve las convenciones más importantes así como instrucciones para configurar Eclipse conforme a las mismas.

Exercise Section1.1. Depuración de un programa en Eclipse: cálculo del número pi

Los depuradores son herramientas de programación que permiten ejecutar de forma controlada un programa, típicamente con el fin de probarlo, encontrar la causa de un error o comprender mejor su funcionamiento.

Algunas de las funciones más habituales que proporcionan los depuradores son:

  • Ejecutar el programa paso a paso (esto es, detener el programa cada vez que este alcance la siguiente línea de código fuente). Tras cada paso, el usuario recupera el control.

  • Detener la ejecución del programa cuando este alcance una determinada línea del código fuente. A partir de este momento, el usuario recupera el control.

  • Cuando la ejecución se encuentra detenida, conocer el valor de una variable o expresión en ese momento.

El entorno de desarrollo Eclipse integra un depurador de Java que puede resultar muy práctico para probar tus programas y, si es el caso, encontrar la causa de que no funcionen.

Apartado 1: Un programa para calcular pi

El siguiente programa permite calcular el valor de pi con la precisión (número de dígitos) que se le indique como argumento de línea de comandos:

import java.math.BigDecimal;
import java.math.MathContext;

public class PiCalc {

    private int numDigits;
    private MathContext mc;

    public PiCalc(int numDigits) {
        this.numDigits = numDigits;
        mc = new MathContext(numDigits);
    }

    public BigDecimal compute() {
        BigDecimal pi = new BigDecimal(0);
        BigDecimal limit = new BigDecimal(1).movePointLeft(numDigits);
        boolean stop = false;
        for (int k = 0; !stop; k++) {
            BigDecimal piK = piFunction(k);
            pi = pi.add(piK);
            if (piK.compareTo(limit) < 0) {
                stop = true;
            }
        }
        return pi.round(mc);
    }

    private BigDecimal piFunction(int k) {
        int k8 = 8 * k;
        BigDecimal val1 = new BigDecimal(4);
        val1 = val1.divide(new BigDecimal(k8 + 1), mc);
        BigDecimal val2 = new BigDecimal(-2);
        val2 = val2.divide(new BigDecimal(k8 + 4), mc);
        BigDecimal val3 = new BigDecimal(-1);
        val3 = val3.divide(new BigDecimal(k8 + 5), mc);
        BigDecimal val4 = new BigDecimal(-1);
        val4 = val4.divide(new BigDecimal(k8 + 6), mc);
        BigDecimal val = val1;
        val = val.add(val2);
        val = val.add(val3);
        val = val.add(val4);
        BigDecimal multiplier = new BigDecimal(16);
        multiplier = multiplier.pow(k);
        BigDecimal one = new BigDecimal(1);
        multiplier = one.divide(multiplier, mc);
        val = val.multiply(multiplier);
        return val;
    }

    public static void main(String[] args) {
        if (args.length != 1) {
            System.err.println("One command-line argument expected: number of "
                               + "digits.");
        } else {
            PiCalc piCalc = new PiCalc(Integer.parseInt(args[0]));
            System.out.println(piCalc.compute());
        }
    }
}

Echa un vistazo general al programa sin preocuparte demasiado por los detalles, y contesta a las siguientes preguntas:

  • ¿Cuál es el flujo del programa? Esto es, qué métodos se ejecutan y en qué orden. ¿Es posible que se ejecute alguno de los métodos más de una vez?

  • ¿Por qué crees que se está usando la clase BigDecimal en vez del tipo de datos float o double? Busca información en la API de Java o en otros recursos de la Web para contestar a esta pregunta.

Apartado 2: Ejecución del programa

Importa el programa en Eclipse y ejecútalo varias veces, cada una con un número de dígitos distinto. Observa que tarda más cuantos más dígitos pides. La causa de esto la comprenderás cuando analices el código en mayor detalle en el próximo apartado.

Apartado 3: Uso del depurador de Eclipse

Utiliza el depurador de Eclipse para profundizar en tu conocimiento de cómo funciona el programa. Para ello, coloca un punto de ruptura (breakpoint) en la primera línea del método compute() (menú Run / Toggle Breakpoint). Ejecuta el programa, pero con la acción Debug en vez de Run. El programa comenzará a ejecutarse y se detendrá cuando alcance la línea en que has puesto el punto de ruptura.

La interfaz gráfica de Eclipse entrará, tras preguntarte, en una perspectiva llamada perspectiva de depuración, que muestra información y controles específicos para la depuración de un programa. En esta perspectiva puedes ver el código fuente, en el cual se resalta la línea donde se ha quedado detenido el programa. Esta línea aún no ha sido ejecutada. Es la primera que se ejecutará si reanudas el programa. También puedes ver el valor de las variables (de momento, sólo muestra this, que se refiere al objeto al cual pertenece el método en que está detenido el programa; si lo despliegas, verás sus atributos). También se muestra la consola.

Una vez el programa está detenido, puedes reanudar su ejecución de varias formas:

  • Opción Run / Resume: reanuda el programa, hasta que finalice o hasta que llegue de nuevo a un punto de ruptura.

  • Opción Run / Step Into: ejecuta la siguiente línea del programa. Si en esta línea se está invocando a un método, se detiene en la primera línea de dicho método, para que lo puedas ejecutar paso a paso.

  • Opción Run / Step Over: ejecuta la siguiente línea del programa. Si en esta línea se está invocando a un método, se ejecuta dicho método completo en un solo paso. Esto es útil si no te interesa depurar el código de ese método.

  • Opción Run / Step Return: ejecuta el método actual hasta el final, y se detiene en la línea siguiente a la que invocó al método actual.

También puedes cancelar en cualquier momento la ejecución del programa mediante la opción Run / Terminate.

Depura el programa con argumento de línea de comandos 10. Cuenta cuántas veces se ejecuta el bucle del método compute() antes de obtenerse el valor de pi definitivo. Haz lo mismo con un número de dígitos un poco mayor. ¿Qué observas?

Vuelve a depurar el programa y observa cómo evoluciona el valor de la variable piK en cada iteración del bucle. ¿Qué le pasa a este valor a medida que se ejecuta el bucle?

Basándote en lo que has observado hasta ahora, y depurando el programa de nuevo si lo crees necesario, ¿qué papel desempeña la variable limit en el programa?

Apartado 4: Fórmula para el cálculo de pi

Observando el código fuente, y usando el depurador si te resulta útil, intenta deducir la fórmula para el cómputo de pi que se está utilizando. Escríbela con notación matemática.

Apartado 5: Área de un círculo

Escribe un programa con una nueva clase que calcule el área de un círculo dado su radio. El programa tendrá un método main que recibirá como argumentos de línea de comandos el número de dígitos de pi con que se deben realizar los cálculos y el radio del círculo. Escribirá en su salida estándar el área calculada.

Tu programa debe utilizar la clase PiCalc de los apartados anteriores para obtener el valor de pi a usar en los cálculos. Utiliza también la clase BigDecimal para realizar los cálculos.

Apartado 6: Área total de varios círculos

Escribe un programa con una nueva clase que calcule la suma de las áreas de varios círculos dados sus radios. El programa tendrá un método main que recibirá como argumentos de línea de comandos el número de dígitos de pi y, a continuación, el radio de un número arbitrario de círculos, cada uno como un argumento de línea de comandos. Escribirá en su salida estándar la suma de las áreas.

Tu programa debe utilizar la clase programada en el apartado anterior, así como la clase BigDecimal para realizar los cálculos.