Está en la página 1de 22

CC1002 - Clase 6

Testing y
Caso de Estudio I
Alejandro Hevia
Sección 5
!
30 de Septiembre 2016

Suma1n = 1 + 2 + 3 + … + n
# suma1n: int -> int
# dado un numero n, determina el valor de
# la serie 1+2+3+ . . . + n
# Ejemplo: suma1n(1) retorna 1
# Ejemplo: suma1n(5) retorna 15
def suma1n(n) :
if n == 1 :
return 1
! else :
! return n + suma1n(n - 1)
!
assert suma1n(1) == 1
assert suma1n(5) == 15
Recuerdo: Afirmaciones
• assert <condición>
– La condición genera un valor de tipo boolean
• True o False
– Un assert no puede ser asignado
– Un assert valida el estado de un programa en un punto dado

– Es válido escribir :
assert True
assert 1 <= 2
assert a == b or (c < d and a > d)

assert False
Traceback (most recent call last):
File "<stdin >", line 1, in <module >
AssertionError

Problema
• El computador no tiene precisión
– No siempre hay un valor exacto
– ¿ Cómo asegurar el test se haga correctamente (y sea
útil) ?
• Hay situaciones que hay que acotar el resultado
⋙ import random
⋙ # numero al azar entre [0 - 1[
⋙ random.random( )
0.2965816702380957

• Construir una función que retorne números


enteros al azar entre 1 y 10
Acotando un resultado
# escogeAlAzar: None -> int
# Devuelve un numero al azar entre 1 y 10
def escogeAlAzar( ):
return int (10 * random.random() ) + 1
# Tests
¿ cómo sería el test dado que el número cambia ?

Acotando un resultado
# escogeAlAzar: None -> int
# Devuelve un numero al azar entre 1 y 10
def escogeAlAzar( ):
return int (10 * random.random() ) + 1
# Tests
assert escogeAlAzar( ) <= 10
assert escogeAlAzar( ) >= 1
Cuando la precisión falla
⋙ print "1.0/2.0 =", 1.0/2.0
1.0/2.0 = 0.5
!
# copiamos el valor resultante y comparamos
⋙ print (0.5 == 1.0/2.0)
True
!
⋙ print "1.0/3.0 =", 1.0/3.0
1.0/3.0 = 0.333333333333
!
# copiamos el valor resultante y comparamos
⋙ print (0.333333333333 == 1.0/3.0)
...

Cuando la precisión falla


⋙ print "1.0/2.0 =", 1.0/2.0
1.0/2.0 = 0.5
!
# copiamos el valor resultante y comparamos
⋙ print (0.5 == 1.0/2.0)
True
!
⋙ print "1.0/3.0 =", 1.0/3.0
1.0/3.0 = 0.333333333333
!
# copiamos el valor resultante y comparamos
⋙ print (0.333333333333 == 1.0/3.0)
...
False
Cuando el resultado está “cerca”
⋙ print 0.1 + 0.2
0.30000000000000004
⋙ print (0.3 == 0.1+0.2)
False Humm… Hay que buscar un parche!
!
⋙ print abs(0.3 – (0.1+0.2)) < 0.001
True

Cuando el resultado está “cerca”


⋙ print 0.1 + 0.2
0.30000000000000004
⋙ print (0.3 == 0.1+0.2)
False Humm… Hay que buscar un parche!
!
⋙ print abs(0.3 – (0.1+0.2)) < 0.001
True
La función “cerca”
# cerca: num num num -> bool
# retorna True si x es igual a y con
# precision epsilon
def cerca(x, y, epsilon) :
diff = x – y
return abs(diff) < epsilon

Series
• Corrija el test de la función masmenos1divn:
! 1 1 1 1 1 1
1− + − + − +...
! 2 3 4 5 6 n
De manera que pueda
validar, por ejemplo:
masmenos1divn(5)
ln(2)
masmenos1divn
# masmenos1divn: int -> num
# dado un numero n, determina el valor de
# la serie 1-1/2+1/3-1/4+ . . . 1/n
# Ejemplo: masmenos1divn (1) retorna 1
# Ejemplo: masmenos1divn (5) retorna 0.783333
def masmenos1divn(n) :
if n == 1 :
return 1
else :
if espar(n) :
return (-1.0/n) + masmenos1divn(n - 1)
else:
return (1.0/n) + masmenos1divn(n - 1)
!
assert masmenos1divn(1) == 1
assert masmenos1divn(2) == 0.5 ß Rehacer el test
assert masmenos1divn(5) . . .

