Está en la página 1de 17

PROGRAMACIÓN

Grado en Física
Facultad de Ciencias

Práctica 6

Práctica 6: Programación modular II

Requisitos previos a la sesión de prácticas

El alumno deberá haber estudiado previamente la materia correspondiente al Tema 6:


Funciones, haber realizado la Relación 3 de problemas y haber leído atentamente este
guión antes del comienzo de la sesión.

Texto recomendado: Problemas de programación, capítulo 4. Editorial AVICAM.

1. Introducción

Cuando se desarrolla un programa en el ámbito científico es importante que el


resultado sea correcto. Sin embargo, en muchos casos, dar la solución correcta no
es suficiente, sino que también es necesario que dicha solución sea calculada en
el menor tiempo posible: esto es lo que se llama eficiencia. En general, para
solucionar un problema existen diversos algoritmos e implementaciones, y algunas
son más eficientes que otras.

En el campo de la Física o las Matemáticas los computadores se utilizan para


resolver problemas de cómputo intensivo. Esto quiere decir que la mayor parte
de los problemas en estos campos engloban una cantidad de operaciones
enorme, lo que conlleva que se necesiten grandes tiempos de cómputo para
resolverlos. No es extraño que un programa tarde horas, días o, incluso, semanas
para obtener la solución a un problema dado. En algunos casos, incluso, hay
problemas que, en la práctica, no se pueden solucionar porque requerirían un
tiempo de cómputo que abarcaría años, siglos o milenios en el mejor de los
computadores actuales.

La resolución eficiente de los problemas es una de los prerrogativas de la


programación científica, ya que es preferible usar algoritmos más eficientes que
esperar a disponer de un ordenador más potente. Estadísticamente, la potencia de
los computadores se multiplica por 10 cada 10 años: esto quiere decir que si hoy
tiene un programa que tarda en dar la solución 1 año (365 días sin interrupción),
un ordenador de dentro de 10 años tardará 36,5 días, uno de dentro de 20 años
tardará 3,65 días, etc; en cambio, si consigue desarrollar un programa 10-100-
1000 (o más) más eficiente, no tendrá que esperar varias decenas de años a tener
un mejor computador que obtenga la solución en un tiempo razonable.

Una de las ventajas de la programación modular es que si en el futuro


desarrollamos un módulo más eficiente que uno determinado, sustituyendo el
1 de 17
PROGRAMACIÓN
Grado en Física
Facultad de Ciencias

Práctica 6
módulo antiguo por el nuevo en un programa y compilándolo de nuevo,
inmediatamente dispondremos de un programa más eficiente. Esto será factible si
ambos módulos usan la misma interfaz, es decir, la llamada al módulo es idéntica
que la anterior (mismos parámetros) y los resultados de ambos son idénticos
(valores devueltos del mismo tipo).

2. Programa a realizar en el laboratorio


Para ilustrar el tema de la eficiencia vamos a resolver problema: calcular la suma
de todos los números primos menores o iguales que un número determinado.

Nuestro programa pedirá que se introduzca un número n desde el teclado y


recorrerá todos los enteros menores o iguales que dicho número, añadiendo a la
suma aquellos que sean primos.

Por tanto, aparte de la función principal, vamos a necesitar una función que
indique si un número es primo o no.

2.1 La función principal: main()

2 de 17
PROGRAMACIÓN
Grado en Física
Facultad de Ciencias

Práctica 6

2.2 La función es_primo()

En cada iteración del ciclo for es necesario comprobar si el número es primo o no


antes de sumarlo. Para hacer esta comprobación vamos a implementar la
alternativa más simple: comprobaremos si el número se puede dividir entre otro
menor que él. Si no encontramos ningún número menor que lo divida, entonces
concluimos que es primo.

2.3 Ficheros de inclusión, directivas y prototipos

