Matemáticas y Programación. Con Python
Matemáticas y Programación. Con Python
Matemáticas
y
programación
con Python
N. Aguilera
Octubre de 2015
Bb
Contenidos
1. Preliminares 1
1.1. Organización y convenciones que usamos . . . . . . . 2
1.2. ¿Por qué Python? . . . . . . . . . . . . . . . . . . . . . 3
1.2.1. Censura, censura, censura . . . . . . . . . . . . . 5
1.3. La versión actual . . . . . . . . . . . . . . . . . . . . . . 7
1.4. Comentarios . . . . . . . . . . . . . . . . . . . . . . . . 7
1.5. Agradecimientos . . . . . . . . . . . . . . . . . . . . . . 8
Parte I : Elementos 9
2. El primer contacto 11
2.1. Funcionamiento de la computadora . . . . . . . . . . . 11
2.2. Bits y bytes . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.3. Programas y lenguajes de programación . . . . . . . . 14
2.4. Python y IDLE . . . . . . . . . . . . . . . . . . . . . . . 16
5. Variables y asignaciones 37
5.1. Asignaciones en Python . . . . . . . . . . . . . . . . . . 37
5.2. None . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.3. Comentarios . . . . . . . . . . . . . . . . . . . . . . . . 45
6. Módulos 46
6.1. Módulos propios . . . . . . . . . . . . . . . . . . . . . . 47
6.2. Ingreso interactivo . . . . . . . . . . . . . . . . . . . . . 49
6.3. Documentación y comentarios en el código . . . . . . 51
6.4. Usando import . . . . . . . . . . . . . . . . . . . . . . . 52
7. Funciones 56
7.1. Ejemplos simples . . . . . . . . . . . . . . . . . . . . . . 57
7.2. Funciones numéricas . . . . . . . . . . . . . . . . . . . 61
7.3. Python y variables lógicas . . . . . . . . . . . . . . . . . 62
7.4. Variables globales y locales . . . . . . . . . . . . . . . . 63
8. Tomando control 70
8.1. if (si) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
8.2. while (mientras) . . . . . . . . . . . . . . . . . . . . . . 75
8.3. El algoritmo de Euclides . . . . . . . . . . . . . . . . . 80
8.4. Ejercicios adicionales . . . . . . . . . . . . . . . . . . . 85
9. Sucesiones 87
9.1. Índices y secciones . . . . . . . . . . . . . . . . . . . . . 88
9.2. tuple (tupla) . . . . . . . . . . . . . . . . . . . . . . . . 89
9.3. list (lista) . . . . . . . . . . . . . . . . . . . . . . . . . 92
Contenidos Pág. iii
ifwhile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
numerico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314
recursion1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
recursion2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
santosvega.txt . . . . . . . . . . . . . . . . . . . . . . . . . . 319
sumardos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
tablaseno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320
Bibliografía 336
Preliminares
Por otra parte hay muy poca teoría, que se habrá visto o se verá en
otros cursos: lo esencial aquí son los ejercicios.
En casi todos los temas habrá algunos ejercicios rutinarios y otros
que no lo son tanto. Algunos pensarán que el material presentado es
excesivo, y habrá otros que querrán resolver más ejercicios o ejercicios
más avanzados, y para ellos en algunos capítulos se incluye una sección
de ejercicios adicionales.
1.4. Comentarios
• Los temas y formas de abordarlos están inspirados en Wirth
(1987), Kernighan y Ritchie (1991), y los tres primeros volúmenes
de Knuth (1997a; 1997b; 1998) en lo referente a programación,
y de Gentile (1991) y Engel (1993) en cuanto a basar el curso en
resolución de problemas (y varios de los temas considerados).
• Los primeros capítulos siguen ideas de las presentaciones de los
libros de Mathematica (Wolfram, 1988, y siguientes ediciones), y
el mismo tutorial de Python.
Pág. 8 Capítulo 1. Preliminares
1.5. Agradecimientos
Agradezco a los muchos docentes y alumnos que influyeron en los
cambios y la detección de errores (tipográficos o conceptuales).
Especialmente quiero agradecer a Luis Bianculli, María de los Ánge-
les Chara, Jorge D’Elía, María Fernanda Golobisky, Egle Haye, Alberto
Marchi, Martín Marques y Marcela Morvidone, con quienes he tenido
el placer de trabajar.
q
Parte I
Elementos
Bb
Capítulo 2
El primer contacto
teclado
ratón
pantalla
memoria CPU
discos
impresora
otros
computadora.
Así, imaginamos que lo que escribimos en el teclado no es procesa-
do directamente por la CPU, sino que es traducido adecuadamente y
alojado en la memoria previamente. Tenemos entonces un esquema
como el de la figura 2.2. Los elementos a la izquierda permiten que
la computadora intercambie datos con el exterior (como el teclado
o la pantalla) o los conserve para uso posterior (como el disco), y la
«verdadera acción» está entre la memoria y la CPU.
Aunque las computadoras modernas suelen tener más de una CPU,
en nuestro modelo consideraremos que hay una sola. Del mismo modo,
consideraremos que la CPU lee y escribe los datos de la memoria
secuencialmente —uno a la vez— a pesar de que las computadoras
actuales pueden ir leyendo y escribiendo simultáneamente varios datos.
Finalmente, las instrucciones que sigue la CPU forman parte de
los datos en la memoria que se procesarán. Es decir, la CPU lee ins-
trucciones en la memoria que le dicen qué otros datos (que pueden ser
más instrucciones) tomar de la memoria y qué hacer con ellos.
Resumiendo, y muy informalmente, nuestro modelo tiene las si-
guientes características:
bits
1 0 1 0 1 0 0 1
byte
éxito
editar probar terminar
error
corregir
q
Capítulo 3
Ejercicio 3.16 (cifras I). La cantidad de cifras (en base 10) para n ∈ N
puede encontrarse usando log10 (el logaritmo en base 10), ya que n tiene
k cifras si y sólo si 10k−1 ≤ n < 10k , es decir, si y sólo si k−1 ≤ log10 n < k,
o sea si y sólo si k = 1 + ⟨︀log10 n⧹︀.
a) Usar estas ideas para encontrar la cantidad de cifras (en base
10) de 123456 .
- Recordar el ejercicio 3.10 y la nota al final de éste.
b) Encontrar la cantidad de cifras en base 2 de 264 y de 1023. ¡
3.3. Comentarios
• La presentación como calculadora es típica en sistemas interac-
tivos como Matlab o Mathematica. En particular, aparece en el
tutorial de Python.
• Más adelante —en el capítulo 13— veremos cómo hacer para
que Python se comporte como una calculadora gráfica también.
q
Capítulo 4
Ejercicio 4.2. Traducir a Python las expresiones del ejercicio 4.1, ob-
servando que en Python (como en matemáticas) la expresión a < b <
c es equivalente a (a < b) and (b < c). ¡
Ejercicio 4.6. Python considera que 1 y 1.0 son de distinto tipo, pero
que sus valores son iguales. Evaluar:
a) type(1) == type(1.0) b) 1 == 1.0 ¡
a) Evaluar:
i) ’mi’ + ’mama’ ii) ’mi’ + ’ ’ + ’mama’
- Para evitar confusiones, a veces ponemos para indicar un
espacio en blanco.
b) A pesar del signo « + », la concatenación no es conmutativa
(como sí lo es la suma de números). Ver el resultado de
1 + 2 == 2 + 1
’pa’ + ’ta’ == ’ta’ + ’pa’
Ejercicio 4.23.
a) Comparar print(’\’) con print(’\\’).
b) Conjeturar y luego verificar los resultado de print(’/\’) y de
print(’//\\’).
c) Imprimir una «casita» usando print:
/\
/__\
| |
|__| ¡
4.5. Comentarios
• El ejercicio 4.23 está tomado de Litvin y Litvin (2010).
q
Capítulo 5
Variables y asignaciones
memoria memoria
123 −5.67 ’mi mama’ 123 −5.67 ’mi mama’
suma texto a
Ejercicio 5.1.
a) Poner a = 123, y comprobar que el valor de a no se muestra.
- Al hacer la asignación, a es una variable con identificador « a »
y valor « 123 ».
Python trabaja con objetos, cada uno de los cuales tiene una iden-
tidad, un tipo y un valor.
- La identidad es el lugar (dirección) de memoria que ocupa el obje-
to. No todos los lenguajes de programación permiten encontrarla,
pero sí Python. Nosotros no estudiaremos esa propiedad.
1 1 1 2
8
a a b a b
a) a = 1 b) a = 1 c) a = 1
a a = a + 1 a = a + a
a a
d) a = 3 e) a = 3 f) a = 3
b = 2 b = 2 b = 2
c = a + b c = a + b a = a + b
d = a - b d = a - b b = a - b
e = d / c e = c / d a
e e b ¡
Ejercicio 5.3.
5.1. Asignaciones en Python Pág. 41
q = a // b y r = a % b. (5.1)
- Más adelante veremos la función divmod que hace una tarea simi-
lar con una única instrucción.
Ejercicio 5.6 (cifras II). En el ejercicio 3.16 vimos una forma de deter-
minar la cantidad de cifras de un entero n (cuando escrito en base 10)
usando log10 . Como Python puede escribir el número, otra posibilidad
es usar esa representación.
5.2. None Pág. 43
a) Ejecutar:
a = 123
b = str(a)
len(b)
5.2. None
Así como en matemáticas es útil tener el número 0 o el conjunto
vacío, en programación es útil tener un objeto que «tenga valor nulo»,
o que sea «el dato vacío». En Python este valor se llama None (nada o
ninguno).
- En otros lenguajes se lo denomina Null (nulo) en vez de None.
Como el número 0 o el conjunto vacío, el concepto no es fácil de
entender. Por ejemplo, el manual de la biblioteca dice sobre None:
Es el único valor del tipo NoneType y es usado frecuen-
temente para indicar la ausencia de valor ...
lo que es bastante confuso.
None es una constante como lo son 123 o ’mi mama me mima’, en
realidad más análoga a 0 o ’’. Es una de las palabras claves que vimos
en el ejercicio 5.4 y no podemos usarla como identificador, del mismo
modo que no podemos poner 0 = 123.
Aunque no se crea, ya hemos visto None en acción: es el valor
retornado por print. Exploramos el tema en el siguiente ejercicio,
pero antes de hacerlo no estaría de más repasar el ejercicio 4.19.
Pág. 44 Capítulo 5. Variables y asignaciones
5.3. Comentarios
• Es posible averiguar las variables definidas usando globals, ob-
teniendo un diccionario. Como tantas otras cosas, no veremos
ni globals ni la estructura de diccionario.
q
Capítulo 6
Módulos
Ejercicio 6.5.
a) En la terminal poner a = 5 y verificar el valor poniendo a.
b) Poner import math y luego calcular math.log(3).
6.4. Usando import Pág. 53
pepe pi pepe
variables
math holapepe
globales
q
Capítulo 7
Funciones
def hola2():
"""Ejemplo de función sin argumento.
"""
print(’Hola, soy la compu’)
nombre = input(’¿Cuál es tu nombre? ’)
print(’Encantada de conocerte’, nombre)
def g(x):
"""Multiplicar por 4."""
return f(f(x))
y evaluar f y g en ±1, ±2 y ±3. ¡
Ejercicio 7.10.
a) Definir una función esbool que determine si el argumento
ingresado es una variable lógica o no desde las matemáticas (no
de Python), retornando verdadero o falso. Por ejemplo:
argumento ’mi mama’ 1 1.2 1.0 True
debe dar False False False False True
marco de la función
instrucciones instrucciones
globales de la función
x a
variables locales
1 3
a f g
variables globales
a = 1
f(a)
a
y observar que el valor de la variable global a no ha cambiado. ¡
Podemos pensar que los distintos elementos que intervienen en el
ejercicio 7.11 están dispuestos como se muestra en la figura 7.1:
• La función tiene instrucciones, datos y variables locales, que
ocupan un lugar propio en memoria, formando un objeto que
puede referenciarse como cualquier otro objeto.
• En este caso, f y g referencian a la misma función.
• La variable global a referencia a 2, mientras que la variable a
local a la función referencia a 3.
Pág. 66 Capítulo 7. Funciones
Ejercicio 7.12.
a) En la terminal de IDLE poner
def f(x):
"""Retorna su argumento."""
print(’el argumento ingresado fue:’, x)
return x
y explicar los resultados de los siguientes:
i) a = f(1234) ii) a = 1234 iii) x = 12
a == 1234 b = f(a) y = f(34)
x a == b x == y
b) Reiniciar la terminal (Shell → Restart Shell), de modo que ni a
ni x estén definidas, poner
def f(x):
"""Usa una variable global a."""
return x + a # a es global, no asignada en f
y explicar los resultados de los siguientes:
i) f(1) ii) a = 1 iii) a = 1
f(2) f(a)
def f(a):
...
a es local a la estructura, y puede o no haber otra variable con
el mismo identificador a fuera de f.
Ver también el ejercicio 7.11 y el apartado h).
x = 1
def f():
"""¿x es local o global?"""
print(x)
x = 2
print(x) ?
¿Por qué?
g) Reiniciar la terminal, poner
def f(x):
"""Trata de cambiar la variable global a."""
global a
a = 5 # a es... ¡global!
return x + a
y explicar los resultados de las siguientes:
i) f(1) ii) a = 2
a f(1)
a
h) Poner
def f(x):
"""Trata de cambiar el argumento con ’global’."""
global x # el argumento no puede ser global
x = 2
return x
y ver que da error: una variable no puede ser a la vez argumento
formal y global. ¡
Ejercicio 7.13. En otra tónica, podemos usar una variable local con el
mismo identificador que la función como en
def f(x):
"""Ejemplo retorcido."""
f = x + 1 # x y f son locales
return f
7.4. Variables globales y locales Pág. 69
y ejecutar el bloque
f
f(1)
f
q
Capítulo 8
Tomando control
8.1. if (si)
Supongamos que al cocinar decidimos bajar el fuego si el agua
hierve, es decir, realizar cierta acción si se cumplen ciertos requisitos.
8.1. if (si) Pág. 71
en vez de poner algo como «else if» para en otro caso si, en Python se
pone elif:
if condición: # si está Mateo
hacer algo # entonces lo visito
elif otra condición: # en otro caso si está Ana
hacer otra cosa # entonces la visito
else: # si ninguna de las anteriores entonces
hacer una tercer cosa # me quedo en casa
Observemos que estamos dando prioridades: en el ejemplo, si
Mateo está lo voy a visitar, y no importa si Ana está o no. En otras
palabras, si tanto Ana como Mateo están, visito a Mateo y no a Ana.
Veamos algunos ejemplos concretos sencillos.
return False ¡
de la ganancia.
b) Modificarla para determinar también la ganancia neta (una vez
deducidos los impuestos).
c) Modificar las funciones de modo que el impuesto y la ganancia
neta se calculen hasta el centavo (y no más).
Sugerencia: hay varias posibilidades. Una es usando round
(ver help(round)). ¡
Paso acción a b r
0 (antes de empezar) 10 3 sin valor
1 r = a 10
2 r >= b: verdadero
3 r = r - b 7
4 r >= b: verdadero
5 r = r - b 4
6 r >= b: verdadero
7 r = r - b 1
8 r >= b: falso
9 imprimir r
if a >= 0:
while r >= b:
...
else: # a < 0
while r < 0:
... ¡
Ejercicio 8.8 (cifras III). En los ejercicios 3.16 y 5.6 (y 7.9) vimos
distintas posibilidades para encontrar las cifras de un número entero
positivo. Una tercer posibilidad es ir dividiendo sucesivamente por 10
hasta llegar a 0 (que suponemos tiene 1 cifra), contando las divisiones
hechas, imitando lo hecho en el ejercicio 8.6 sólo que dividimos en vez
de restar.
Informalmente pondríamos:
c←0
repetir:
c ← c+1
n ← n ⇑⇑ 10
hasta que n = 0
- El esquema anterior está escrito en seudo código: una manera
informal para escribir algoritmos. Las operaciones se denotan
como en matemáticas (y no como Python), de modo que « = »
es la igualdad mientras que « ← » es la asignación, aunque nos
tomamos la libertad de indicar con « ⇑⇑ » la división entera y poner
comentarios como en Python.
No tiene mucho sentido mcd(0, 0), y más que nada por comodi-
dad, definimos mcd(0, 0) = 0, de modo que la relación anterior sigue
valiendo aún para z = 0.
Cuando mcd(a, b) = 1 es usual decir que los enteros a y b son
primos entre sí o coprimos (pero a o b pueden no ser primos: 8 y 9 son
coprimos pero ninguno es primo).
- Para nosotros, un número p es primo si p ∈ N, p > 1, y los únicos
divisores de p son ±1 y ±p. Los primeros primos son 2, 3, 5, 7 y 11.
Algunos autores consideran que −2, −3, etc. también son pri-
mos, pero nosotros los consideraremos siempre mayores que 1.
En el libro VII de los Elementos, Euclides enuncia una forma de
encontrar el máximo común divisor, lo que hoy llamamos algoritmo
de Euclides y que en el lenguaje moderno puede leerse como:
(1)
¡Como su nombre lo indica!
Pág. 82 Capítulo 8. Tomando control
Pablito
papá
0 1 2 3 4 5
mcm(a, b) × mcd(a, b) = a × b.
kb × nb × d p × p p = k p × n p × db × pb (8.3)
donde las incógnitas son kb y k p que deben ser enteros positivos lo más
chicos posibles, y por lo tanto las cantidades en (8.3) deben coincidir
con
mcm(nb × d p × p p , n p × db × pb ),
a partir del cual se pueden encontrar kb y k p , y luego la cantidad de
metros recorridos usando la ecuación (8.2). ¡
q
Capítulo 9
Sucesiones (secuencias)
1 2 1 2
a, b = b, a
8 8
a b a b
d) Aunque hay que escribir un poco más (porque con las tuplas
no tenemos que escribir paréntesis), también podemos hacer
asignaciones múltiples e intercambios con listas como hicimos
con tuplas (en los ejercicios 9.3 y 9.4).
i) En la terminal poner [a, b] = [1, 2] y verificar los va-
lores de a y b.
ii) Poner [a, b] = [b, a] y volver a verificar los valores de
a y b. ¡
Ejercicio 9.7 (mutables e inmutables). Una diferencia esencial entre
tuplas y listas es que podemos modificar los elementos de una lista, y
no los de una tupla.
a) Poner en la terminal a = [1, 2, 3] y verificar el valor de a.
b) Poner a[0] = 5 y volver a verificar el valor de a.
c) Poner b = a y verificar el valor de b.
d) Poner a[0] = 4 y verificar los valores de a y b.
e) Poner a = [7, 8, 9] y verificar los valores de a y b.
1 Cambios de partes de a se reflejan en b, pero una nueva
asignación a a no modifica b.
f ) Repetir los apartados anteriores cambiando a tuplas en vez de
listas, es decir, comenzando con
a = 1, 2, 3
y ver en qué casos da error. ¡
El ejercicio anterior muestra que podemos modificar los elementos
de una lista (sin asignar la lista completa), y por eso decimos que las
Pág. 94 Capítulo 9. Sucesiones
listas son mutables. En cambio, las tuplas son inmutables: sus valores no
pueden modificarse y para cambiarlos hay que crear un nuevo objeto
y hacer una nueva asignación.
- Dentro de ciertos límites, como vemos en el ejercicio 9.14.
def f(a):
"""Agregar 1 a la lista a."""
a.append(1)
Poniendo
a = [2]
b = a
f(a)
b
vemos que b se ha modificado, y ahora es [2, 1]. ¡
Ejercicio 9.13. Si queremos trabajar con una copia de la lista a, pode-
mos poner b = a[:].
a) Evaluar
a = [1, 2, 3]
b = a
c = a[:]
a[0] = 4
y comprobar los valores de a, b y c.
b) Modificar la función f(a) del ejercicio 9.12, de modo de retor-
nar una copia de a a la que se le ha agregado 1, sin modificar la
lista a. ¡
Ejercicio 9.14. En realidad la cosa no es tan sencilla como sugiere el
ejercicio 9.13. La asignación a = b[:] se llama una copia «playa» o
«plana» (shallow), y está bien para listas que no contienen otras listas.
Pero en cuanto hay otra lista como elemento las cosas se complican
como en los ejercicios 9.7 y 9.12.
a) Por ejemplo:
a = [1, [2, 3]]
b = a[:]
a[1][1] = 4
a
b
9.3. list (lista) Pág. 97
x = [0, 1]
i = 0
i, x[i] = 1, 2
y luego verificar la conjetura con Python. ¡
a) [1, 2] + [3, 4]
b) (1, 2) + (3, 4)
c) [1, 2] + (3, 4) ¡
Ejercicio 9.19 (isinstance II). Con isinstance (ejercicio 4.18) po-
demos determinar si un objeto es de cierto tipo. Si queremos deter-
minar si es de uno entre varios tipos posibles, ponemos el segundo
argumento de isinstance como tupla.
a) Si queremos determinar si x es un número (entero o real),
podríamos poner
isinstance(x, (int, float))
Probar este esquema cuando x es:
i) 1 ii) 1.2 iii) ’mi mama’ iv) False
- La última respuesta no es satisfactoria si queremos que los
valores lógicos no sean considerados como enteros (ver el
ejercicio 7.10).
b) Definir una función essecuencia que determine si su argu-
mento es o no una secuencia (cadena, tupla, lista o rango). ¡
Ejercicio 9.20 (cambiando el tipo de sucesión). Es posible cambiar
el tipo de una sucesión a otra, dentro de ciertas restricciones.
a) Determinar el tipo de a = [1, 2, 3] y encontrar:
i) str(a) ii) tuple(a) iii) list(a)
b) Si a = (1, 2, 3), ver que tuple(list(a)) es a.
c) De la misma forma, ver que cuando a = [1, 2, 3], entonces
list(tuple(a)) es a.
d) Determinar el tipo de a = ’Ana Luisa’ y encontrar:
i) str(a) ii) tuple(a) iii) list(a)
iv) ¿Es cierto que str(list(a)) es a?
- Si convertimos una cadena a lista (por ejemplo), podemos recu-
perar la cadena a partir de la lista de caracteres usando la función
9.6. Comentarios Pág. 101
9.6. Comentarios
• La mutabilidad de las listas es un arma de doble filo. Por un lado
al usarlas aumenta la rapidez de ejecución, pero por otro nos
dan más de una sorpresa desagradable, como se puede apreciar
con la aparición de numerosos símbolos en la sección 9.3.
• El concepto de mutabilidad e inmutabilidad es propio de Python,
y no existe en lenguajes como C o Pascal. Estos lenguajes tienen
el concepto de «pasar por valor o referencia», que tiene ciertas
similitudes.
• La estructura de arreglo (listas con objetos del mismo tipo con-
secutivos en memoria) es de suma importancia para cálculos
científicos de gran tamaño. Esta estructura es distinta a la de
lista y no está implementada en Python.
En este curso será suficiente emular arreglos usando listas
porque los ejemplos son de tamaño muy reducido.
El módulo no estándar numpy implementa arreglos en Python
eficientemente, pero no lo usaremos en el curso.
• Varios de los ejercicios están inspirados en los ejemplos del tuto-
rial y del manual de referencia de Python.
q
Capítulo 10
Recorriendo sucesiones
Muchas veces tendremos que repetir una misma acción para ca-
da elemento de una sucesión. Por ejemplo, para contar la cantidad
de elementos en una lista la recorreríamos sumando un 1 por cada
elemento. Algunas de estas acciones son tan comunes que Python
tiene funciones predefinidas para esto, y para contar la cantidad de
elementos usaríamos directamente len.
Sin embargo, a veces no hay funciones predefinidas o cuesta más en-
contrarlas que hacerlas directamente. Para estos casos, Python cuenta
con la sentencia for (para) que estudiamos en este capítulo.
donde iterable puede ser una sucesión (cadena, tupla, lista o rango).
- Recordar que las secuencias tienen un orden que se puede obtener
mirando los índices, como hicimos al principio del capítulo 9.
- Las similitudes con el uso de in (ejercicio 9.17) son intencionales.
- Hay otros iterables (que no son sucesiones) en los que se pue-
de usar for, como los archivos de texto que estudiamos en el
capítulo 12.
d) La construcción
for i in range(n):
...
es equivalente a
i = 0
while i < n:
...
i = i + 1
Comprobarlo cambiando el lazo for en c) por uno while. ¡
y
for i in range(len(a)): # para cada índice
...
a) x = 5 # x no está en la lista
for x in [1, 2, 3]:
print(x)
x # x no es 5
10.1. for (para) Pág. 105
b) x = 2 # x está en la lista
b = [1, x, 3]
for x in b:
print(x)
x # x no es 2 ¡
Ejercicio 10.8. Definir una nueva función sumar en base a estas ideas
y comprobar su comportamiento en distintas sucesiones como:
a) [1, 2, 3] b) ’Mateo’
c) [1, [2, 3], 4] d) [’Mateo’]
e) [[1, 2], [3, 4]] f ) [’Mateo’, ’Adolfo’]
g) [] h) [’M’, ’a’, ’t’, ’e’, ’o’]
i) ’’ j) ()
k) range(6) l) range(6, 1)
m) range(1, 6, 2) ¡
Pág. 110 Capítulo 10. Recorriendo sucesiones
donde
n n! n × (n − 1) × ⋅ ⋅ ⋅ × (n − k + 1)
( )= = (10.10)
k k! (n − k)! k!
(2)
A veces llamado teorema del binomio de Newton.
10.1. for (para) Pág. 111
s = (a1 , a1 + a2 , a1 + a2 + a3 , . . . , a1 + ⋅ ⋅ ⋅ + a n ),
k
sk = ∑ ai , k = 1, . . . , n. (10.11)
i=1
y de aquí que
Por ejemplo:
• Para la suma ponemos inicialmente s = 0 y en cada paso s =
s + x.
• Para el producto ponemos inicialmente p = 1 y en cada paso p
= p * x.
• Para ver si todos los valores lógicos de una lista son verdaderos,
ponemos inicialmente t = True y en cada paso t = x and t.
En este caso, dado que una vez que t sea falso, siempre lo
seguirá siendo, podemos poner (ver también el esquema (10.2)):
t = True
for x in a:
if not x:
t = False
break # salir del lazo
t
Consideraciones similares se aplican para ver si alguno de los
valores lógicos de una lista es verdadero.
• Finalmente, como vimos en el ejercicio 10.8 para la suma (de
números u otros objetos) y en el ejercicio 10.6 para el máximo,
Pág. 114 Capítulo 10. Recorriendo sucesiones
L Ejercicio 10.12 (el río y los caballos). Veamos algunos peligros que
pueden surgir al cambiar de caballo en la mitad del río.
a) Si cambiamos la secuencia sobre la que se itera dentro del lazo,
podemos tener un lazo infinito:
b = [1]
for x in b:
b.append(1)
*
/ \
* *
/ \ / \
* * *
/ \ / \ / \
* * * *
Ejercicio 10.14.
a) Evaluar [n**2 for n in a] cuando
i) a = [1, 2] ii) a = [2, 1] iii) a = [1, 2, 1]
viendo que la operación n**2 se realiza en cada elemento de a,
respetando el orden.
b) Cambiando listas por tuplas en el apartado anterior, ver los
resultados de:
i) [n**2 for n in (1, 2, 1)]
ii) (n**2 for n in (1, 2, 1))
10.2. Listas por comprensión Pág. 117
s = 0
for k in range(n):
s = s + 2 * k + 1
s
a) Probar los tres esquemas anteriores, viendo que dan los mismos
resultados.
b) Calcular las sumas para n = 1, 2, 3, 4. ¿Qué se observa? Conje-
turar una fórmula para n general.
Ayuda: la suma tiene que ver con n2 .
c) ¿Podrías demostrar la fórmula? ¡
10.3. Filtros
Las listas por comprensión nos permiten fabricar listas a partir de
sucesiones, pero podríamos tratar de construir una nueva lista sólo
con los elementos que satisfacen cierta condición, digamos p(x) (que
debe tener valores lógicos).
Así, queremos una variante del esquema (10.15) de la forma:
lista = []
for x in iterable:
if p(x): (10.16)
lista.append(f(x))
lista
Ejercicio 10.20. Usando filtros (en vez de un lazo for), dar una defi-
nición alternativa de la función posiciones del ejercicio 10.4.
Comparar ambas versiones cuando a = ’mi mama me mima’ (sin
tildes) y x es:
a) ’m’ b) ’i’ c) ’a’ d) ’A’ ¡
10.5. Comentarios
• for tiene distintos significados dependiendo del lenguaje de
programación y no siempre existe. En general, for puede reem-
plazarse por un lazo while adecuado, como mencionamos en
el ejercicio 10.1.d). En realidad, el esquema con while de ese
ejercicio es ligeramente más eficiente en Python que el corres-
pondiente lazo for.
• Las estructuras de listas por comprensión y de filtro no están
disponibles en lenguajes como Pascal o C. Claro que el esque-
ma (10.16) puede realizarse en estos lenguajes sin mayores pro-
blemas.
• En lenguajes que tienen elementos de programación funcional,
la estructura [f(x) for x in secuencia] muchas veces se lla-
ma map, mientras que la estructura [x for x in iterable if
p(x)] a veces se llama filter o select.
La estructura [f(x) for x in iterable if p(x)] genera-
liza map y select, y puede recuperarse a partir de ambas.
Python tiene las funciones map y filter con características
similares a las descriptas (ver help(map) o help(filter)). No
veremos estas estructuras en el curso, usando en cambio listas
por comprensión con filtros.
• Los lenguajes declarativos como SQL (usado en bases de datos)
tienen filtros muy similares a los que vimos.
q
Capítulo 11
12 h = 12 × 60 m = 720 m,
720 m + 34 m = 754 m,
754 m = 754 × 60 s = 45240 s,
4524 s + 56.78 s = 45296.78 s,
n = len(tiempo) # len(c) es n - 1
t = tiempo[0]
for i in range(1, n): (11.5)
t = t * c[i - 1] + tiempo[i]
t # tiempo pasado a segundos
Ejercicio 11.1. Tomando como base el esquema (11.5), definir una fun-
ción asegs(tiempo) para pasar el tiempo expresado en años, días,
horas, minutos y segundos a segundos
Aclaración: suponemos tiempo de la forma [a, d, h, m, s].
Comprobar los resultados cuando los argumentos son:
a) [0, 0, 12, 34, 56.78]
b) [5, 67, 8, 9, 12.34] ¡
Ejercicio 11.2. Tomando como base el esquema (11.6), definir una fun-
ción desegs(tiempo) que dado un número no negativo de segundos
lo convierte a años, días, horas, minutos y segundos respetando las
condiciones (11.4).
Comprobar que desegs es efectivamente la inversa de asegs, to-
mando como entrada los resultados del ejercicio 11.1. ¡
Ejercicio 11.3.
a) Si la inflación el primer año fue del 22 %, y el segundo año fue
del 25 %, ¿cuánto cuesta ahora un artículo que dos años atrás
costaba $ 100?
Aclaración: hablamos de un artículo genérico, seguramente
habrá artículos que aumentaron más y otros menos que la
Pág. 126 Capítulo 11. Cuatro variaciones sobre un tema
inflación indicada.
b) El kilo de pan hoy me cuesta $ 12 y (exactamente) dos años
atrás me costaba $ 7.50. ¿Qué estimación podríamos dar sobre
la inflación promedio en cada uno de estos dos años? ¡
c1 = v1 + d1 .
donde
• r = [r[0], r[1],...] son las tasas de interés (nominal, anual,
en porciento), y
• d = [d[0], d[1],...] son los depósitos mensuales.
Ejercicio 11.4. Tomando como base el esquema (11.9), definir una fun-
ción vencimiento(n, d, r) que determine el monto del certificado
al vencimiento del mes n, antes de hacer el depósito (o extracción)
correspondiente a ese mes. ¡
Pág. 128 Capítulo 11. Cuatro variaciones sobre un tema
11.3. Polinomios
Los polinomios son expresiones de la forma
n
P(x) = ∑ a k x k = a0 + a1 x + ⋅ ⋅ ⋅ + a n x n
k=0 (11.10)
= a n x + a n−1 x
n n−1
+ ⋅ ⋅ ⋅ + a0 ,
y son las funciones más sencillas que podemos considerar: para su
cálculo sólo se necesitan sumas y productos (y no tenemos que hacer
11.3. Polinomios Pág. 129
k
n = ∑ ai bi , donde a i ∈ Z y 0 ≤ a i < b. (11.12)
i=0
k
n = ∑ a i 2i ,
i=0
Pág. 132 Capítulo 11. Cuatro variaciones sobre un tema
y hacer
k−1 a ka
x n = x a0 +2a1 +2 =
2a
2 +⋅⋅⋅+2 k−1 +2 k
2 k−1 k
= x a0 ⋅ (x 2 )a1 ⋅ (x 4 )a2 ⋯(x )a k−1 ⋅ (x 2 )a k .
Observando que las potencias de x son x, x 2 , x 4 ,... , llegamos a un
esquema como:
pot = x # x, x**2, x**4, ...
prod = 1 # el producto a retornar
while True:
if n % 2 == 1: # coeficiente no nulo
prod = prod * pot
n = n // 2
if n > 0:
pot = pot * pot # x**k -> x**(2 * k)
else:
break
return prod
q
Capítulo 12
12.1. Formatos
Empezamos estudiando cómo imprimir secuencias en forma pro-
lija, especialmente cuando se trata de encolumnar la información en
tablas. Por supuesto que la presentación puede ser mejorada enorme-
mente con otro tipo de aplicaciones como los procesadores de texto
o las de diseño de página. Como además no hay mucha matemática
involucrada, lo que vemos en esta sección no forma parte esencial del
curso, si bien será útil muchas veces.
print(x)
print(formato.format(
str(p), str(q), str(p and q)))
archivo.read()
viendo que la última instrucción da error.
j) En el módulo dearchivoaconsola hacemos una síntesis de lo
que vimos: preguntamos por el nombre del archivo de texto a
imprimir en la consola, abrimos el archivo, lo imprimimos y
finalmente lo cerramos.
Probarlo ingresando los nombres santosvega.txt y dearchi-
voaconsola.py. ¡
Ejercicio 12.9. Usando split, imprimir —una por renglón— las pa-
labras con 5 o más letras en el archivo santosvega.txt. ¡
q
Bb
Parte II
Popurrí
Bb
Capítulo 13
El módulo graficar y
funciones numéricas
Ejercicio 13.1.
a) Copiar el módulo graficar en el directorio donde se guardan
nuestros módulos, y poner help(graficar) y después, por
ejemplo, help(graficar.funcion) (funcion sin tildes).
- Recordar que antes de usar help hay que colocarse en el di-
rectorio correcto y usar import.
b) Las rectas pueden darse por dos de sus puntos o bien por pun-
to y pendiente. Por ejemplo, si queremos agregar rectas re-
presentando los ejes coordenados, podríamos poner antes de
graficar.mostrar():
graficar.recta((0, 0), 0) # eje x
graficar.recta((0, 0), (0, 1)) # eje y
i) El bloque
import graficar
def f(x):
return 1/x
graficar.funcion(f, -1, 1)
graficar.mostrar()
posiblemente dará error de división por cero.
ii) Podemos cambiar la opción npuntos de gráficos de fun-
ciones, de modo de no evaluar 1⇑x para x = 0. Para un
intervalo simétrico alrededor de 0, podemos poner un nú-
mero par de puntos: cambiar el renglón que empieza con
graficar.funcion en el bloque anterior por
graficar.funcion(f, -1, 1, npuntos=100)
y ver el resultado.
iii) Una solución más satisfactoria es dividir el intervalo en dos
o más para evitar los saltos, como hacemos en el módulo
gr1sobrex en el que se puede ajustar eps.
- Ponemos explícitamente el estilo (en este caso, color azul)
para evitar que las ramas de la hipérbola se dibujen con
distintos colores.
b) La función tangente, tan, no está definida en π⇑2 + kπ, para k ∈
Z. Hacer un gráfico de esta función en el intervalo (−π⇑2, π).
- La evaluación de Python de tan π⇑2 no da error, como vimos
en el ejercicio 3.13. ¡
Ejercicio 13.7. Recordando el ejercicio 8.5:
a) Hacer un gráfico aproximado (sin tener en cuenta saltos) del
impuesto y la ganancia neta, cuando la ganancia bruta está
entre $ 0 y $ 150 000.
b) En el gráfico se podrá observar que la ganancia neta para un
ingreso de $ 100 000 es mayor que la correspondiente a ingresos
un poco mayores.
Pág. 155
q
Capítulo 14
Números aleatorios
Cualquiera que considere métodos aritméticos
para producir dígitos aleatorios está, por supuesto,
en estado de pecado.
John von Neumann (1903–1957)
random.random()
Ejercicio 14.2. Es posible usar sólo unas pocas funciones del módulo
random y emular con ellas el resto. Veamos algunos ejemplos.
0.50
0.01 x
0.00 49.75 99.50 149.25 199.00
0.50
0.01 x
0.00 49.75 99.50 149.25 199.00
• n2 = n // 2
lista2 = lista[:n2]
14.2. ¿Qué son los números aleatorios? Pág. 163
graficar.reinicializar()
graficar.puntos(pts2d(lista2))
graficar.titulo = ’La mitad de los números’
graficar.mostrar()
14.3. Aplicaciones
Ejercicio 14.4. La función dado1 (en el módulo dados) simula tirar
un dado mediante números aleatorios, retornando un número entero
entre 1 y 6 (inclusivos).
a) Hacer varias «tiradas», por ejemplo construyendo una lista.
b) Modificar la función para simular tirar una moneda con resul-
tados «cara» o «ceca». ¡
Ejercicio 14.5. La función dado2 (en el módulo dados) hace una si-
mulación para encontrar la cantidad de veces que se necesita tirar un
dado hasta que aparezca un número prefijado.
- Observar que si el argumento es un número menor que 1 o mayor
que 6, el lazo no termina nunca.
a) Ejecutar la función varias veces, para tener una idea de cuánto
tarda en aparecer un número.
b) Modificar el lazo de modo de no usar break en el lazo poniendo
veces = 1 inicialmente.
Sugerencia: cambiar también la condición en while.
c) Corriendo la función 1000 veces, calcular el promedio de los
tiros que tardó en aparecer el número predeterminado.
- Recordar que el promedio generalmente es un número deci-
mal.
14.3. Aplicaciones Pág. 165
Ejercicio 14.12. Definir una función para simular una máquina que
emite números al azar (uniformemente distribuidos) en el intervalo
(︀0, 1) uno tras otro hasta que su suma excede 1. Comprobar que al usar
la máquina muchas veces, la cantidad promedio de números emitidos
es aproximadamente e = 2.71828 . . . ¡
14.6. Comentarios
• Hay distintos algoritmos para generar números aleatorios, y los
resultados pueden ser muy distintos según el algoritmo, a dife-
Pág. 170 Capítulo 14. Números aleatorios
q
Capítulo 15
Clasificación y búsqueda
15.1. Clasificación
Ejercicio 15.1. Para clasificar una lista (modificándola) podemos usar
el método sort en Python. Si no queremos modificar la lista o tra-
bajamos con una cadena de caracteres o tupla —que no se pueden
modificar— podemos usar la función sorted que da una lista.
Verificar los resultados de los siguientes en la terminal de IDLE,
donde usamos la función sumar definida en el ejercicio 10.8:
a) import random
a = list(range(10))
random.shuffle(a)
a
b = sorted(a)
b
a # no se modificó
a.sort(reverse=True) # clasificar al revés
a
c) a = (4, 1, 2, 3, 5)
15.1. Clasificación Pág. 173
Ejercicio 15.3. Definir una función que tome como argumento una
cadena de caracteres y escriba los caracteres ingresados y la cantidad
de apariciones, ordenados decrecientemente según la cantidad de apa-
riciones, y alfabéticamente ante igualdad de apariciones.
15.1. Clasificación Pág. 175
○
0 ○
2 ○
2 ○
1 ○
0 ○
1 ○
0 ○
1 ○
0 ○
2
disposición inicial
○
0
○
0 ○
1 ○
2
○
0 ○
1 ○
2
○
0 ○
1 ○
2
0 1 2
poniendo en cajas
○
0 ○
0 ○
0 ○
0 ○
1 ○
1 ○
1 ○
2 ○
2 ○
2
disposición final
b = []
for x in a:
if x not in b:
b.append(x)
b
Definir una función con estas ideas y probarla en el ejemplo
dado.
b) En base al esquema anterior, definir una función purgar(a)
de modo que a se modifique adecuadamente sin usar una lista
auxiliar.
Aclaración: no debe usarse una lista auxiliar pero elementos
de a pueden cambiar de posición o ser eliminados.
Sugerencia: usar un índice para indicar las posiciones que
sobrevivirán.
- Sugerencia si la anterior no alcanza.
m = 0 # a[0],...,a[m - 1]
# son los elementos sin repetir
for x in a:
if x not in a[:m]: # primera aparición,
a[m] = x # incorporarlo a lo
m = m + 1 # que quedará
a[m:] = [] # considerar sólo a[0],..., a[m-1]
Ejercicio 15.6.
15.2. Listas como conjuntos Pág. 179
j = j + 1 # ambas listas
c = c + a[i:] # copiar el resto de a
c = c + b[j:] # copiar el resto de b
15.5. Comentarios
• Los interesados en el apasionante tema de clasificación y bús-
queda pueden empezar mirando el libro de Wirth (1987) y luego
profundizar con el de Knuth (1998). El libro de Sedgewick y
Wayne (2011) es de un nivel intermedio, pero está en inglés.
• Python usa funciones hash(3) para encontrar rápidamente ele-
mentos en una secuencia no ordenada, es decir, en general no
usa ni un recorrido lineal ni búsqueda binaria.
Los tres libros mencionados anteriormente incluyen descrip-
ciones de esta técnica y algoritmos asociados.
Los curiosos pueden poner help(hash) y después probar con
hash(’mama’), hash(’mami’), hash(1), hash(1.0), etc.
(3)
q
Normalmente traducidas como transformaciones de llave (o clave).
Capítulo 16
tadora) pero no con todos los números decimales. Para los últimos
usa una cantidad fija de bits (por ejemplo 64) divididos en dos grupos,
uno representando la mantisa y otro el exponente como se hace en la
notación científica al escribir 0.123 × 1045 (0.123 es la mantisa y 45 el
exponente en base 10, pero la computadora trabaja en base 2).
- Python usa una estructura especial que le permite trabajar con
enteros de cualquier tamaño, si es necesario fraccionándolos pri-
mero para que la computadora haga las operaciones y luego rear-
mándolos, procesos que toman su tiempo.
Por cuestiones prácticas, no se decidió hacer algo similar con
los decimales, que también mediante fraccionamiento y rearmado
podrían tener tanta precisión como se quisiera. Esto se puede
hacer con el módulo estándar decimal, que no veremos en el
curso.
1 2 4 8 16
float(a) # da error
876.0 ** 123 # da error
obteniendo errores de overflow (desborde o exceso), es decir,
que Python no ha podido hacer la operación pues se trata de
números decimales grandes.
- Ya hemos visto (ejercicios 3.16, 5.6 o 8.8) que a tiene 362 cifras
en base 10.
b) Haciendo un procedimiento similar a los que vimos en los
ejercicios anteriores, y esperando tener un error (como en el
apartado a)) o que no termine nunca, cruzando los dedos po-
nemos:
x = 1.0
while 2 * x > x:
x = 2 * x
x
En conclusión:
1 Python a veces da el valor inf cuando hace cálculos con
decimales, pero sólo números no demasiado grandes se deben
comparar con inf. ¡
Ejercicio 16.6. Recordando lo expresado al principio y como repaso
de lo visto, para cada caso encontrar decimales x, y y z tales que los
siguientes den verdadero:
a) x + y == x con y positivo.
b) (x + y) + z != x + (y + z).
c) x + y + z != y + z + x. ¡
16.2. Errores numéricos Pág. 195
anteriores. ¡
Llegamos a una regla de oro en cálculo numérico:
f (x) = x,
0.60 0.60
cos(x)
identidad
cos(x) inicial
identidad raíz
0.00 x 0.00 x
0.00 0.30 0.60 0.90 1.20 0.00 0.30 0.60 0.90 1.20
técnica usada por los babilonios hace miles de años para aproximar a
la raíz cuadrada, y resulta ser un caso particular de otro para funciones
mucho más generales que estudiamos en esta sección.
Recordemos que la derivada de f en x, f ′ (x), se define como
f (x + h) − f (x)
f ′ (x) = lı́m ,
h→0 h
es decir,
f (x + h) − f (x)
f ′ (x) ≈ si ⋃︀h⋃︀ es suficientemente chico. (16.3)
h
Si la derivada existe, o sea, si los cocientes incrementales se parecen
cada vez más a algo a medida que ⋃︀h⋃︀ se hace más y más chico, decimos
que la función es derivable (en x), pero es posible que los cocientes no
se parezcan a nada.
Intuitivamente, f es derivable en x cuando podemos trazar la recta
tangente al gráfico de la curva en el punto (x, f (x)). Como basta
dar la pendiente y un punto para definir una recta, para determinar
la tangente en (x, f (x)) basta dar su pendiente, y ésta es lo que se
denomina f ′ (x).
Supongamos ahora que f es una función derivable en todo punto,
y que x ∗ es un cero de f . Si x es un punto próximo a x ∗ , digamos
x ∗ = x + h, «despejando» en la relación (16.3), llegamos a
f (x + h) ≈ f (x) + f ′ (x) h,
y como h = x ∗ − x, queda
f (x)
x∗ ≈ x − .
f ′ (x)
16.4. El método de Newton Pág. 205
f (x)
g(x) = x − . (16.5)
f ′ (x)
f (x + ∆x⇑2) − f (x − ∆x⇑2)
f ′ (x) ≈ , (16.7)
∆x
Aproximando la tangente
y
f (x + h) − f (x)
− f ′ (x) = O(h),
h
mientras que el error en (16.7)
f (x + h) − f (x − h)
− f ′ (x) = O(h 2 ).
2h
- La idea de usar derivadas aproximadas se extiende tomando h
variable (acá lo tomamos fijo) dando lugar al método secante que
es muy usado en la práctica como alternativa al de Newton, y que
no veremos en el curso.
Pág. 208 Capítulo 16. Cálculo numérico elemental
-5.00 -5.00
f
y=0
f inicial
y=0 raíz
-20.00 x -20.00 x
-2.00 -0.50 1.00 2.50 4.00 -2.00 -0.50 1.00 2.50 4.00
a = a0 c2 b = b0 = b1
c0 = a 1 = a 2 c1 = b2
1.00 1.00
-3.00 x -3.00 x
-3.00 -1.75 -0.50 0.75 2.00 -3.00 -1.75 -0.50 0.75 2.00
f (x) = x (x + 1) (x + 2) (x − 4⇑3),
que tiene ceros en x = −2, −1, 0, 4⇑3, como se ilustra en la figura 16.6
(izquierda). Usando el método de la bisección para esta función to-
mando como intervalo inicial (︀−1.2, 1.5⌋︀, obtenemos una sucesión de
intervalos dados por los puntos que se muestran en la misma figura a
la derecha.
a) En caso de que haya más de una raíz en el intervalo inicial, la
solución elegida depende de los datos iniciales. Verificar este
comportamiento ejecutando biseccion sucesivamente con los
valores .8, 1 y 1.2 para mucho, pero tomando poco = −3 en todos
estos casos.
b) ¿Por qué si ponemos poco = −3 y mucho = 1 obtenemos la raíz
x = −1 en una iteración?
- En general, nunca obtendremos el valor exacto de la raíz:
recordar que para la computadora sólo existen unos pocos
racionales.
16.5. El método de la bisección Pág. 213
mucho − poco ≤ 1.
b1 = tc, c1 = b1 − p, b2 = tc1 , c2 = b2 − p, . . .
y en general
c m = b m − p = t c m−1 − p, (16.9)
donde inclusive podríamos poner c0 = c, constituyendo una variante
de las ecuaciones (11.7).
a) Considerando que c y r están fijos, ¿existe un valor de p de
modo que el saldo sea siempre el mismo, es decir, c m+1 = c m
para m = 0, 1, 2, . . . ?, ¿cuál?
Respuesta: cuando el interés mensual es la cuota: cr⇑1200.
b) Del mismo modo, encontrar una tasa crítica, rcrít (c, p) (depen-
diendo sólo de c y p), tal que la deuda se mantenga constante,
c m+1 = c m para m = 0, 1, 2, . . .
Respuesta: 1200p⇑c.
16.5. El método de la bisección Pág. 215
1000.00
0.00
-1000.00
saldo
r
40.00 80.00
comprar en cuotas.
Respuesta: 60.39 %.
j) Como dispone ahora de $ 1099, Maggie podría poner ese di-
nero en certificados a plazo fijo cada mes, extrayendo $ 79.90
mensualmente para pagar la cuota.
Si el banco ofrece una tasa de 12 % (nominal anual), ¿cuán-
tos meses podría pagar la cuota (sacando del certificado del
banco)?
Respuesta: 15 meses.
k) En el apartado anterior, ¿qué tasa debería ofrecer el banco para
que pagar en cuotas fuera equivalente a hacer certificados en
el banco?
Respuesta: la misma del apartado i).
l) Suponiendo que la tasa anual de inflación está entre 20 % y
30 %, y que los bancos ofrecen una tasa no mayor al 12 % en
certificados a plazo fijo, ¿debería Maggie hacer la compra en
efectivo o en cuotas haciendo certificados a plazo fijo en el
banco?
16.5. El método de la bisección Pág. 217
0.50
sen
lagrange
taylor grado 3
taylor grado 5
puntos Lagrange
-0.20 x
0.00 0.79 1.57 2.36 3.14
16.7. Comentarios
• Apenas hemos arañado el caparazón del cálculo numérico.
16.7. Comentarios Pág. 221
q
Capítulo 17
Números enteros
(1)
Bah, ¡a lo bestia!
17.1. Ecuaciones diofánticas y la técnica de barrido Pág. 225
x = (410 - 30 * y) // 50
...
que realiza 14 pasos.
En este caso es más eficiente el primero (pues hay menos
valores de x que de y), pero cualquiera de los dos esquemas
es aceptable.
- También podríamos poner
for x in range(1 + 410 // 50):
y = int((410 - 50 * x) / 30)
...
pero estaríamos ignorando las ventajas de usar división entera
antes que la decimal más una conversión.
- En fin, también podríamos poner
for x in range(1 + 410 // 50):
y = (410 - 50 * x) / 30
if y == int(y): # si y es entero
...
ahorrando la verificación 50 * x + 30 * y == 410.
Esta versión puede no dar resultados correctos si y no
es entero pero y == int(y) para Python debido a errores
numéricos. Por ejemplo:
>>> y = (10**20 - 1)/10**20 # decimal
>>> y
1.0
>>> int(y) == y
True
>>> (10**20 - 1)//10**20 # entero
0
17.2. Cribas
Una criba (o cedazo o tamiz) es una selección de los elementos de
en una lista que satisfacen cierto criterio que depende de los elementos
precedentes, y en cierta forma es una variante de la técnica de barrido.
Pág. 228 Capítulo 17. Números enteros
2 3 4 . . . n.
2 3 4⇑ 5 6⇑ . . .
2 3 4⇑ 5 6⇑ 7 8⇑ 9⇑ 10
⇑ 11 12
⇑ ...
⌋︂
- Como ya observamos,
⌋︂ si a × b = m y m < b < m, debe
ser 1 < a < m.
4
1 2
3
1 2
4
5 5
3
jugador j.
Inicialmente podemos poner todas las entradas de salio en −1
para indicar que nadie salió, poniendo en 0 la entrada en la posición 0.
Quedaría un esquema como el siguiente:
Definir una función con este esquema que tome como argumen-
tos m y n y que retorne la tupla (salio, flavio). En el caso n = 5
y m = 3, se debe retornar ([1, 3, 0, 4, 2], [2, 0, 4, 1, 3])
pues numeramos entre 0 y n − 1.
- En mi máquina, el nuevo esquema es unas 5 veces más rápido que
el (17.2) para n = 1234 y m = 3. ¡
Por ejemplo:
>>> factores(20)
[[2, 2], [5, 1]]
>>> factores(21)
[[3, 1], [7, 1]]
Encontrar todos los números menores que 9 699 691 que son de la
forma (17.3) y que no son primos de Euclides.
¦ No se sabe si hay infinitos primos de Euclides. ¡
A falta de fórmula, se ha intentado estudiar los primos como si
«fueran al azar», mirando «estadísticamente» cómo se reparten los
primos en la recta.
17.3. Divisibilidad y números primos Pág. 237
(cada uno con 200 700 cifras decimales), pero no se sabe si hay infinitos
pares de primos gemelos.
(2)
Julio de 2013, http://primes.utm.edu/top20/page.php?id=1#records
Pág. 238 Capítulo 17. Números enteros
Hacer una función para encontrar todos los pares de primos geme-
los menores que n, y ver que hay 35 pares de primos gemelos menores
que 1000.
- Si usamos listas con filtros, una primera posibilidad es usar un
filtro del tipo
[... p in criba(n - 2)
(†)
if p + 2 in criba(n - 2)]
Como no queremos calcular más de una vez criba(n - 2),
mejor es hacer
primos = criba(n - 2)
(‡)
[... p in primos if p + 2 in primos]
Esta última posibilidad tiene el inconveniente que recorremos
toda la lista para cada p, haciendo el algoritmo ineficiente. Más
razonable es mirar directamente a los índices:
p = criba(n - 2)
[... i in range(len(p) - 1) (∗)
if p[i + 1] == p[i] + 2]
Para n = 1000, en mi máquina el último esquema es el doble
de rápido que el esquema (‡) y unas 160 veces más rápido que el
esquema (†). Para n = 10 000 en cambio, (∗) es 8 veces más rápido
que (‡) y 1200 veces más rápido que (†). ¡
Los números primos surgen del intento de expresar un número
como producto de otros, pero podemos pensar en otras descomposi-
ciones. Por ejemplo, tomando sumas en vez de productos, como en el
siguiente ejercicio.
Ejercicio 17.15 (conjetura de Goldbach). La conjetura de Goldbach,
originada en la correspondencia entre Christian Goldbach y Euler en
1742, dice que todo número par mayor que 4 puede escribirse como la
suma de dos números primos impares (no necesariamente distintos).
a) Definir una función que dado el número n par, n ≥ 6, lo des-
componga en suma de dos primos impares, exhibiéndolos (ve-
rificando la conjetura) o en su defecto diga que no se puede
descomponer así.
17.4. Ejercicios adicionales Pág. 239
17.5. Comentarios
• Entre las ecuaciones diofánticas no lineales más interesantes es-
tán las de la forma x n + y n = z n . Cuando n = 2, las soluciones
forman una terna pitagórica y están completamente caracteri-
zadas. Para n > 2 la ecuación no tiene soluciones. Justamente
P. Fermat (1601–1665) escribió en el margen de su copia de la
«Aritmética» de Diofanto (traducida por Bachet) sobre la impo-
sibilidad de resolución cuando n > 2:
Encontré una demostración verdaderamente destaca-
ble, pero el margen del libro es demasiado pequeño
Pág. 242 Capítulo 17. Números enteros
para contenerla.
R. Taylor y A. Wiles demostraron el teorema en 1994, ¡casi 350
años después!
• Como ya mencionamos, divisibilidad y números primos han
dejado de ser temas exclusivamente teóricos.
– El problema más acuciante es encontrar un algoritmo eficien-
te para factorizar enteros: ¡quien lo encuentre puede hacer
colapsar al sistema bancario mundial!
Curiosamente, decidir si un número es primo o no es mu-
cho más sencillo: en 2002, M. Agrawal, N. Kayal y N. Saxena
probaron que existe un algoritmo muy eficiente para este pro-
blema.
En el ejercicio 17.11 vimos métodos para resolver estos pro-
blemas, que son extremadamente ineficientes para números
grandes (200 o más cifras decimales).
– La función ϕ de Euler que calculamos en el ejercicio 17.17 es
un herramienta fundamental en el algoritmo de criptografía
de R. Rivest, A. Shamir y L. Adleman (1978), uno de los más
usados.
Por supuesto, lo que hacemos acá es muy elemental, lejos
de lo que se hace en la realidad. El ejercicio 11.9 da una idea
de cosas que se pueden hacer para mejorar la eficiencia.
– Si bien se sabe que hay infinitos primos desde Euclides, re-
cién hacia fines del siglo XIX pudieron resolverse algunas
cuestiones muy generales sobre cómo se distribuyen.
El teorema de los números primos, mencionado en los ejer-
cicios 17.4 y 17.13, fue conjeturado por Gauss hacia 1792 o 1793,
cuando tenía unos 15 años, y fue demostrado en 1896 inde-
pendientemente por Jacques Hadamard (1865–1963) y Charles
Jean de la Vallée-Poussin (1866–1962).
– Johann Peter Gustav Lejeune Dirichlet (1805–1859) demostró
en 1837 que toda progresión aritmética a + bk, k = 1, 2, . . . ,
17.5. Comentarios Pág. 243
q
Capítulo 18
Grafos
3 2
4 1
5 6
tes del grafo. Por ejemplo, el grafo de la figura 18.1 no es conexo, pues
tiene un vértice aislado, y sus componentes son {1, 2, 3, 4, 6} y {5}.
Si el grafo es conexo (y simple), como se puede unir un vértice
con los n − 1 restantes, debe tener al menos n − 1 aristas. De modo que
para un grafo (simple) conexo, m tiene que estar básicamente entre n
y n2 ⇑2.(2)
Dada su estructura, es más sencillo trabajar con árboles que con gra-
fos. Un árbol es un grafo (simple) conexo y sin ciclos, pero hay muchas
formas equivalentes de describirlo, algunas de las cuales enunciamos
como teorema (que por supuesto creeremos):
Ejercicio 18.2. Definir una función simple(uv, vw) que dados los
caminos u–v y v–w como listas de vértices, retorna un camino simple
u–w. Por ejemplo, si uv es (︀1, 2, 3, 4⌋︀ y vw es (︀4, 2, 5⌋︀, un camino simple
u–w es (︀1, 2, 5⌋︀.
Aclaración 1: suponemos u, v y w distintos entre sí.
Aclaración 2: los caminos u–v y v–w pueden no ser simples.
Aclaración 3: se pide un camino simple u–w aunque puede ha-
ber más de uno, por ejemplo si uv = (︀1, 2, 3, 4, 5⌋︀ y vw = (︀5, 2, 4, 3⌋︀,
entonces (︀1, 2, 3⌋︀, (︀1, 2, 4, 3⌋︀ y (︀1, 2, 5, 4, 3⌋︀ son caminos simples 1–3. ¡
Observar que los elementos de aristas son a su vez listas en las que
el orden es importante para Python (pues (︀1, 2⌋︀ ≠ (︀2, 1⌋︀). Sin embargo,
al tratarse de aristas de un grafo para nosotros serán iguales.
- Recordando lo hecho en la el capítulo 15 al tratar listas como con-
juntos, para conservar la salud mental trataremos de ingresar la
arista {u, v} poniendo u < v, aunque en general no será necesario.
Ver el ejercicio 18.6.
La lista de vecinos tendrá índices desde 1, por lo que pondremos
None en la posición 0 a fin de evitar errores (pero la lista de aristas
tiene índices desde 0).
vecinos = [None,
[2, 3], [1, 3, 6], [1, 2, 4, 6],
[3, 6], [], [2, 3, 4]]
Ejercicio 18.4. Definir una función para que dada la lista de vecinos
imprima, para cada vértice, los vértices que son adyacentes.
Por ejemplo, si la entrada es el grafo del ejemplo 18.1, la salida
debería ser algo como
Vértice Vecinos
1 2 3
2 1 3 6
3 1 2 4 6
Pág. 250 Capítulo 18. Grafos
4 3 6
5
6 2 3 4 ¡
a r
v r a a
a v
restantes los vértices de cada arista: por lo menos debe tener un renglón
(correspondiente al número de vértices), y a partir del segundo debe
haber exactamente dos datos por renglón.
Por ejemplo, para el grafo del ejemplo 18.3, el archivo tendría (ni
más ni menos):
6
1 2
1 3
2 3
2 6
3 4
3 6
4 6
Definir una función que toma como argumento el nombre de
un archivo de texto donde se guarda la información sobre el grafo
(como indicada anteriormente). Comprobar la corrección de la función
imprimiendo la lista de aristas, una por renglón.
¿Qué pasa si el grafo no tiene aristas? ¡
y en caso afirmativo:
b) imprima el camino inverso vk , . . . , v0 , y
c) verifique si (v0 , v1 , . . . , vk ) es un ciclo.
- Comparar con el ejercicio 18.2. ¡
Algoritmo recorrido
Para los ejemplos del curso no hace diferencia porque las listas
no son demasiado grandes.
El módulo estándar collections implementa listas fifo eficien-
temente en collections.deque (ver el manual de la biblioteca).
Nosotros no lo veremos en el curso.
Volviendo al recorrido de un grafo, una primera versión es la fun-
ción recorrido (en el módulo grafos). Esta función toma como argu-
mentos la lista de vecinos (recordando que los índices empiezan desde
1) y un vértice raíz, retornando los vértices para los cuales existe un
camino desde la raíz.
Observar el uso de padre en la función recorrido. Inicialmente
el valor es None para todo vértice, y al terminar el valor es None sólo si
no se puede llegar al vértice correspondiente desde la raíz.
También podemos ver que la cola se ha implementado como pila
pues sale el último en ingresar.
3 2
1 cola
3 4
hijo - padre
árbol
4 2 1 elegido
arista sacada
n orden de agregado
5 6
Figura 18.4: Recorrido lifo del grafo del ejemplo 18.3 tomando raíz 1.
En la figura 18.4 podemos ver que las aristas elegidas por la función
recorrido forman un árbol. Usando la raíz 1 en el grafo del ejem-
plo 18.3, las aristas del árbol son {1, 2}, {1, 3}, {3, 4} y {3, 6}, como ya
mencionamos. En cambio, el árbol se reduce a la raíz cuando ésta es 5,
y no hay aristas.
3 2
2 cola
4 1
hijo - padre
árbol
4 1 elegido
3
arista sacada
n orden de agregado
5 6
Figura 18.5: Recorrido fifo del grafo del ejemplo 18.3 tomando raíz 1.
18.6. Comentarios
• Las figuras de los laberintos (figura 18.6) se hicieron con el mó-
dulo graficar. Las restantes figuras en este capítulo se hicieron
con el módulo grgrafo, así como las «películas» en la página del
libro para ilustrar los distintos algoritmos.
• La presentación de la función recorrido y del algoritmo 18.3
están basadas en la de Papadimitriou y Steiglitz (1998).
q
Capítulo 19
Recursión
recursivo, va. 1. adj. ver recursivo.
19.1. Introducción
Una forma de sumar los números a0 , a1 , a2 , . . . , es ir construyendo
las sumas parciales que llamamos acumuladas en el ejercicio 10.11:
s0 = a0 , s1 = s0 + a1 , s2 = s1 + a2 , . . . , s n = s n−1 + a n , . . . ,
1! = 1, 2! = 1! × 2, 3! = 2! × 3, . . . , n! = (n − 1)! × n, . . . ,
(1)
La palabra recursión no existe en castellano según la RAE.
Pág. 266 Capítulo 19. Recursión
"""
if n == 1: # paso base
return 1
return n * factorial(n-1)
Ejercicio 19.2. Definir una función recursiva para calcular las sumas
de Gauss,
n
s n = 1 + 2 + ⋅ ⋅ ⋅ + n = ∑ k,
k=1
n × (n + 1)
sn = ,
2
y compararlas.
- Usar división entera para la segunda función.
¦ Según se dice, Johann Carl Friederich Gauss (1777–1855) tenía 8
años cuando el maestro de la escuela le dio como tarea sumar los
números de 1 a 100 para mantenerlo ocupado (y que no molestara).
Sin embargo, hizo la suma muy rápidamente al observar que la
suma era 50 × 101.
19.3. Números de Fibonacci Pág. 267
n a = fn b = f n−1
2 1 1
3 2 1
4 3 2
5 5 3
obteniendo la sucesión 1, 1, 2, 3, 5, 8, . . . :
Ejercicio 19.6.
a) Como para el cálculo de f n con n ≥ 3 sólo necesitamos conocer
los dos valores anteriores, podemos usar un lazo for en el que
conservamos los dos últimos encontrados. Para fijar ideas, lla-
mamos a al valor de f n y b al valor de f n−1 , como está indicado
en la figura 19.1.
Llegamos a algo como
a, b = 1, 1 # los dos primeros
for i in range(n - 2): # ojo que no es n
a, b = a + b, a # i no se usa
return a
19.3. Números de Fibonacci Pág. 269
n = b2 f2 + b3 f3 + ⋅ ⋅ ⋅ + b m f m , (19.7)
def fibc(n):
...
cont = 0
sol = fibc(n)
print("Se hicieron", cont, "llamadas")
return sol
- Por supuesto que el peligro al declarar cont como global es que ha-
ya otra variable global con ese identificador. La solución adecuada
es usar variables no locales con nonlocal, que no veremos.
Tenemos que ser un poco más específicos, ya que las agujas en cada
caso son distintas. Así, para pasar de la aguja a a b debemos usar c
como intermedia, para pasar de c a b debemos usar a como intermedia,
etc.
Si genéricamente llamamos x, y y z a las agujas (que pueden ser a,
b y c en cualquier orden), podemos poner
def pasar(k, x, y, z):
"""Pasar los discos 1,..., k de x a y usando z."""
if k == 1:
print(’pasar el disco 1 de’, x, ’a’, y)
else:
pasar(k - 1, x, z, y)
print(’pasar el disco’, k, ’de’, x, ’a’, y)
pasar(k - 1, z, y, x)
(2)
¡Y que no hay cortes de luz!
Pág. 276 Capítulo 19. Recursión
Por ejemplo:
>>> hanoi(3)
Paso 0
a: [3, 2, 1]
b: []
c: []
Paso 1
a: [3, 2]
b: [1]
c: []
Paso 2
a: [3]
19.5. Los Grandes Clásicos de la Recursión Pág. 277
b: [1]
c: [2]
...
Sugerencia: trabajar con las listas como pilas.
1
/ \
1 1
/ \ / \
1 2 1
/ \ / \ / \
1 3 3 1
/ \ / \ / \ / \
1 4 6 4 1
de psicología y neuro-psicología.
Lucas es más conocido matemáticamente por su test de primali-
dad —variantes del cual son muy usadas en la actualidad— para
determinar si un número es primo o no. ¡
n n n n−1 n−1
( )=( )=1 y ( )=( )+( ) si 0 < k < n. (19.8)
0 n k k−1 k
1 4 10 20 35
1 3 6 10 15
1 2 3 4 5
1 1 1 1
19.8. yield
Hay distintas técnicas para construir los objetos uno a la vez, evi-
tando generar la «gran lista». Por ejemplo, podemos poner una función
dentro de otra envolvente, como hicimos en la función hanoi del ejer-
cicio 19.10. En esta sección estudiaremos otra técnica basada en la
sentencia yield de Python.
Una forma de calcular los primeros n números de Fibonacci (y no
sólo uno), es construyendo una lista con un lazo for:
lista = []
a, b = 0, 1
for k in range(n):
a, b = a + b, a
lista.append(a)
Si no necesitamos la lista completa, y nos basta con mirar a cada
número de Fibonacci individualmente, podemos usar la sentencia
yield, que en este contexto podría traducirse como producir, proveer
o dar lugar a:
def fibgen(n):
"""Generar n números de Fibonacci."""
a, b = 0, 1
(19.10)
for k in range(n):
a, b = a + b, a
yield a
Pág. 284 Capítulo 19. Recursión
while True:
k = k + 1
yield k
y evaluar:
it = naturales() # iterador
[next(it) for i in range(5)]
next(it)
[next(it) for i in range(5)]
it2 = naturales() # otro iterador
next(it2) # comienza con 1
next(it) # sigue por su lado
Ejercicio 19.21.
a) Definir una función cadenas(m, n) para generar todas las
listas de longitud n con los elementos de {0, ..., m − 1} (m, n ∈
N). Por ejemplo, si m = 3 y n = 2, las posibilidades son:
(︀0, 0⌋︀, (︀0, 1⌋︀, (︀0, 2⌋︀, (︀1, 0⌋︀, (︀1, 1⌋︀, (︀1, 2⌋︀, (︀2, 0⌋︀, (︀2, 1⌋︀, (︀2, 2⌋︀.
n1 + n2 + ⋅ ⋅ ⋅ + n k (n1 + n2 + ⋅ ⋅ ⋅ + n k )!
( )= .
n1 , n2 , . . . , n k n1 ! n2 ! . . . n k !
(3 + 1 + 2 + 6)!
= 55 440.
3! × 1! × 2! × 6!
Definir una función multinomial(lista) para calcular es-
tos coeficientes, donde lista es de la forma [n1, n2,...].
b) Definir una función permsrep(lista) para generar todas las
permutaciones posibles de una lista dada que puede tener re-
peticiones. Por ejemplo, si la lista es [’m’, ’i’, ’m’, ’a’],
hay 12 permutaciones posibles, como:
[’m’, ’i’, ’m’, ’a’], [’m’, ’i’, ’a’, ’m’],
[’m’, ’a’, ’i’, ’m’], [’a’, ’m’, ’i’, ’m’],
[’m’, ’m’, ’i’, ’a’], [’m’, ’m’, ’a’, ’i’], etc.
Aclaración 1: la lista que es argumento no debe modificarse.
Aclaración 2: no construir una «gran lista».
Sugerencia: imitar la función perms, finalizando el intercam-
bio en cuanto se encuentra un elemento repetido.
c) Aplicar la función permsrep (o variante) para encontrar todas
las palabras distintas que se pueden escribir permutando las
letras de ’mimama’ (sin espacios).
19.11. Comentarios Pág. 293
19.11. Comentarios
• En cursos de matemática discreta es usual estudiar las relaciones
de recurrencia lineales, homogéneas y con coeficientes constantes,
q
Parte III
Apéndices
Bb
Apéndice A
Módulos y archivos
mencionados
import random
def dado1():
"""Simular tirar un dado, obteniendo un entero entre 1 y 6."""
return random.randint(1, 6)
def dado2(k):
"""Veces que se tira un dado hasta que aparece k.
"""
veces = 0
while True: # repetir
veces = veces + 1
if random.randint(1, 6) == k: # hasta obtener k
break
Pág. 298 Apéndice A. Módulos y archivos mencionados
return veces
lectura.close() # y cerrarlo
"""
def epsilon(inic):
"""Menor potencia de 2 que sumada a inic da mayor que inic.
"""
x = 1.0
while inic + x > inic:
x = x / 2
return 2 * x # volver al valor anterior
eratostenes Pág. 299
epsmaq = epsilon(1.0)
# cálculo de epsmin
x = 1.0
while x > 0:
x, epsmin = x / 2, x
# cálculo de maxpot2
x = 1.0
while 2 * x > x:
x, maxpot2 = 2 * x, x
Esta es una primera versión que debe mejorarse según los ejercicios
en el libro.
"""
def criba(n):
"""Lista de primos <= n."""
#----------------------------------------------
# inicialización
# usamos una lista por comprensión para que todos
# los elementos tengan un mismo valor inicial
# las posiciones 0 y 1 no se usan, pero conviene ponerlas
#----------------------------------------------
# lazo principal
for i in range(2, n+1):
if esprimo[i]:
for j in range(i * i, n + 1, i):
Pág. 300 Apéndice A. Módulos y archivos mencionados
esprimo[j] = False
#----------------------------------------------
# salida
# observar el uso del filtro
return [i for i in range(2, n + 1) if esprimo[i]]
"""
for it in range(maxit):
if a > b:
a = a - b
elif b > a:
b = b - a
else:
break
print(’ iteraciones:’, it + 1)
if it == maxit - 1:
print(’*** Máximas iteraciones alcanzadas.’)
print(’ b:’, b)
return a
a, b = b, a % b
print(’ iteraciones:’, it + 1)
if it == maxit - 1:
print(’*** Máximas iteraciones alcanzadas.’)
print(’ b:’, b)
return a
# tolerancia permitida
tol = 10**(-7)
"""
for it in range(maxit):
if a > b + tol:
a = a - b
elif b > a + tol:
b = b - a
else:
break
print(’ iteraciones:’, it + 1)
if it == maxit - 1:
print(’*** Máximas iteraciones alcanzadas.’)
print(’ b:’, b)
return a
print(’ b:’, b)
return a
def f(x):
"""Suma 1 al argumento."""
return x + 1
def g(x):
"""Multiplica el argumento por 2."""
return 2 * x
def fexterna():
"""Ilustración de variables y funciones globales y locales."""
x = 2 # x es local a fexterna
print(’al comenzar fexterna, x es’, x)
finterna()
print(’al terminar fexterna, x es’, x)
- La discontinuidad está en x = 0.
- Separamos en partes el dominio: antes y después de 0 con eps > 0.
- Si eps = 0 da error de división por 0.
"""
import graficar
# titulo de la ventana
graficar.titulo = ’Gráfico de 1/x’
# cotas
eps = 0.01 # distancia a separar, poner también 0
def f(x):
return 1/x
graficar.ymax = ymax
graficar.ymin = ymin
# ejes coordenados
graficar.recta((0, 0), (1, 0), estilo={’fill’: ’black’})
graficar.recta((0, 0), (0, 1), estilo={’fill’: ’black’})
Pág. 304 Apéndice A. Módulos y archivos mencionados
graficar.mostrar()
def devecinosaaristas(vecinos):
"""Pasar de lista de vecinos a lista de aristas.
"""
ngrafo = len(vecinos) + 1 # no usamos vecinos[0]
aristas = []
for v in range(1, ngrafo):
for u in vecinos[v]:
# guardamos arista sólo si v < u para no duplicar
if v < u:
aristas.append([v, u])
return aristas
"""
vertices = range(len(vecinos)) # incluimos 0
padre = [None for v in vertices]
cola = [raiz]
padre[raiz] = raiz
while len(cola) > 0: # mientras la cola es no vacía
u = cola.pop() # sacar uno (el último) y visitarlo
for v in vecinos[u]: # examinar vecinos de u
if padre[v] == None: # si no estuvo en la cola
cola.append(v) # agregarlo a la cola
padre[v] = u # poniendo de dónde viene
return [v for v in vertices if padre[v] != None]
"""
# módulos de Python
# import math # si se usan funciones trascendentales
# módulos propios
import graficar, grnumerico
Pág. 306 Apéndice A. Módulos y archivos mencionados
# intervalo
a = -3
b = 2
# ejecución
grnumerico.biseccion(f, a, b, eps, leyendaf)
# módulos de Python
import math
# módulos propios
import graficar
xmin = -2
xmax = 5
ymin = -5
ymax = xmax
graficar.xticks = list(range(xmin, xmax, 2))
graficar.yticks = list(range(ymin + 1, ymax, 2))
graficar.ymin = ymin
graficar.ymax = ymax
graficar.aspecto = False
graficar.leyendaspos = ’NO’
graficar.mostrar()
"""
Pág. 308 Apéndice A. Módulos y archivos mencionados
import grgrafo
#----------------------------------------------
# descripción del grafo, modificar a gusto
# ejemplo en los apuntes
ngrafo = 6
aristas = [[1, 2],
[1, 3],
[2, 3],
[2, 6],
[3, 4],
[3, 6],
[4, 6]]
#----------------------------------------------
grgrafo.mostrar()
"""
# módulos de Python
# import math # si se usan funciones trascendentales
# módulos propios
import graficar, grnumerico
# intervalo
a = -2
b = 4
graficar.leyendaspos = ’SE’
# ejecución
grnumerico.newton(f, a, b, eps, maxit, leyendaf)
"""
# módulos de Python
import math # si se usan funciones trascendentes
# módulos propios
import graficar, grnumerico
# intervalo
a = 0
b = 1.2
# ejecución
grnumerico.puntofijo(f, a, b, eps, maxit, leyendaf)
# módulos de Python
import math
# módulos propios
import graficar
graficar.mostrar()
"""
print(’Hola Mundo’)
"""
print(’¿Cómo te llamás?’)
pepe = input()
print(’Hola’, pepe, ’encantada de conocerte’)
Pág. 312 Apéndice A. Módulos y archivos mencionados
def espositivo(x):
"""Decidir si el número es positivo o no.
"""
if x > 0: # si x es positivo
print(x, ’es positivo’)
else: # en otro caso
print(x, ’no es positivo’)
def piso(x):
"""Encontrar el piso de un número."""
y = int(x) # int redondea hacia cero
if y < x: # x debe ser positivo
print(’el piso de’, x, ’es’, y)
elif x < y: # x debe ser negativo
print(’el piso de’, x, ’es’, y - 1)
else: # x es entero
print(’el piso de’, x, ’es’, y)
"""
r = a # al principio hay a
while r >= b: # mientras pueda sacar b
r = r - b # lo saco
print(’El resto de dividir’, a, ’por’, b, ’es’, r)
def cifras(n):
"""Cantidad de cifras del entero n (en base 10)."""
ifwhile Pág. 313
# inicialización
n = abs(n) # por si n es negativo
c = 0 # contador de cifras
# lazo principal
while True: # repetir...
c = c + 1
n = n // 10
if n == 0: # ... hasta que n es 0
break
# salida
return c
mcd2(0, 0) = 0.
"""
# lazo principal
while b != 0:
r = a % b
a = b
b = r
# acá b == 0
# salida
return a
Pág. 314 Apéndice A. Módulos y archivos mencionados
"""
# algunas constantes
maxit = 200 # máximo número de iteraciones
tol = 10**(-7) # error permitido
# inicialización y lazo
yinic = func(xinic)
x, y = float(xinic), float(yinic)
for it in range(maxit):
if abs(y - x) < tol:
break
x, y = y, func(y)
if it + 1 == maxit:
print(’ *** Iteraciones máximas alcanzadas’)
print(’ el resultado puede no ser punto fijo’)
return y
x0 es un punto inicial.
numerico Pág. 315
No se controla si la derivada es 0.
"""
# algunas constantes
dx = 1.0e-7 # incremento para la derivada
tol = 1.0e-7 # error permitido
maxit = 20 # máximo número de iteraciones
# inicialización
y0 = func(x0)
x, y = x0, y0
# lazo principal
for it in range(maxit):
if abs(y) < tol:
break
x1 = x - y/fp(x)
y1 = func(x1)
x, y = x1, y1
if it + 1 == maxit:
print(’ *** Iteraciones máximas alcanzadas’)
print(’ el resultado puede no ser raíz’)
return x
"""
# algunas constantes
eps = 1.0e-7 # error permitido
# inicialización
fpoco = func(poco)
if abs(fpoco) < eps: # poco es raíz
return poco
fmucho = func(mucho)
if abs(fmucho) < eps: # mucho es raíz
return mucho
poco = medio
else:
mucho = medio
# salida
return medio
def factorial(n):
"""n! con recursión (n entero no negativo)."""
if n == 1:
return 1
return n * factorial(n-1)
def fibonacci(n):
"""n-ésimo úmero de Fibonacci con recursión."""
if n > 2:
return fibonacci(n-1) + fibonacci(n-2)
return 1
"""
if (a > b):
return mcd(a - b, b)
if (a < b):
return mcd(a, b - a)
return a
Pág. 318 Apéndice A. Módulos y archivos mencionados
def hanoi(n):
"""Solución recursiva a las torres de Hanoi."""
# función interna
def pasar(k, x, y, z):
"""Pasar los discos 1,..., k de x a y usando z."""
if k == 1:
print(’pasar el disco 1 de’, x, ’a’, y)
else:
pasar(k - 1, x, z, y)
print(’pasar el disco’, k, ’de’, x, ’a’, y)
pasar(k - 1, z, y, x)
# ejecución
pasar(n, ’a’, ’b’, ’c’)
def subs(n):
"""Generar los subconjuntos de {1,...,n}."""
if n == 0: # no hay elementos
yield [] # único subconjunto
else:
for s in subs(n-1):
yield s # subconjunto de {1,...,n-1}
s.append(n) # agregar n al final
yield s # con n
s.pop() # sacar n
def perms(n):
"""Permutaciones de {1,...,n}."""
if n == 0: # nada que permutar
yield []
else:
for p in perms(n-1):
p.append(n) # agregar n al final
yield p
i = n - 1
while i > 0: # llevar n hacia adelante
j = i - 1
p[i] = p[j]
p[j] = n
yield p
i = j
p.pop(0) # sacar n
print(__doc__)
a = input(’Ingresar algo: ’)
b = input(’Ingresar otra cosa: ’)
import math
aradianes = math.pi/180
# abrir el archivo
archivo = open(’tablaseno.txt’, ’w’, encoding=’utf-8’)
# escribir la tabla
for grados in range(0, 91):
archivo.write(’{0:3} {1:<15.8g}\n’.format(
grados, math.sin(grados*aradianes)))
# cerrar el archivo
archivo.close()
q
Apéndice B
Notaciones y símbolos
B.1. Lógica
⌋︂
⇒ implica o entonces. x > 0 ⇒ x = x 2 puede leerse como si x
es positivo, entonces...
⇔ si y sólo si. Significa que las condiciones a ambos lados son
equivalentes. Por ejemplo x ≥ 0 ⇔ ⋃︀x⋃︀ = x se lee x es positivo
si y sólo si...
∃ existe. ∃ k ∈ Z tal que... se lee existe k entero tal que...
⌋︂
∀ para todo. ∀ x > 0, x = x 2 se lee para todo x positivo,...
¬ La negación lógica no. Si p es una proposición lógica, ¬p se
lee no p. ¬p es verdadera ⇔ p es falsa.
∧ La conjunción lógica y. Si p y q son proposiciones lógicas, p∧q
es verdadera ⇔ tanto p como q son verdaderas.
Pág. 322 Apéndice B. Notaciones y símbolos
B.2. Conjuntos
∈ pertenece. x ∈ A significa que x es un elemento de A.
∉ no pertenece. x ∉ A significa que x no es un elemento de A.
∪ unión de conjuntos. A ∪ B = {x ∶ x ∈ A o x ∈ B}.
∩ intersección de conjuntos. A ∩ B = {x ∶ x ∈ A y x ∈ B}.
∖ diferencia de conjuntos. A ∖ B = {x ∶ x ∈ A y x ∉ B}.
⋃︀A⋃︀ cardinal del conjunto A. Es la cantidad de elementos de A. No
confundir con ⋃︀x⋃︀, el valor absoluto del número x.
∅ El conjunto vacío, ⋃︀∅⋃︀ = 0.
arcsen x,
arccos x,
arctan x Funciones trigonométricas inversas respectivamente de sen,
cos y tan.
En Python, se indican como asin, acos y atan (resp.).
signo(x) Las función signo, definida para x ∈ R por
)︀
⌉︀ si x > 0,
⌉︀
⌉︀
⌉︀
1
signo(x) = ⌋︀0 si x = 0,
⌉︀
⌉︀
⌉︀
⌉︀
]︀−1 si x < 0.
L Cosas que hay que evitar. En general quitan puntos en los exá-
menes.
Pasaje con conceptos que pueden llevar a confusión y que debe
leerse cuidadosamente.
1 «Moraleja», explicación o conclusión especialmente interesan-
te. El texto está en cursiva para distinguirlo.
¤ «Filosofía», ideas a tener en cuenta. Están a un nivel superior
a las «moralejas», que a veces son sólo aplicables a Python.
B.6. Generales
Indica un espacio en blanco en entrada o salida de datos.
i. e. es decir o esto es, del latín id est.
e. g. por ejemplo, del latín exempli gratia.
RAE Real Academia Española.
q
Bb
Parte IV
Índices
Bb
Comandos de Python que
usamos
!=, 28 \, 35
", 31 \n, 35
""" (documentación), 48 \\, 36
’, 31 *, 18
+ **, 18
concatenación
abs, 20
de cadenas, 32
and, 28
de sucesiones, 99
append, 94
números, 18
-, 18 bool, 27
/, 18 break
//, 18 en while, 79
<, 28
<=, 28 close (archivo), 139
=, 37 continue, 80
count, 106
y ==, 28
==, 28
def, 56
>, 28
divmod, 92
>=, 28 __doc__ (documentación), 49
# (comentario), 51
%, 18 elif, 72
Pág. 330 Comandos de Python que usamos
sorted, 165
split, 142
str, 27
sum, 108
True, 27
tuple, 89
type, 20
yield, 283
Índice de figuras y cuadros
Ulam, S, 162
generador, 248
sucesión, 87
suma, véase también cap. 10
acumulada, 111
promedio, 108
techo (función), 25
técnica
de barrido, 224
teorema
Dirichlet, 242
números primos, 229, 237
terminal, 15
tipo (type)
cambio, 21, 100
de datos, 26
triángulo
de Pascal, 278
tupla (tuple), 87, 89
clasificación, 165
variable, 38
global, 54, 63
local, 54, 63
vértice
aislado, 245
vínculo, véase referencia
von Neumann
arquitectura, 13
o