masmenos1divn
# masmenos1divn: int -> num
# dado un numero n, determina el valor de
# la serie 1-1/2+1/3-1/4+ . . . 1/n
# Ejemplo: masmenos1divn (1) retorna 1
# Ejemplo: masmenos1divn (5) retorna 0.783333
def masmenos1divn(n) :
if n == 1 :
return 1
else :
if esPar(n) :
return (-1.0/n) + masmenos1divn(n - 1)
else:
return (1.0/n) + masmenos1divn(n - 1)
!
assert cerca(masmenos1divn(1), 1, 0.001)
assert cerca(masmenos1divn(2), 0.5, 0.001)
assert cerca(masmenos1divn(5), 0.783333, 0.001)
Testeando con una función

15

Suma1n = 1 + 2 + 3 + … + n
# suma1n: int -> int
# dado un numero n, determina el valor de
# la serie 1+2+3+ . . . + n
# Ejemplo: suma1n(1) retorna 1
# Ejemplo: suma1n(5) retorna 15
def suma1n(n) :
if n == 1 :
return 1
! else :
! return n + suma1n(n - 1)
!
assert suma1n(1) == 1 ¿Es suficiente como test?
assert suma1n(5) == 15 ¿Puedo hacer uno mejor?
n=9
assert suma1n(n) == n*(n+1)/2
Suma1n = 1 + 2 + 3 + … + n
# suma1n: int -> int
# dado un numero n, determina el valor de
# la serie 1+2+3+ . . . + n
# Ejemplo: suma1n(1) retorna 1
# Ejemplo: suma1n(5) retorna 15
def suma1n(n) :
if n == 1 :
return 1
! else : # suma1nAlternativa: int int -> num
# funcion auxiliar para testear suma1n
! return n + suma1n(n - 1) # calcula lo mismo usando formula
! # clasica n*(n+1)/2
assert suma1n(1) == 1 def suma1nAlternativa(n) :
assert suma1n(5) == 15 return n*(n+1)/2
n=9
assert suma1n(n) == suma1nAlternativa(n)

Suma1n = 1 + 2 + 3 + … + n
# suma1n: int -> int
# dado un numero n, determina el valor de
# la serie 1+2+3+ . . . + n
# Ejemplo: suma1n(1) retorna 1
# Ejemplo: suma1n(5) retorna 15
def suma1n(n) :
if n == 1 :
return 1
! else :
! return n + suma1n(n - 1)
!
assert suma1n(1) == 1 # testSuma1n: None -> bool
assert suma1n(5) == 15 # funcion auxiliar para testear suma1n
def testSuma1n(n) :
assert testSuma1n(9) return suma1n(n) == suma1nAlternativa(n)
assert testSuma1n(11)
Caso de Estudio I

Calculando Raíz Cuadrada y Pi

19

Raíz Cuadrada
• Cómo calcular una raíz cuadrada
– Sin la calculadora ☹

• Se puede hacer “a mano”


– “Raíz de 18?… 16=4*4, 25=5.5… 4.algo? 4.5*4.5= 20.25…
4.3*4,3= 18.49, …, 4.24*4.24=17.977, es 4.24 aprox.”
– Pero toma tiempo ☹
– Usemos el computador ☺

• Método creado por Heron


– Matemático Griego, siglo I
Raíz Cuadrada: Heron
a
¿Cómo calcular la raíz cuadrada de N?
1. Supongamos tenemos a, b, N = a * b N = area b
2. Se calcula una estimación:
p = (a + b) / 2
3. Se calcula el otro lado del rectángulo
r = (a*b) / p p=(a+b)/2
4. Si abs(p – r) < epsilon la raíz es r ó p
r=
5. En caso contrario N (a*b)/p
a=p
b=r
Se repite al paso 1

Raíz Cuadrada: Heron a* b


a = 12 Un lado se reemplaza por el promedio (p)
El otro lado se reemplaza por (a*b)/p

b=3

a * b = 12 * 3 = 36
a = (12 + 3) / 2 = 15 / 2 = 7.5
b = 36 / 7.5 = 4.8
a * b = 7.5 * 4.8 = 36
Raíz Cuadrada: Heron a* b
a = 12 Un lado se reemplaza por el promedio (p)
El otro lado se reemplaza por (a*b)/p

b=3

a * b = 12 * 3 = 36
a = (12 + 3) / 2 = 15 / 2 = 7.5
b = 36 / 7.5 = 4.8
a * b = 7.5 * 4.8 = 36
a = 7.5

b = 4.8

Raíz Cuadrada: Heron a* b


a = 7.5 Un lado se reemplaza por el promedio (p)
El otro lado se reemplaza por (a*b)/p

b = 4.8