Por último, no debemos olvidar añadir al principio del código fuente las directivas
de inclusión, las directivas de definición y los prototipos de las funciones que
hemos declarado:

3 de 17
PROGRAMACIÓN
Grado en Física
Facultad de Ciencias

Práctica 6
3. Probando el programa

Copie el programa expuesto anteriormente tratando de entender los distintos


algoritmos que se han seguido para implementar las funciones. Compile y ejecute
el programa para comprobar que éste funciona correctamente. Compruebe que
salen los siguientes resultados:

n suma
5 10
10 17
500 21.536
1000 76.127
20000 21.171.191
50000 121.013.308

Además, comprobaremos que cuanto mayor es el número, mayor es el tiempo


necesario para realizar la suma, puesto que es necesario comprobar si son primos
muchos más números. Para números pequeños la solución se obtiene enseguida,
pero para 50.000 ya se tardan varios segundos, y para números mayores el
tiempo crece cada vez más.

4. Calculando el tiempo de ejecución

A menudo puede ser necesario calcular el tiempo que tarda en ejecutarse un


programa, función o rutina de cara a estudiar su eficiencia. Podríamos hacerlo
cronómetro en mano, pero es mejor usar algún procedimiento algo más preciso y
menos tedioso.

La biblioteca estándar de C/C++ provee unas funciones para calcular el tiempo


transcurrido entre dos instantes de tiempo en un programa. Concretamente,
vamos a usar la función clock(), incluida en la biblioteca ctime.

El tiempo en un ordenador se mide en ciclos de reloj, de forma que 1 segundo


consta de varios miles de ciclos. La función clock(), cada vez que se invoca,
devuelve el número de ciclos de reloj transcurridos desde el comienzo del
programa. Para averiguar el tiempo que se invierte en ejecutar una rutina,
simplemente hay que llamar a la función clock() dos veces, antes de iniciar la
rutina y al terminar. La diferencia entre esos dos instantes indicará el número de
ciclos de reloj invertidos. A partir de este valor, se puede calcular el tiempo en
segundos dividiendo por la constante CLOCKS_PER_SEC, es decir, por el
número de ciclos/segundo. Por ejemplo:

4 de 17
PROGRAMACIÓN
Grado en Física
Facultad de Ciencias

Práctica 6
t1=clock();
bloque_instrucciones_que_quiero_medir;
t2=clock();

numsecs=(double)(t2-t1)/CLOCKS_PER_SEC;

Fíjese en que hemos tenido que transformar el numerador a double para forzar el
cociente real.

5. Calculando el tiempo de ejecución de nuestra rutina

Vamos a medir el tiempo que tarda en ejecutarse la suma de los números primos.
En negrita se muestran las modificaciones a realizar en la función principal.

5 de 17
PROGRAMACIÓN
Grado en Física
Facultad de Ciencias

Práctica 6

Además, de los cambios señalados, recuerde que al principio del programa debe
añadir una directiva que incluya al fichero ctime:

6 de 17
PROGRAMACIÓN
Grado en Física
Facultad de Ciencias

Práctica 6

Ejercicios de laboratorio (5 puntos)

Ejercicio de laboratorio L6.1

Tal y como se indica en el apartado 2 copie el primer programa expuesto y


verifique que es correcto, validando los valores de la tabla que se indican en el
apartado 3.

Modifique el programa tal y como se indica en los apartados 4 y 5 para poder


calcular el tiempo que se invierte en calcular la suma de números primos.

Realice 10 pruebas, para los siguientes valores de n: 10.000, 20.000, 30.000,


40.000, 50.000, 60.000, 70.000, 80.000, 90.000 y 100.000. Para cada una de ellas
anote en una tabla el número resultante de la suma, así como el tiempo invertido
para calcularla.

Ejercicio de laboratorio L6.2

La función es_primo() que hemos realizado es muy poco eficiente y puede


mejorarse bastante (en clase de problemas se han visto varias alternativas).

