Sei sulla pagina 1di 56

4 Informática (Teorı́a)

Python: Fors, Tiempo de cálculo y


Programas interactivos

Joaquim Gabarro
gabarro@cs.upc.edu

Computer Science
Universitat Politècnica de Catalunya
Ejemplos con for

Tiempo de cálculo

Primeros pasos en integración mumérica

Programación Interactiva

Dos nuevas instrucciones

Evaluación de un polinomio

Contando de nuevo primos

Bibliografı́a
Ejemplos con for
Example: drawH(n)

P56724 Simple types and strings (1), first exercise.

Write a function drawH(n) that given an odd integer n≥ 3 prints


a letter H of size n formed with symbol *. Follow the pattern of
the example below.

>>> drawH(5)
* *
* *
*****
* *
* *
Veamos como imprimir los dos tipos de lineas horizontales que
aparecen en la H.
Recordemos que n ≥ 3 con lo que n-2>0.

>>> n=5
>>> print(n*’*’)
*****
>>> print(’*’ + (n - 2)*’ ’ + ’*’)
* *
>>>
Esquematicamente:
def drawH(n):
escribir n//2 veces
print(’*’ + (n - 2)*’ ’ + ’*’)
print(n*’*’)
escribir n//2 veces
print(’*’ + (n - 2)*’ ’ + ’*’)

Tratemos:
escribir n//2 veces
print(’*’ + (n - 2)*’ ’ + ’*’)

Introduciendo una variable mid = n//2 (mid denota middle) y


una variable line para recorrer el for tenemos:
for line in range(mid):
print(’*’ + (n - 2)*’ ’ + ’*’)
Finalmente (fichero drawH.py):

def drawH(n):
mid = n//2
for line in range(mid):
print(’*’ + (n - 2)*’ ’ + ’*’)
print(n*’*’)
for line in range(mid):
print(’*’ + (n - 2)*’ ’ + ’*’)
===== RESTART: C:/..../drawH.py =====
>>> drawH(9)
* *
* *
* *
* *
********
* *
* *
* *
* *
>>>
Ejemplo: Contando números primos

Dado n>1, se pide diseñar una función count primes(n) que


retorne cuantos números primos hay entre 2 y n.
Por ejemplo n=10 :

2, 3, 4, 5, 6, 7, 8, 9, 10

Entre 2 y 10 los primos son 2, 3, 5, 7 por lo tanto


count primes(10) ha de retornar 4
Recordemos, un número natural es primo, si es mayor que 1 y solo
tiene como divisores el 1 y el mismo.
Parte I: recorrido

Cuando n=10 contamos cuantos primos hay entre el 2 y el 10.


Recordemos
>>> list(range(2,n+1))
[2, 3, 4, 5, 6, 7, 8, 9, 10]
>>>

Suponiendo que tenemos una función booleana is prime(n),


hacemos un recorrido:
def count_primes (n):
count=0
for m in range (2,n+1):
if is_prime(m): count=count+1
return count
Parte II: búsqueda

Diseñemos la función is prime(n) con n=9.


Hay que buscar el primer número k, tal que 1 < k < n de la lista
[2, 3, 4, 5, 6, 7, 8] que divida a n
>>> n=9
>>> list(range(2,n))
[2, 3, 4, 5, 6, 7, 8]
>>>