a = (7.5+4.8) / 2 = 12.3 / 2 = 6.15


b = 36 / 6.15 = 5.853658…
Raíz Cuadrada: Heron a* b
a = 7.5 Un lado se reemplaza por el promedio (p)
El otro lado se reemplaza por (a*b)/p

b = 4.8

a = (7.5+4.8) / 2 = 12.3 / 2 = 6.15


b = 36 / 6.15 = 5.853658…
a = 6.15

b = 5.853658…
Esto se repite hasta que a y b
estén bastante “cerca” … a=b=6

raizCuadrada(n, epsilon)
# raizCuadrada: num num -> num
# retorna la raiz cuadrada de x con
# una precision epsilon
def raizCuadrada(x, epsilon) :
a=x
b=1
# notar que (a * b) == (x * 1) == x
return heron(a, b, epsilon)
heron(a, b, epsilon)
# heron: num num num -> num
# funcion auxiliar, retorna la raiz cuadrada de a*b con una
# precision epsilon usando aproximacion b (metodo Heron)
def heron(a, b, epsilon) :
p = (a + b) / 2.0 # OJO debe ser real!
r = (a * b) / p # x == (a*b)
!
if cerca(p, r, epsilon) :
return r # tambien puede ser p
else :
return heron(p, r, epsilon)

raizCuadrada(n, epsilon)
# heron: num num num -> num
# funcion auxiliar, retorna raiz cuadrada de a con
# raizCuadrada: num num -> num # preci. epsilon usando aprox. b (metodo Heron)
# retorna la raiz cuadrada de x con def heron(a, b, epsilon) :
p = (a + b) / 2.0 # OJO debe ser real!
# una precision epsilon !
r = (a * b) / p # x == (a*b)

def raizCuadrada(x, epsilon) : if cerca(p, r, epsilon) :


return r # tambien puede ser p
a=x else :
return heron(p, r, epsilon)
b=1
return heron(a, b, epsilon)
# Test
import math
assert cerca(raizCuadrada(2, 0.1), math.sqrt(2), 0.1)
assert cerca(raizCuadrada(4, 0.01), math.sqrt(4), 0.01)
⋙ import math
⋙ print raizCuadrada(2, 0.01), “sqrt=”, math.sqrt(2)
1.41666666667 sqrt= 1.41421356237
!
⋙print raizCuadrada(2, 0.0001), “sqrt=”, math.sqrt(2)
1.41421568627 sqrt= 1.41421356237
...
⋙print raizCuadrada(25, 0.01), “sqrt=”, math.sqrt(25)
5.00001295305 sqrt= 5.00
...
⋙print raizCuadrada(0.1, 0.01), “sqrt=”, math.sqrt(0.1)
0.320097780954 sqrt= 0.316227766017

Buscando un valor terminal


• El numero π es infinito

• Serie de Leibniz para el cálculo de π


π 1 1 1 1 1 1
= 1− + − + − +!+ (−1)k+1 *
4 3 5 7 9 11 (2 * k) −1

• ¿Hasta cuándo calcular para obtener π ?


1. Hasta el término k
2. Hasta un error ε
π calculado para k términos
• Paso 1: crear una función de calcule el valor de
la serie en k:
! 1
leibniz_kesimo = (−1)k+1 *
! (2 * k) −1
!
• Paso 2: calcular la serie para los k términos

leibniz_kesimo(k)
# leibniz_kesimo: num -> num
# dado un valor de k, calcula el termino k
# de la serie de leibniz.
def leibniz_kesimo(k) :
if esPar(k) :
signo = -1
else :
signo = 1
# se calcula el valor k-esimo
# OJO 2.0 o 1.0 debe ser real!
valor = signo * (1 / ((2.0 * k) - 1))
return valor
π 1 1 1 1 1 1
= 1− + − + − +!+ (−1)k+1 *
4 3 5 7 9 11 (2 * k) −1
π calculado para k términos
• Paso 1: crear una función de calcule el valor de
la serie en k:
! 1
leibniz_kesimo = (−1)k+1 *
! (2 * k) −1
!
• Paso 2: calcular la serie para los k términos

pi_Leibniz(k)
# pi_Leibniz(n): int -> num
# calcula el numero pi hasta la iteracion k
def pi_Leibniz(k) : # leibniz_kesimo: num -> num
# dado un valor de k, calcula el
if (k == 1) :
# termino k de la serie de leibniz.
return 1 def leibniz_kesimo(k) :
else : if esPar(k) :
signo = -1
# se calcula el valor k else :
valorK = leibniz_kesimo(k) signo = 1
# se calcula el valor k-esimo
# se suma el valor a la serie y # OJO 2.0 o 1.0 debe ser real!
valor = signo * (1 / ((2.0 * k) - 1))
# se calcula los terminos faltantes return valor
return pi_Leibniz(k - 1) + valorK