Una mejora inmediata es sustituir el ciclo for por un ciclo while: en la


implementación realizada se usa un ciclo for para recorrer todos los números
menores que uno dado y comprobar si lo dividen pero, en realidad, si encontramos
que uno lo divide no tiene sentido seguir comprobando el resto, ya que ya hemos
averiguado que el número no es primo y no tiene sentido seguir probando.
Podemos reescribir la función es_primo() de la siguiente manera:

7 de 17
PROGRAMACIÓN
Grado en Física
Facultad de Ciencias

Práctica 6

Copie en un nuevo fichero el programa anterior sustituyendo la función


es_primo() anterior por esta última. Compile y ejecute el nuevo programa,
realizando las mismas 10 pruebas que en el ejercicio de laboratorio 1.

Anote en una tabla los resultados obtenidos para la suma y el tiempo invertido en
calcularla. Comprobará que se obtiene el mismo resultado para la suma pero ha
mejorado el tiempo considerablemente con un cambio muy pequeño, pero
altamente efectivo.

Cuando termine los dos programas y haya rellenado las dos tablas, avise al
profesor para que lo compruebe. Recuerde subir a SWAD tanto los códigos fuente
de ambos programas como las dos tablas realizadas.

8 de 17
PROGRAMACIÓN
Grado en Física
Facultad de Ciencias

Práctica 6

Ejercicios propuestos (5 puntos)

Mediante los ejercicios que se proponen en este guión, vamos a realizar un


estudio de la eficiencia de un programa. Para ello, vamos a resolver un mismo
problema con tres algoritmos distintos y vamos a comparar los resultados de
tiempo de cálculo que se obtienen con ellos.

Ejercicio P6.1
Repita en el ordenador de su casa los mismos experimentos que ha realizado en
el laboratorio con los dos programas realizados.
Usando el primer programa implementado, rellene una tabla que muestre los
resultados obtenidos para la suma y el tiempo de ejecución para los siguientes
valores de n: 10.000, 20.000, 30.000, 40.000, 50.000, 60.000, 70.000, 80.000,
90.000 y 100.000.
Realice una gráfica del tiempo de ejecución t en función de n. Realice un ajuste
polinomial para obtener un modelo matemático que permita calcular el tiempo de
ejecución t a partir del valor de n. Usando el polinomio obtenido añada una
columna en la tabla anterior que muestre el tiempo calculado con el polinomio para
cada uno de los valores de n considerados en los experimentos. (Ver anexo sobre
ajuste de curvas para hacer esta parte).

Ejercicio P6.2
Usando el segundo programa implementado, rellene una tabla que muestre los
resultados obtenidos para la suma y el tiempo de ejecución para los siguientes
valores de n: 10.000, 20.000, 30.000, 40.000, 50.000, 60.000, 70.000, 80.000,
90.000 y 100.000.
Realice una gráfica del tiempo de ejecución t en función de n. Realice un ajuste
polinomial para obtener un modelo matemático que permita calcular el tiempo de
ejecución t a partir del valor de n. Usando el polinomio obtenido añada una
columna en la tabla anterior que muestre el tiempo calculado con el polinomio para
cada uno de los valores de n considerados en los experimentos. (Ver anexo sobre
ajuste de curvas para hacer esta parte).

9 de 17
PROGRAMACIÓN
Grado en Física
Facultad de Ciencias

Práctica 6
Ejercicio P6.3

Vamos a repetir exactamente los mismos pasos que en los ejercicios anteriores
usando un nuevo algoritmo. El código de la función es_primo() que vamos a
probar es el siguiente (explicado en clase de problemas):

Notará enseguida que el resultado de la suma se obtiene en un tiempo


espectacularmente inferior a los otros dos. De hecho, es probable que la medición
del tiempo resulte ser 0; el motivo es que se ejecuta tan rápido que no se tiene la
suficiente precisión para distinguir lapsos de tiempo tan pequeños. Un truco para
poder medir el tiempo en casos como éste, consiste en repetir la misma rutina
varias veces y promediar el tiempo total que se invierte en ello, es decir, hacer
algo así:

t1=clock();
for(r=1; r<=100; r++)
bloque_instrucciones_que_quiero_medir;
t2=clock();

numsecs=(double)(t2-t1)/(CLOCKS_PER_SEC*100);

10 de 17
PROGRAMACIÓN
Grado en Física
Facultad de Ciencias

Práctica 6
En el ejemplo estamos midiendo el tiempo necesario para ejecutar la misma rutina
100 veces, y después se divide ese tiempo total entre 100 para calcular lo que se
tarda en ejecutarla una única vez, que es lo que nos interesa (es decir, en nuestro
caso, debemos ejecutar la suma acumulada 100 veces consecutivas para cada
valor de n, y dividir entre 100 el tiempo total medido). Si fuese necesario tener más
precisión, en vez de 100 puede usarse un factor mayor.

Así pues, implemente un nuevo programa que use esta última función y realice los
cambios necesarios para poder medir el tiempo de ejecución.
Rellene una tabla que muestre los resultados de la suma y del tiempo de cálculo
dobtenido para los siguientes valores de n: 10.000, 20.000, …, 100.000.
Realice una gráfica del tiempo de ejecución t en función de n. Realice un ajuste
polinomial para obtener un modelo matemático que permita calcular el tiempo de
ejecución t a partir del valor de n. Usando el polinomio obtenido añada una
columna en la tabla anterior que muestre el tiempo calculado con el polinomio para
cada uno de los valores de n considerados en los experimentos. (Ver anexo sobre
ajuste de curvas para hacer esta parte).

Ejercicio P6.4
Al realizar el ajuste de los datos medidos para el tiempo de ejecución en los 3
ejercicios anteriores, ha obtenido los coeficientes de un polinomio de segundo
grado que le permiten calcular el tiempo que tardará en ejecutarse cada programa
a partir del valor de n, sin necesidad de tener que ejecutar el programa para
medirlo.
Usando los coeficientes obtenidos para cada caso, diseñe una nueva tabla para
comparar el tiempo que tardaría en ejecutarse cada uno de los programas para
valores grandes de n.
Así, debe confeccionar una nueva tabla que muestre muestre el tiempo estimado
que el ordenador invertirá en calcular la suma de los primos menores que los
siguientes valores de n: 1.000.000, 10.000.000, 100.000.000 y 1.000.000.000 . En
dicha tabla, para cada uno de los programas, exprese el valor del tiempo obtenido
en segundos y también expresado en días.

Nota: Es imprescindible que ejecute los tres algoritmos en el mismo ordenador, ya que va a
comparar sus tiempos de ejecución. Procure que el ordenador no esté realizando otras tareas ni
ejecutando otros programas mientras realiza las medidas (no esté descargando nada, ni
escuchando música, ni haciendo copias de seguridad, etc), ya que le afectaría.

11 de 17
PROGRAMACIÓN
Grado en Física
Facultad de Ciencias

Práctica 6
Conteste a las siguientes preguntas:

1. Indique las características del computador que ha utilizado para los


ejercicios propuestos:

a. Tipo de procesador (Celerón, i3, i5, i7, … ), modelo y frecuencia.


b. Cantidad de memoria principal (2GB, 4GB, ...)
c. Sistema operativo instalado (Windows 10, MacOS version, ...)
(puede averiguar estas tres cosas picando con el botón derecho del ratón
sobre el icono de “Equipo” o en “Acerca de este equipo” y seleccionando la
opción “Propiedades”).

2. ¿Cuántos años tardaría el algoritmo menos eficiente que ha implementado


en calcular la suma de los primos menores que 1.000.000.000 (mil
millones)?

3. ¿Cuántos años tardaría el algoritmo más eficiente que ha implementado en