Atención: Hay que quitar n=9 de la lista (n=9 siempre es divisible


por n=9). El rango es range(2,n) y no range(2,n+1).
def is_prime(n):
if n <= 1: return false
for k in range(2, n):
if n % k == 0: return False
return True
Restrinjamos (siempre que sea posible) el rango de la búsqueda.
Miremos la descomposición de range(2,n) en range(2, n//2+1) y
range(n//2+1, n)
Caso par: n=10 tenemos [2, 3, 4, 5 | 6, 7, 8, 9]
>>> n=10
>>> list(range(2, n//2+1))
[2, 3, 4, 5]
>>> list(range(n//2+1, n))
[6, 7, 8, 9]

Hace falta buscar k in [6, 7, 8, 9]? Par que n=10 sea divisible
por 6 hace falta encontrar un z ≥ 2 tal que 6*z= 10 pero como
6*2 = 12 esto es imposible. Los casos 7, 8, 9 son similares.
Caso impar: n=9 tenemos [2, 3, 4 | 5, 6, 7, 8]
>>> n=9
>>> list(range(2, n//2+1))
[2, 3, 4]
>>> list(range(n//2+1, n))
[5, 6, 7, 8]

Hace falta buscar k in [5, 6, 7, 8]? Par que n=9 sea divisible
por 5 hace falta encontrar un z ≥ 2 tal que 5*z= 9 pero como
5*2 = 10 esto es imposible. Los casos 6, 7, 8 son similares.
Los ejemplos precedentes se pueden genralizar y formalizar sin
problema.
Conclusión: Independientemente de la paridad, es suficiente
recorrer range(2, n//2+1) con lo que tenemos:

def is_prime(n):
if n <= 1: return false
for k in range(2, n//2+1):
if n % k == 0: return False
return True
Finalmente (fichero count primes(n)):

def is_prime(n):
if n <= 1: return false
for k in range(2, n//2+1):
if n % k == 0: return False
return True

def count_primes (n):


count=0
for m in range (2,n+1):
if is_prime(m): count=count+1
return count
>>>
= RESTART: C:/....count_primes.py =
>>> count_primes(10)
4
>>> count_primes(100)
25
>>> count_primes(1000)
168
>>> count_primes(10000)
1229
>>> count_primes(100000)
9592
>>>

I El tiempo de ejecución va aumentando. Cuando se ejecuta


count primes(10) el resultado aparece al instante. Esto no
es cierto cuando se jecuta count primes(100000).
I Como podemos estimar del tiempo de ejecución de un
programa?
Tiempo de cálculo
time.clock()

https://www.tutorialspoint.com/python/time_clock.htm
I Method time.clock() returns the current processor time as
a floating point number expressed in seconds on Unix and in
Windows it returns wall-clock seconds elapsed since the first
call to this function, as a floating point number.
I This is the function to use for benchmarking Python or timing
algorithms.
Example: Sleep time

File: script sleep time.py


import time

def procedure():
time.sleep(2.5)

# measure process time


t0 = time.clock()
procedure()
print(time.clock() - t0, "seconds process time")

>>>
RESTART: C:/..../script_sleep_time.py
2.500300373589652 seconds process time
>>>
Tiempo de cálculo: count primes()
Fichero: count primes process time.py

import time

def is_prime(n): ...

def count_primes(n): ...

def count_primes_process_time (n):


t0 = time.clock()
count_primes(n)
return("Seconds process time: ", time.clock() - t0)

if __name__ == "__main__":
print(count_primes_process_time(100))
print(count_primes_process_time(10000))
print(count_primes_process_time(100000))
El tiempo de ejecución (en mi laptop) es:

>>>
RESTART: C:/.../Teo4/count_primes_process_time.py
(’Seconds process time: ’, 0.0004898137513077344)
(’Seconds process time: ’, 0.33380679151512876)
(’Seconds process time: ’, 28.312309173170494)
>>>
Primeros pasos en integración mumérica
Regla del rectángulo

El intervalo entre x = a y x = b se divide en n partes iguales por


los puntos a = x0 , x1 , . . . , xn−1 , xn = b

b i=n
b−a
Z X
f (x) dx ≈ f (xi )
a n
i=0

I Notad b−a
n f (xi ) corresponde al area de un rectángulo de base
b−a
n y altura f (xi )

b−a
areai = f (xi ) = base × alturai
n
b−a b−a
I Notad que xi = x0 + i × n =a+ i× n
I En particular xn = a + n × b−a
n =b
Z b
f (x) dx ≈ area0 + area1 + · · · + arean
a
El programa consiste en un recorrido [0, . . . , n] que va calculando
las areai , 0 ≤ i ≤ n i acumula en una variable area total los valores

area total = 0
area total = area0
area total = area0 + area1
..
.
area total = area0 + area1 + · · · + arean
Caso: f (x) = x 2 (square function)

Suponganos n = 10, hay que evaluar

f (x0 ), . . . , f (xi ), . . . , f (x10 )

Recordad
>>> n= 10
>>> list(range(0,n+1))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

def integral_definida_sq(a,b,n):
x = a
base = (b - a) / n
area_total = 0
for i in range(0, n+1):
#calcular area rectangulo i-esimo
area_total = area_total + # area rectangulo i-esimo
x = x + base
return area
Fichero integral definida sq.py
def integral_definida_sq(a,b,n):
x = a
base = (b - a) / n
area_total = 0
for i in range(0, n+1):
altura = x * x
area = base * altura
area_total = area_total + area
x = x + base
return area_total
if __name__ == "__main__":
print(integral_definida_sq(0,1,1))
print(integral_definida_sq(0,1,10))
print(integral_definida_sq(0,1,100))
print(integral_definida_sq(0,1,1000))
print(integral_definida_sq(0,1,10000))
print(integral_definida_sq(0,1,100000))
print(integral_definida_sq(0,1,1000000))
El resultado es:
>>>
RESTART: C:...\integral_definida_sq.py
1.0
0.3849999999999999
0.3383500000000004
0.33383350000000095
0.3333833349999431
0.3333383333493713
0.3333338333339987
>>>

Rb R1
Recordad a x 2 dx = (b 3 − a3 )/3 entonces 0 x 2 dx = 1/3
>>> 1/3
0.3333333333333333
>>>
Recapitulemos.
I Hemos visto la función integral definida sq(a,b,n) que
era útil para integrar la funcion f (x) = x 2 .
I Si queremos canviar de funcion de f (x) = x 2 a f (x) = x 3
siempre podemos crear una cópia de
integral definida sq(a,b,n), bautizarla com
integral definida cube(a,b,n) y modificar
altura = x * x

por
altura = x*x*x

I Pregunta. No se puede pasar la función f como parámetro?


Es decir, queremos una función
integral definida(a,b,n,f) en que f sea un parámetro
Lambda abstractions

def my_square():
return lambda x: x*x

=== RESTART: C:/..../my_square.py ===


>>> f=my_square()
>>> f(2)
4
>>> f(9)
81

En el fichero integral definida.py tenemos la funcion


integral definida(a,b,n,f) que vemos en la seguidamente:
def my_square():
return lambda x: x*x

def my_cube():
return lambda x: x*x*x

def integral_definida(a,b,n,f):
x = a
base = (b - a) / n
area_total = 0
for i in range(0, n+1):
altura = f(x)
area = base * altura
area_total = area_total + area
x = x + base
return area_total

if __name__ == "__main__":
print(integral_definida(1, 100, 10000, my_square()))
print(integral_definida(1, 2, 1000, my_cube()))
Programación interactiva
Que pasa si nos equivocamos?

I Queremos leer un entero y entramos un flotante, o un string


o,...:
>>> x = int(input())
2.3 <--- dato erroneo, espera un entero y le llega un flotante
Traceback ...
...
ValueError: invalid literal for int() with base 10: ’2.3’
>>>

Hemos generado un ValueError


I Le damos al crl+c que corresponde a KeyboardInterrupt
>>> x = int(input())
<-- hacemos Ctrl +c
Traceback ...
...
KeyboardInterrupt
>>>
El Typo None

Typo None
>>> None
>>> type(None)
<class ’NoneType’>
>>> x=None
>>> type(x)
<class ’NoneType’>
>>> x=3
>>> type(x)
<class ’int’>
>>>
Ejemplo: la pertinaz lectura

I Programa (script pertinaz read int.py) que lee y


escribe un entero.
I Ante los “fallos” ValueError y KeyboardInterrupt informa y
vuelve a pedir el dato.
x= None
while x is None:
try:
x= int(input("entra el valor entero de la x: "))
except ValueError:
print("el valor no es un int, vuelvelo a intentar")
x= None
except KeyboardInterrupt:
print("le has dado a crl+c, vuelvelo a intentar")
x= None
print("el valor entero de x es: ", x)

Notemos que acaba cuando se ha leido el entero.


Ejemplo de ejecución
>>>
RESTART: C:.../scrip_pertinaz_read_int.py
entra el valor entero de la x: 2.3
el valor no es un int, vuelvelo a intentar
entra el valor entero de la x: None
el valor no es un int, vuelvelo a intentar
entra el valor entero de la x:
le has dado a crl+c, vuelvelo a intentar
entra el valor entero de la x: (le das al return)
el valor no es un int, vuelvelo a intentar
entra el valor entero de la x: (mas return)
el valor no es un int, vuelvelo a intentar
entra el valor entero de la x: 7
el valor entero de x es: 7
>>>
Dos nuevas instrucciones
Dos nuevas intrucciones

I while...
I try...
While
http://anh.cs.luc.edu/python/hands-on/3.1/handsonHtml/
whilestatements.html

A Python while loop behaves quite similarly to common English.


While your tea is too hot, add a chip of ice.

In pidgin Python you will say,


while your tea is too hot :
add a chip of ice

En castellano:
mientras tu te esta demasiado caliente :
a~
nade un poco de hielo

Esquematicamente, en nuestro ejemplo:


x= None
while x is None:
trata de leer x
print("el valor entero de x es: ", x)
try

Recordad:
try:
x= int(input("entra el valor entero de la x: "))
except ValueError:
...
except KeyboardInterrupt:
...
...
https://docs.python.org/3/tutorial/errors.html
The try statement works as follows.
I First, the try clause (the statement(s) between the try and
except keywords) is executed.
I If no exception occurs, the except clause is skipped and
execution of the try statement is finished.
I If an exception occurs during execution of the try clause, the
rest of the clause is skipped. Then if its type matches the
exception named after the except keyword, the except clause
is executed, and then execution continues after the try
statement.
%Toma paloma
Evaluación de un polinomio
Ejemplo: Polynomial evaluation (1) P96767 en
Statement. Write a program that reads a number x and a
polynomial p(x) = c0 x 0 + c1 x 1 + · · · + cn x n , and computes p(x).
I Input. Input consists of a real number x followed by the
description of the polynomial p(x): the real coefficients
c0 , c1 , . . . , cn in this order. (The first sample input/output
corresponds to the evaluation of p(x) = 3 + 4x + 5x 2 at
x = 2.)
I Output. Print p(x) with 4 digits after the decimal point.
Public test cases

Input
2
3 4 5
Output
31.0000

More details in jutge.org


Problema: Marcar el final de la secuencia de entrada

En el caso P96767 en la secuencia de entrada es:

x, c0 , c1 , c2 , . . . , cn

I El grado del polinomio, es decir la n, no se conoce antes de


ejecutar el programa.
I Por lo tanto, un diseño que utilize for ... in range(n):
... no tiene sentido porque NO conocemos n antes de acabar
de leer la secuencia.
I Hay que decirle al programa cuando acaba la secuencia con
una marca de fin.

x, c0 , c1 , c2 , . . . , cn , marca de fin
Desarrollamos dos versiones, para el Shell, que utilizan distintas
marcas de final de secuencia.
I (I) Jutge: utiliza el package jutge que hay que importar.
Utiliza como marca de fin: primero return y luego Ctrl+d.
>>> int(input())
<--- aqui Ctrl + d y aparece
Traceback ...
EOFError: EOF when reading a line <--- EOF es End of File

Un Ctrl+d inesperado genera un EOFError


I (II) Una versión que utiliza como Ctrl+c que genera un
KeyboardInterrupt
(I) Versión para el jutge.org (fichero poli jutge.py)
Se puede ejecutar en el Shell utilizando el package jutge
from jutge import read

x = read(float)
pot = 1.
coef = read(float)
res = coef
coef = read(float)
while coef is not None:
pot = pot*x
res += coef*pot
coef = read(float)
print("{0:0.4f}".format(res))

Recordemos como ejecutarlo seguidamente.


Ejecución en el Shell de la versión para el Jutge, poli jutge.py
== RESTART: C:....\poli_jutge.py ==
2 3 4 5 <---- Aqui hacemos RETURN (salto de linea)
<---- Ctrl+D, en la MISMA linea y aparece el resultado, es decir:
31.0000
>>>

Es decir, en el Shell, utilizando poli jutge.py, para acabar de


leer el input hace falta hacer Return y luego Ctrl+d.
(II) Ahora desarrollamos una versión alternativa para el Shell que
no utiliza el package jutge.
Queremos completar el siguiente esquema
x = leemos un foltante
pot = 1.
coef = leemos un foltante
res = coef
coef = leemos un foltante
while coef is not None:
pot = pot*x
res += coef*pot
coef = leemos un foltante o la marca de fin de sequencia de entrada
print("{0:0.4f}".format(res))

Cuando se lea la marca de final de sequencia (de los datos de


entrada) coeff ha de tomar el valor None. Entonces el bucle
while se acaba.
Utilizamos Ctrl + C (Interrupción de Teclado o KeyboardInterrupt)
como marca de fin de sequencia.
>>> x= <---- aqui hacemos Ctrl+c
KeyboardInterrupt
>>>

La frase: ‘‘leemos un foltante o la marca de fin de


sequencia de entrada’’ se traduce en:
def rich_float_read():
try: return float(input())
except KeyboardInterrupt: return None
Tenemos (fichero poli shell.py):
def rich_float_read():
try: return float(input())
except KeyboardInterrupt: return None

x = float(input())
pot = 1.
coef = float(input())
res = coef
coef = float(input())
while coef is not None:
pot = pot*x
res += coef*pot
coef = rich_float_read()
print("{0:0.4f}".format(res))
Un ejemplo de ejecución:
== RESTART: C:...\poli_shell.py ==
2
3
4
5
31.0000
>>>
Contando de nuevo primos
Ejemplo de while: contando primos

Mejoremos el tiempo de cálculo, better count primes.py


def better_is_prime(n):
if n <= 1: return False
k =2
while n % k != 0 and k*k <= n: k=k+1
return k*k > n

def better_count_primes(n):
count=0
for n in range (2,n+1):
if better_is_prime(n): count=count+1
return count

Vamos fijarnos en el tiempo de ejecución.


Fichero: better count primes process time.py
Miremos el tiempo de ejecución:
import time

def better_is_prime(n): ...

def better_count_primes(n):...

def better_count_primes_process_time (n):


t0 = time.clock()
better_count_primes(n)
return("Seconds process time: ", time.clock() - t0)

if __name__ == "__main__":
print(better_count_primes_process_time(100))
print(better_count_primes_process_time(10000))
print(better_count_primes_process_time(100000))
El resultado es:
RESTART: C:/.../Teo4/better_count_primes_process_time.py
(’Seconds process time: ’, 0.00027221356562224266)
(’Seconds process time: ’, 0.02408535388616865)
(’Seconds process time: ’, 0.5367300580096495)
>>>

Notemos la gran diferencia entre el tiempo de cálculo entre

tiempo(count primes process time(100000)) ≈ 28.31


tiempo(better count primes process time(100000)) ≈ 0.53

El diseño es muy importante!


Bibliografı́a
Bibliografı́a

I While statement:
http://anh.cs.luc.edu/python/hands-on/3.1/
handsonHtml/whilestatements.html
I Errors and Exceptions
https://docs.python.org/3/tutorial/errors.html

Potrebbero piacerti anche