π 1 1 1 1 1 1
= 1− + − + − +!+ (−1)k+1 *
4 3 5 7 9 11 (2 * k) −1
Pi(K)
# Pi: int -> num
# retorna el número Pi luego de
# haber calculado la serie de Leibniz hasta k
def Pi(k) :
return 4 * pi_Leibniz(k)

Resultados de Pi(k)

⋙ print Pi(1)
4
⋙ print Pi(2)
2.66666666667
⋙ print Pi(100)
3.13159290356
⋙ print Pi(999)
3.14259365434
π 1 1 1 1 1 1
= 1− + − + − +!+ (−1)k+1 *
4 3 5 7 9 11 (2 * k) −1
Buscando un valor terminal
• El numero π es infinito
!
!
• Serie de Leibniz para el cálculo de π
! π = 1− 1 + 1 − 1 + 1 − 1 +!+ (−1)k+1 * 1
! 4 3 5 7 9 11 (2 * k) −1
• Hasta cuándo calcular para obtener π ?
1. Hasta el termino k
2. Hasta un error ε

Buscando un valor terminal


• Propuesta se solución:
– Calcular πk
– Calcular πk+1
– Si (πk – πk+1) < ε entonces se retorna πk+1
– En caso contrario se incorpora otro término

π 1 1 1 1 1 1
= 1− + − + − +!+ (−1)k+1 *
4 3 5 7 9 11 (2 * k) −1
Pi(epsilon)
# Pi: num -> num
# retorna el número Pi con Calculará serie partiendo
de k=1, usando πk=1 y
# una precision epsilon error epsilon
def Pi(epsilon) :
return 4 * leibniz(1, 1, epsilon)

π 1 1 1 1 1 1
= 1− + − + − +!+ (−1)k+1 *
4 3 5 7 9 11 (2 * k) −1

leibniz(k, pik, epsilon)


# leibniz: int num num -> num
# dado un valor de Pi en la iteracion k de la serie
# de leibniz, calcula el termino k+1
# de la serie de leibniz. Si (pik – pik+1) < epsilon # leibniz_kesimo: num -> num
# retorna pik+1 # dado un valor de k, calcula el
# termino k de la serie de leibniz.
def leibniz(k, pik, epsilon) : def leibniz_kesimo(k) :
! # se calcula el valor de k+1 if esPar(k) :
signo = -1
pikmas1 = pik + leibniz_kesimo(k+1) else :
signo = 1
if cerca(pik, pikmas1, epsilon) : # se calcula el valor k-esimo
# OJO 2.0 o 1.0 debe ser real!
return pikmas1 valor = signo * (1 / ((2.0 * k) - 1))
else : return valor

return leibniz(k+1, pikmas1, epsilon)

π 1 1 1 1 1 1
= 1− + − + − +!+ (−1)k+1 *
4 3 5 7 9 11 (2 * k) −1
Resultados de Pi(epsilon)

⋙ print Pi(0.5)
2.66666666667
⋙ print Pi(0.1)
2.97604617605
⋙ print Pi(0.01)
3.16119861299
⋙ print Pi(0.001)
3.14358865959
π 1 1 1 1 1 1
= 1− + − + − +!+ (−1)k+1 *
4 3 5 7 9 11 (2 * k) −1

Resultados de Pi(epsilon)
Notar que si epsilon es,
⋙ print Pi(0.5) por ejemplo, 0.1,
2.66666666667 |Pi(0.1) – π| > 0.1
⋙ print Pi(0.1) !
¿A qué se debe?
2.97604617605
⋙ print Pi(0.01)
3.16119861299
⋙ print Pi(0.001)
3.14358865959
π 1 1 1 1 1 1
= 1− + − + − +!+ (−1)k+1 *
4 3 5 7 9 11 (2 * k) −1
Resultados de Pi(epsilon)
Notar que si epsilon es,
⋙ print Pi(0.5) por ejemplo, 0.1,
2.66666666667 |Pi(0.1) – π| > 0.1
⋙ print Pi(0.1) !
¿A qué se debe?
2.97604617605
⋙ print Pi(0.01)
epsilon es la distancia entre
3.16119861299 leibnizk y leibnizk+1 y no la
⋙ print Pi(0.001) distancia a π
3.14358865959
π 1 1 1 1 1 1
= 1− + − + − +!+ (−1)k+1 *
4 3 5 7 9 11 (2 * k) −1

También podría gustarte