calcular la suma de los primos menores que 1.000.000.000 (mil millones)?

4. Si se cumple la previsión que indica que cada 10 años la potencia de los


computadores se multiplica por 10, ¿cuantos años tendría que esperar
aproximadamente para comprar un ordenador que calculase la suma de los
primos menores o iguales que 1.000.000.000 usando el programa menos
eficiente en el mismo tiempo que lo hace ahora el más eficiente en su
ordenador actual?

12 de 17
PROGRAMACIÓN
Grado en Física
Facultad de Ciencias

Práctica 6
Anexo: Ajuste de curvas y regresión
Ajustar una curva a partir de datos experimentales es una operación usual en
cualquier experimento. Consiste en encontrar una expresión matemática que
reproduzca de forma fiel los mismos resultados que se han obtenido en un
experimento.
Por ejemplo, imaginemos que medimos una barra de metal a distintas
temperaturas y queremos conocer la fórmula que relaciona la longitud de dicha
barra con la temperatura. Para conseguirlo, existe una herramienta estadística
llamada “análisis de regresión” que, usando las medidas que hemos realizado,
permite obtener una expresión matemática que ajusta esos datos, es decir,
obtendremos una fórmula en la que, a partir del valor de la temperatura,
proporcionará el valor de la longitud de la barra metálica que se ha medido.
Probablemente, en las clases de prácticas de Física les habrán enseñado a
realizar ajustes o regresiones mediante rectas (si no lo han hecho aún, pronto lo
harán, pueden estar seguros). El ajuste mediante una recta es válido cuando
existe una relación lineal del tipo y = ax + b entre la variable medida (y) y la
variable usada como referencia (x). Por ejemplo, en el caso de la barra metálica, lo
medido sería la longitud y la referencia sería la temperatura (L = aT + b).
En general, las relaciones entre 2 variables físicas no siempre son lineales y por
ello existen otros tipos de ajustes que usan más variables o más coeficientes para
modelar formas o relaciones más complejas. Un tipo de ajuste muy usual es el
polinómico, en el cual se usa un polinomio de grado n para modelar
matemáticamente la relación entre 2 variables:

y = a x n + b x n−1 + c x n−2 + ....

En nuestro caso, usaremos un polinomio de grado 2, es decir, mediante una


expresión del tipo:

t = a n2 + b n + c

siendo t el tiempo de ejecución y n el valor del entero para el que queremos


calcular la suma de los primos menores que él.
Escoger un ajuste de grado 2 para este problema no es una decisión arbitraria de
los profesores; en cualquiera de los programas de este guión, hay 2 bucles
anidados por lo que se intuye que, por tanto, para cualquier valor del entero n, se
realizarán del orden de n2 iteraciones, es decir, la complejidad del algoritmo es
O(n2), por lo que justamente se necesita un ajuste polinomial de grado 2.

13 de 17
PROGRAMACIÓN
Grado en Física
Facultad de Ciencias

Práctica 6
Por tanto, haremos un análisis de regresión usando las medidas que hemos
realizado y obtendremos los valores de los coeficientes a, b y c del polinomio.
Usando esos coeficientes podremos calcular el valor de t para cualquier n,
simplemente usando el polinomio resultante, sin necesidad de tener que hacer
nuevos experimentos.
Existen muchos programas que permiten calcular las curvas de regresión
(Microsoft Excel u OpenOffice, por ejemplo). Sin embargo, por sencillez,
recomendamos usar una aplicación online y gratuita llamada Polynomial
Regression Data Fit:
http://arachnoid.com/polysolve/index.html

Calculando las curvas de ajuste de nuestras medidas


Accediendo a la aplicación indicada desde un navegador web, veremos una
página con cuatro áreas bien diferenciadas:
• Área de introducción de datos (Figura 1). En este área simplemente
debemos copiar las columnas correspondientes al valor de n y t de la tabla
que hemos confeccionado para cada programa.

Figura 1. Area de introducción de datos

• Área de dibujo (Figura 2). En esta zona se mostrará una gráfica con los
puntos correspondientes a los datos introducidos (en color rojo). En color
azul se dibujará la curva correspondiente al polinomio que mejor concuerda
con esos datos. Compruebe el ajuste que realiza si usa un ajuste lineal en
vez de un polinomio de grado 2, u otros tipos de ajustes; verá que el
14 de 17
PROGRAMACIÓN
Grado en Física
Facultad de Ciencias

Práctica 6
modelo resultante es mucho más impreciso que en nuestro caso, lo cual
permite percibir visualmente si el modelo matemático usado para ajustar los
datos es más o menos preciso.

Figura 2. Área de dibujo.

• Área de resultados (Figura 3). En esta zona se mostrarán los valores


obtenidos para los coeficientes del polinomio que ajusta nuestros datos. En
nuestro caso, hemos obtenido que nuestros datos se ajustan muy bien con
el polinomio:
t = 4.645 10-2 – 1.077 10-7 n + 1.774 10-9 n2
es decir, para un valor de n cualquiera, usando esa expresión pordríamos
predecir el tiempo t necesario para ejecutar nuestro algoritmo.

15 de 17
PROGRAMACIÓN
Grado en Física
Facultad de Ciencias

Práctica 6

Figura 3. Área de resultados.

• Tabla generadora (Figura 4). En esta zona se muestran los resultados que
se obtienen usando los coeficientes calculados para distintos valores de n.
De esta forma podemos observar si los valores que se calculan son
similares a los obtenidos experimentalmente (usando los mismos valores de
n para el cálculo que utilizamos para las mediciones) o bien, estimar qué
valor se obtiene para t usando valores de n arbitrarios.

Figura 4. Área de generación de valores.

16 de 17
PROGRAMACIÓN
Grado en Física
Facultad de Ciencias

Práctica 6

En resumen, en la memoria de prácticas debe entregar para esta práctica:

1. El código fuente de cada programa implementado


2. Las capturas de pantalla de la ejecución de cada uno de los programas
3. Las tablas de resultados de la suma y el tiempo de cálculo de cada
programa para valores de n: 10.000, 20.000, …, 100.000 (*). Recuerde que
además de los valores medidos, debe mostrar los valores calculados con el
polinomio de ajuste obtenido.
4. Las gráficas que representan el tiempo de ejecución en función del valor de
n (**)
5. Valor de los tres coeficientes de las curvas que ajustan cuadráticamente los
puntos obtenidos en las mediciones
6. Tabla que muestre el tiempo de cálculo (en segundos y en días) que se
emplearía con cada uno de los programas implementados para calcular la
suma de los primos menores o iguales que: 1.000.000, 10.000.000,
100.000.000 y 1.000.000.000.
7. Responder a las cuestiones planteadas.

Compruebe que usando la aplicación expuesta en este anexo, es muy simple lo


que tiene que hacer en esta práctica (básicamente copiar los códigos fuente y
tomar medidas del tiempo de ejecución), ya que todo lo demás (gráficas, valores
de los coeficientes del polinomio, cálculo de valores estimados) se puede hacer
con dicha aplicación.

Los ejercicios propuestos en esta práctica formarán parte de la segunda memoria


de prácticas, que se completará con ejercicios propuestos de las prácticas
siguientes.

(*) Es imprescindible que ejecute los tres algoritmos en el mismo ordenador, ya que va a comparar
sus tiempos de ejecución. Procure que el ordenador no esté realizando otras tareas ni ejecutando
otros programas mientras realiza estas medidas.

(**) Las gráficas pueden ser simplemente las capturas de pantalla de la gráfica que genera la
página de http://arachnoid.com/polysolve/index.html como resultado del ajuste.

17 de 17

También podría gustarte