Python
Python
Python
Matemáticas
y
programación
con Python
para ingenierías
N. Aguilera
11 de julio de 2019
Bb
Contenidos
1. Preliminares 1
1.1. ¿Qué es esto? . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2. Organización y convenciones que usamos . . . . . . . 2
1.3. ¿Por qué Python? . . . . . . . . . . . . . . . . . . . . . 3
1.4. Censura, censura, censura . . . . . . . . . . . . . . . . 5
1.5. De la paciencia, o cómo estudiar . . . . . . . . . . . . . 6
1.6. Comentarios . . . . . . . . . . . . . . . . . . . . . . . . 7
1.7. 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 39
5.1. Asignaciones en Python . . . . . . . . . . . . . . . . . . 39
5.2. None . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
5.3. Comentarios . . . . . . . . . . . . . . . . . . . . . . . . 47
6. Módulos 48
6.1. Módulos propios . . . . . . . . . . . . . . . . . . . . . . 49
6.2. Ingreso interactivo . . . . . . . . . . . . . . . . . . . . . 51
6.3. Documentación y comentarios en el código . . . . . . 53
6.4. Usando import . . . . . . . . . . . . . . . . . . . . . . . 54
7. Funciones 58
7.1. Ejemplos simples . . . . . . . . . . . . . . . . . . . . . . 59
7.2. Funciones numéricas . . . . . . . . . . . . . . . . . . . 63
7.3. Variables globales y locales . . . . . . . . . . . . . . . . 64
7.4. Comentarios . . . . . . . . . . . . . . . . . . . . . . . . 71
8. Tomando control 72
8.1. if (si) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
8.2. while (mientras) . . . . . . . . . . . . . . . . . . . . . . 77
8.3. El algoritmo de Euclides . . . . . . . . . . . . . . . . . 83
9. Sucesiones 88
9.1. Índices y secciones . . . . . . . . . . . . . . . . . . . . . 89
9.2. tuple (tupla) . . . . . . . . . . . . . . . . . . . . . . . . 90
9.3. list (lista) . . . . . . . . . . . . . . . . . . . . . . . . . 93
9.4. range (rango) . . . . . . . . . . . . . . . . . . . . . . . 100
Contenidos Pág. iii
Bibliografía 300
Preliminares
Esto hace que, a diferencia del curso con Pascal, dediquemos una
buena parte del tiempo a estudiar el lenguaje, tratando de entender su
idiosincrasia.
Aunque será inevitable mencionar algunas particularidades de
Python, es conveniente tener siempre presente que:
1.6. Comentarios
• A medida que pasan los años, los contenidos del «libro» se van
modificando. Hay temas que cambian, otros se eliminan, otros
se agregan, y otros... ¡reaparecen!
Esta versión es mayormente un reordenamiento de versiones
anteriores, se corrigieron algunos errores tipográficos, y segura-
mente aparecieron otros.
• Los temas y formas de abordarlos están inspirados en Wirth
(1987) y Kernighan y Ritchie (1991) en lo referido a programación,
y en 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 los libros de Mathematica
(Wolfram, 1988, y siguientes ediciones), y el tutorial de Python.
• Hemos tratado de incluir referencias bibliográficas sobre temas
y problemas particulares, pero muchos pertenecen al «folklore»
(3)
O sea, los exámenes.
Pág. 8 Capítulo 1. Preliminares
1.7. Agradecimientos
A lo largo de tantos años de existencia, son muchos los muchos
docentes y alumnos que influyeron en los cambios y detectaron erro-
res (tipográficos o conceptuales) de estas notas. Especialmente quiero
agradecer a Luis Bianculli, María de los Ángeles Chara, Jorge D’Elía,
María Fernanda Golobisky, Conrado Gómez, Egle Haye, Alberto Mar-
chi, Martín Marques y Marcela Morvidone, con quienes he tenido el
placer de trabajar.
(4)
(5)
(6)
q
http://www-history.mcs.st-and.ac.uk/
http://www.wikipedia.org/
http://cm.baylor.edu/welcome.icpc
Parte I
Elementos
Bb
Capítulo 2
El primer contacto
teclado
ratón
pantalla
memoria CPU
discos
impresora
otros
bits
1 0 1 0 1 0 0 1
byte
en la memoria,
• la CPU realiza las operaciones secuencialmente.
- El modelo, con pocos cambios, se debe a John von Neumann
(1903–1957).
éxito
editar probar terminar
error
corregir
del lenguaje— que luego serán traducidas a algo que la CPU pueda
entender, es decir, las famosas ristras de ceros y unos. Las sentencias
que escribimos (en lenguaje humano) forman el programa fuente o
código fuente o simplemente código, para distinguirlo del programa
ejecutable o aplicación que es el que tiene los ceros y unos que entiende
la computadora.
Cuando trabajamos con el lenguaje Python, el programa llamado
(casualmente) python hace la traducción de humano a binario e indica
a la CPU que realice la tarea.
En la mayoría de los casos —aún para gente experimentada—
habrá problemas, por ejemplo por errores de sintaxis (no seguimos las
reglas del lenguaje), o porque al ejecutar el programa los resultados no
son los esperados. Esto da lugar a un ciclo de trabajo esquematizado
en la figura 2.4: editamos, es decir, escribimos las instrucciones del
programa, probamos si funciona, y si hay errores —como será la
mayoría de las veces— habrá que corregirlos y volver a escribir las
instrucciones.
A medida que los programas se van haciendo más largos (ponemos
mayor cantidad de instrucciones) es conveniente tener un mecanismo
que nos ahorre volver a escribir una y otra vez lo mismo. En todos
los lenguajes de programación está la posibilidad de que el programa
traductor (en nuestro caso Python) tome las instrucciones de un archi-
vo que sea fácil de modificar. Generalmente, este archivo se escribe y
modifica con la ayuda de un programa que se llama editor de textos.
Para los que están haciendo las primeras incursiones en progra-
Pág. 16 Capítulo 2. El primer contacto
>>> 2 + 2
y ahora apretamos la tecla «retorno» (o «intro» o «return» o «enter» o
con un dibujo parecido a , dependiendo del teclado) para obtener
4
>>>
quedando IDLE a la espera de que ingresemos nuevos comandos. En
un rapto de audacia, ingresamos 2 + 3 para ver qué sucede, y seguimos
de este modo ingresando operaciones como en una calculadora.
Si queremos repetir o modificar alguna entrada anterior, podemos
movernos con alt-p (previous o previo) o alt-n (next o siguiente)
donde «alt» indica la tecla modificadora alterna marcada con «alt»,
o bien —dependiendo del sistema y la instalación— con ctrl-p y
ctrl-n, donde «ctrl» es la tecla modificadora control. En todo caso se
pueden mirar las preferencias en el menú de IDLE para ver qué otros
atajos hay o modificarlos a gusto.
Con ctrl-d (fin de datos) cerramos la ventana de la terminal, o
bien podemos salir de IDLE usando el menú correspondiente.
q
Capítulo 3
antes de la evaluación.
E 3.6. Conjeturar el valor y luego verificarlo con Python:
a) 2 - 3 + 4 - 5 b) 3 / 4 * 5 / 6 ¡
E 3.7. La expresión de Python -3**-4, ¿es equivalente en matemáticas
a (−3)−4 o a −3−4 ?
¿Cuáles son las precedencias de Python en este caso? ¡
En el curso trataremos de evitar construcciones como la de los
ejercicios anteriores, agregando paréntesis aunque sean redundantes:
MVQSYNQF.(1)
⌋︂ ⌋︂
E 3.8. Desde las matemáticas, ¿es 3 entero?, ¿y 4?
¿De qué tipo son 3**(1/2) y 4**(1/2)? ¡
E 3.9. En un triángulo rectángulo, un cateto mide 12 y el otro 5. Cal-
cular cuánto mide la hipotenusa usando Python. ¡
E 3.10. Compré 4 botellas a $ 100 cada una y 7 a $ 60 cada una.
Resolver con lápiz y papel (o mentalmente) y luego hacer las cuen-
tas con Python:
a) ¿Cuántas botellas compré?
b) ¿Cuánto gasté en total?
c) En promedio, ¿cuál fue el costo por botella? ¡
E 3.11 (Inflación). 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?
(1)
Más vale que sobre y no que falte.
3.1. Operaciones con números Pág. 21
a) Calcular math.e.
b) Usando help, averiguar qué hace la función math.log y calcu-
lar math.log(math.e). ¿Es razonable el valor obtenido?
c) Para encontrar el logaritmo en base 10 de un número, podemos
usar math.log(número, 10) pero también podemos poner di-
rectamente math.log10(número): ver qué hace math.log10
usando help, y calcular log10 123 de las dos formas. ¿Hay dife-
rencias?, ¿debería haberlas?
d) Calcular log10 5 aproximadamente, y verificar el resultado cal-
culando 10log10 5 (¿cuánto debería ser?).
3.2. El módulo math Pág. 27
E 3.23 (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⧹︀.
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.
• Es posible hacer que Python se comporte como una calculadora
gráfica haciendo, por ejemplo, gráficos en 2 y 3 dimensiones. En
los apuntes no trabajaremos directamente con estas posibilida-
des.
q
Capítulo 4
tenemos los dos que hemos visto, int o entero (como 123) y float o
decimal (como 45.67) y ahora veremos dos más:
• bool o lógico, siendo los únicos valores posibles True (verdade-
ro) y False (falso).
- Poniendo help(bool) vemos que, a diferencia de otros len-
guajes, para Python bool es una subclase de int, lo que tiene
sus ventajas pero trae aparejada muchas inconsistencias.
- bool es una abreviación de Boolean, que podemos traducir
como booleanos y pronunciar buleanos. Los valores lógi-
cos reciben también ese nombre en honor a G. Boole (1815–
1864).
• str o cadena de caracteres, como 'Mateo Adolfo'.
- str es una abreviación del inglés string, literalmente cuerda,
que traducimos como cadena, en este caso de caracteres
(character string).
E 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 ¡
E 4.12. Ver que para Python 'Ana Luisa' y "Ana Luisa" son lo mis-
mo usando ==. ¡
E 4.13. Las comillas simples ' no se pueden intercambiar con las dobles
", pero se pueden combinar. Ver los resultados de:
a) 'mi" b) 'mi" mama" c) "mi' mama" d) 'mi" "mama' ¡
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
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.
Podemos pensar que la asignación a = algo consiste en:
• Evaluar el miembro derecho algo, realizando las operaciones
indicadas si las hubiere. Si algo involucra variables, las operacio-
nes se hacen con los valores correspondientes. El valor obtenido
se guarda en algún lugar de la memoria.
Recordar que si algo es sólo el identificador de una variable
(sin otras operaciones), el valor es el del objeto al cual referencia
la variable.
• En a se guarda (esencialmente) la dirección en la memoria del
valor obtenido.
Por ejemplo:
a = 1 → a es una referencia a 1 (figura 5.2, izquierda)
b = a → b también es una referencia a 1 (figura 5.2, centro)
a = 2 → ahora a es una referencia a 2 (figura 5.2, derecha)
a → el valor de a es 2
b → b sigue siendo una referencia a 1
1 1 1 2
8
a a b a b
d) a = 3 e) a = 3
b = 2 b = 2
c = a + b a = a + b
d = a - b b = a - b
e = d / c a
e b ¡
Los identificadores (los nombres de las variables) pueden tener
cualquier longitud (cantidad de caracteres), pero no se pueden usar
todos los caracteres. Por ejemplo, no pueden tener espacios, ni signos
de puntuación como « , » o « . », ni signos como « + » o « - » para no
confundir con operaciones, y no deben empezar con un número. No
veremos las reglas precisas, que son un tanto complicadas y están en el
manual de referencia.
Aunque se permiten, es conveniente que los identificadores no
empiecen con guión bajo « _ », dejando esta posibilidad para identifi-
cadores de Python. También es conveniente no poner tildes, como en
« á », « ñ » o « ü ».
Finalmente, observamos que identificadores con mayúsculas y
minúsculas son diferentes (recordar el ejercicio 3.12).
q = a // b y r = a % b. (5.1)
- Más adelante veremos la función divmod que hace una tarea si-
milar con una única instrucción.
Para ver el comportamiento de Python en estas operaciones, eva-
luamos q y r para distintos valores de a y b: positivos, negativos, enteros
o decimales.
a) ¿Qué pasa si b es 0?, ¿y si a y b son ambos 0?
b) ¿Qué hace Python cuando b es entero pero negativo? (o sea:
¿qué valores de q y r se obtienen?).
c) Si b es positivo pero decimal, al realizar las operaciones en (5.1),
Python pone q decimal y r decimal, pero esencialmente q es
entero pues q == int(q).
Verificar esto tomando distintos valores decimales de a y b
(b positivo).
d) Si a es decimal y b = 1, determinar si el valor de q coincide
con int(a) o round(a) o ninguno de los dos.
e) Dar ejemplos «de la vida real» donde tenga sentido considerar:
i) a decimal y b entero positivo,
ii) b decimal y positivo.
Ayuda: hay varias posibilidades, por ejemplo pensar en horas,
en radianes y b = 2π, y en general en cosas cíclicas.
f ) ¿Qué hace Python cuando b es negativo y decimal? ¡
E 5.6 (cifras II). En el ejercicio 3.23 vimos una forma de determinar
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.
a) Ejecutar:
a = 123
5.2. None Pág. 45
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:
E 5.7 (None).
a) Poniendo en la terminal:
abs(-4)
y luego
a = abs(-4)
vemos que una diferencia entre estos dos grupos de instruccio-
nes es que en el primer caso se imprime el valor de abs(-4) (y
no existe la variable a), mientras que en el segundo el valor de
abs(-4) se guarda en la variable a, y no se imprime nada.
Verificar el valor y tipo de a.
b) Cambiando abs por print, pongamos:
print(-4)
y luego
a = print(-4)
¿Cómo se comparan los resultados de estos dos grupos con
los del apartado anterior? En particular, ¿cuál es el valor de a?,
¿y su tipo?
c) Siempre con a = print(-4), poner a == None para ver que,
efectivamente, el valor de a es None.
d) Poner None en la terminal y ver que no se imprime resultado
alguno. Comparar con los apartados anteriores. ¡
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
por
a = int(input('Ingresar un entero: '))
E 6.7 (contextos).
a) Poner import math y luego math.pi, viendo que obtenemos
un valor más o menos familiar, pero que si ponemos sólo pi
(sin math.) nos da error.
6.4. Usando import Pág. 57
Contexto global
pepe pi pepe
variables
math holapepe
globales
q
Capítulo 7
Funciones
tos.
def g(x):
"""Multiplicar por 4."""
return f(f(x))
y evaluar f y g en ±1, ±2 y ±3. ¡
Contexto global
contexto de la función
instrucciones instrucciones
globales de la función
x a
variables locales
1 3
a f g
variables globales
return x
y ver que da error: una variable no puede ser a la vez argumento
formal y global. ¡
L E 7.12. 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
y ejecutar el bloque
f
f(1)
f
Desde ya que este uso da lugar a confusiones, y aunque válido para
Python, en el curso está prohibido. ¡
7.4. Comentarios
• Ocasionalmente necesitaremos variables que no son ni locales
ni globales para lo que se puede usar nonlocal que no veremos
en el curso.
• Una variante a la de pasar una función como argumento de
otra función (ejercicio 7.14) son las funciones recursivas, que
estudiamos en los capítulos 14 y 17, pero que en pocas palabras
pueden describirse como funciones que se llama a sí mismas.
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. 73
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
E 8.8 (cifras III). En los ejercicios 3.23 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 seudocó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.
Python no tiene la estructura repetir... hasta que..., pero
podemos imitarla usando break en un «lazo infinito»:
c = 0
while True: # repetir...
c = c + 1
Pág. 82 Capítulo 8. Tomando control
n = n // 10
if n == 0: # ... hasta que n es 0
break
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. Así, los primeros primos son 2, 3, 5, 7
y 11.
(1)
¡Como su nombre lo indica!
(2)
Cuanto más se confunda, mejor.
Pág. 84 Capítulo 8. Tomando control
mientras a ≠ b:
si a > b:
a ← a−b
en otro caso: # acá es b > a (8.1)
b←b−a
# acá es a = b
retornar a
8.3. El algoritmo de Euclides Pág. 85
Pablito
papá
0 1 2 3 4 5
mcm(a, b) × mcd(a, b) = a × b.
Sucesiones (secuencias)
E 9.3 (tuplas).
a) Poner
a = (123, 'mi mamá', 456)
b = 123, 'mi mamá', 456
9.2. tuple (tupla) Pág. 91
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.6).
i) En la terminal poner [a, b] = [1, 2] y verificar los
valores de a y b.
ii) Poner [a, b] = [b, a] y volver a verificar los valores
de a y b. ¡
9.3. list (lista) Pág. 95
E 9.11. Ejecutar:
a = [1, 2, 3, 4, 5]
a[2:4]
a[2:4] = [6, 7, 8, 9]
a
a[1:-3]
a[1:-3] = [3, 4]
a
a[1:-1]
a[1:-1] = []
a ¡
9.3. list (lista) Pág. 97
E 9.12. Si a es una lista (por ejemplo a = [1, 2, 3]), ¿cuáles son las
diferencias entre a.reverse() y a[::-1]?
Ayuda: mirar el resultado de cada operación (lo que Python escribe
en la terminal) y el contenido de a al final de cada una de ellas. ¡
def g(a):
"""Asignar la lista."""
print("Al entrar a la función:", a)
a.append(2)
print("En el medio de la función:", a)
a = a + [3]
print("Antes de salir de la función:", a)
y luego evaluar
a = [1]
g(a)
a ¡
a[1][1] = 4
a
b
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 no existe en lengua-
jes 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, y no está implementada en Python.
Para nosotros será suficiente usar listas porque los ejemplos son
de tamaño muy reducido.
- numpy (http://numpy.scipy.org/) es un módulo no es-
tándar de Python que implementa arreglos eficientemente.
• 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.18) 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 11.
Miremos algunos ejemplos sencillos.
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
definiendo adecuadamente n). ¡
y
for i in range(len(a)): # para cada índice
... # hacer algo con a[i]
for x in b:
print(x)
x # x no es 2 ¡
p = []
for i in range(len(a)):
if x == a[i]: (10.4)
p.append(i)
return p
E 10.7. Definir una nueva función sumar en base a estas ideas y com-
probar 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) ¡
de dos formas:
a) Mediante una función gauss1(n) que usa un lazo for con el
esquema:
s = 0
for i in range(1, n + 1):
s = s + i
return s
n × (n + 1)
sn = .
2
- Usar división entera. ¡
donde
n n! n × (n − 1) × ⋅ ⋅ ⋅ × (n − k + 1)
( )= = (10.10)
k k! (n − k)! k!
son los coeficientes binomiales o números combinatorios (0 ≤ k ≤ n).
- Cuando x = y = 1, (10.9) se reduce a 2n = ∑nk=0 (nk ), que tiene una
bonita interpretación combinatoria: si el conjunto total tiene car-
dinal n, el miembro izquierdo es la cantidad total de subconjuntos
mientras que (nk ) es la cantidad de subconjuntos con exactamente
k elementos.
E 10.10. Hacer el cálculo de los tres factoriales (n!, k! y (n − k)!) en
el segundo miembro de las igualdades en (10.10) es ineficiente, y es
mejor hacer la división entera a la derecha de esas igualdades porque
involucra muchas menos multiplicaciones.
(2)
A veces llamado teorema del binomio de Newton.
10.1. for (para) Pág. 113
y de aquí que
En este caso, dado que una vez que t sea falso, siempre lo seguirá
siendo, podemos poner (como en 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.5 para el máximo y
en el ejercicio 10.7 para la suma (de números u otros objetos),
cuando las secuencias a considerar son no vacías podemos poner
a secuencia[0] como valor inicial del acumulador.
- Acá vienen preguntas «filosóficas» de cuánto valen:
– la suma de ningún número,
– el producto de ningún número, o
– el máximo de una lista vacía.
Ninguna tiene mucho sentido.
Es decir, ponemos el acumulador inicialmente en 0 para
la suma o en 1 para el producto sólo por una cuestión de
simplicidad, pensando en que la lista con la que estamos
trabajando es no vacía.
L E 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 (¡no ejecutar lo que sigue!):
b = [1]
for x in b:
b.append(1)
Para verificar que el lazo no termina, paremos después de 10
pasos:
Pág. 116 Capítulo 10. Recorriendo sucesiones
b = [1]
for x in b:
b.append(1)
if len(b) == 10: # o 20,...
break
b
E 10.13. Python tiene el método reverse que «da vuelta» una lista
modificándola (ver el ejercicio 9.10). Esta acción se puede hacer efi-
cientemente con un lazo while, tomando dos índices que comienzan
en los extremos y se van juntando:
10.2. Un alto en el camino Pág. 117
*
* *
* * *
* * * *
* * * * *
i, j = 0, len(a) - 1
while i < j:
a[i], a[j] = a[j], a[i] # intercambiar
i, j = i + 1, j - 1 # nuevos i y j
*
/ \
* *
/ \ / \
* * *
/ \ / \ / \
* * * *
lista = [] # acumulador
for x in iterable:
(10.15)
lista.append(f(x))
lista
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? ¡
E 10.20. Comparar las funciones gauss1(n) y gauss2(n) del ejerci-
cio 10.8 para n = 1, . . . , 10:
10.4. Filtros Pág. 121
10.4. 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
Pág. 122 Capítulo 10. Recorriendo sucesiones
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
E 10.23. Usando filtros (en vez de un lazo for), dar una definició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 Pág. 123
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).
• 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
11.1. Formatos
Empezamos estudiando cómo imprimir secuencias en forma pro-
lija, especialmente cuando se trata de encolumnar la información en
tablas. Desde ya que aplicaciones más específicas, como procesadores
de texto o de diseño de página, hacen esta tarea mucho más sencilla.
E 11.1 (opciones de print). Pongamos a = 'Mateo Adolfo' en la
terminal.
a) Ver el resultado de
for x in a:
print(x)
for x in a:
print(x, end='')
viendo el resultado.
c) En algunos casos la impresión se junta con >>>, en cuyo caso
se puede agregar una instrucción final print(''). Mejor aún
es poner:
for x in a[:-1]:
print(x, end='')
print(a[-1])
(1)
Sí, es una palabra permitida por la RAE.
Pág. 126 Capítulo 11. Formatos y archivos de texto
print('-{0:20}-{1:^20}-{2:>20}-'.format(
'izquierda', 'centro', 'derecha'))
También se puede especificar < para alinear a la izquierda,
pero en cadenas es redundante.
d) Cuando trabajamos con decimales, las cosas se ponen un tanto
más complicadas. Un formato razonable es el tipo g, que agre-
ga una potencia de 10 con e si el número es bastante grande
o bastante chico, pudiendo adecuar la cantidad de espacios
ocupados después del « : » y la cantidad cifras significativas
después del « . »:
a = 1234.5678901234
print('{0} {0:g} {0:15g} {0:15.8g}'.format(a))
print('{0} {0:g} {0:15g} {0:15.8g}'.format(1/a))
a = 1234567890.98765
print('{0} {0:g} {0:15g} {0:15.8g}'.format(a))
print('{0} {0:g} {0:15g} {0:15.8g}'.format(1/a))
E 11.3. Imprimir una tabla del seno donde la primera columna sean
los ángulos entre 0○ y 45○ en incrementos de 5 poniendo:
import math
Pág. 128 Capítulo 11. Formatos y archivos de texto
aradianes = math.pi/180
for grados in range(0, 46, 5):
print('{0:6} {1:<15g}'.format(
grados, math.sin(grados * aradianes)))
Probar estas instrucciones y agregar un encabezado con las palabras
'grados' y 'seno' centradas en las columnas correspondientes. ¡
E 11.4. Las instrucciones siguientes construyen la tabla de verdad para
la conjunción ∧ («y» lógico):
formato = '{0:^5s} {1:^5s} {2:^5s}'
print(formato.format('p', 'q', 'p y q'))
print(19 * '-')
for p in [False, True]:
for q in [False, True]:
print(formato.format(
str(p), str(q), str(p and q)))
Poner
archivo.close() # cerrar el archivo
archivo.read() # volver a leerlo
viendo que la última instrucción ahora da error.
f ) En este ejemplo no hay mucho problema en leer el renglón
impreso mediante archivo.read() porque se trata de un tex-
to relativamente corto. En textos más largos es conveniente
imprimir (o lo que sea que queramos hacer) cada renglón se-
paradamente, lo que podemos hacer poniendo
archivo = open('santosvega.txt', 'r',
encoding='utf-8')
for renglon in archivo:
print(renglon)
archivo.close() # ya no usamos más el archivo
len(archivo)
archivo.close() # siempre cerrar al terminar
E 11.10. Usando split, imprimir por pantalla las palabras (una por
renglón) con 5 o más letras en el archivo santosvega.txt. ¡
E 11.11 (leyendo tablas). En el ejercicio 6.3 vimos que cuando se ingre-
san datos con input, Python los interpreta como cadenas de caracteres
y debemos pasarlos a otro tipo si es necesario. Algo similar sucede
cuando se lee un archivo de texto.
a) Ubicándose en el directorio correspondiente, en la terminal
poner
archivo = open('tablaseno.txt', 'r',
encoding='utf-8')
donde tablaseno.txt es el archivo construido en el ejercicio 11.7.
b) Usando for para construir una lista por comprensión (en forma
similar al ejercicio 11.5.f )), ver el resultado de las siguientes
instrucciones:
a = [x for x in archivo] # lista de renglones
a
a[0] # primer renglón
a[0].split()
E 11.12. Empezamos por ver cómo podemos usar split para distinguir
datos separados por comas.
a) Ejecutar y estudiar el resultado
a = ['{},{}'.format(n, n**2) for n in range(10)]
a # ver los contenidos
11.4. Comentarios
• Algunos entusiastas de Python prefieren el esquema
with open('datos.dat') as lectura:
for renglon in lectura:
print renglon
ya que el archivo se cierra aún si hubo errores en el medio. Nues-
tro esquema es (algo) más parecido al de otros lenguajes.
Capítulo 12
Clasificación y búsqueda
12.2. Clasificación
E 12.2. Para clasificar una lista (modificándola) podemos usar el mé-
todo de listas sort (clasificar en inglés). Si no queremos modificar la
lista o trabajamos con una cadena de caracteres o tupla —que no se
pueden modificar— podemos usar la función sorted (clasificada en
inglés) que da una nueva lista.
Verificar los resultados de los siguientes en la terminal de IDLE,
donde usamos la función sumar del ejercicio 10.7:
a) import random
a = list(range(10)) # [0, 1, 2,...]
random.shuffle(a) # retorna None
a # se modificó
sorted(a) # una lista
a # no se modificó
12.2. Clasificación Pág. 141
○
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
E 12.6. a) Definir una función cuentas(a) que dada una lista a retor-
na una nueva lista [[x, p], [y, q],...] donde x, y,... son
los elementos de a sin repeticiones, y p, q,... es la cantidad de
apariciones.
Por ejemplo, si a = [1, 3, 2, 4, 2, 4, 1, 2], el resulta-
do debe ser [[1, 2], [3, 1], [2, 3], [4, 2]]. Atención:
a no debe modificarse, trabajar con una copia.
Sugerencia: trabajar con índices en el esquema sugerido en
el ejercicio 12.5.b), modificando un contador del índice cada
vez que se encuentra x.
- También podría mirarse el ejercicio 12.4.
E 12.8 (de lista a conjunto). Definir una función para «pasar una lista
a conjunto», ordenándola y purgándola (en ese orden). Por ejemplo,
si a = [3, 1, 4, 2, 3, 1], el resultado debe ser [1, 2, 3, 4] (la
lista original a no debe modificarse).
- En general (no siempre) es más eficiente primero clasificar y
después purgar (según el ejercicio 12.7) que purgar primero (según
el ejercicio 12.5) y después clasificar. ¡
poco = 0
mucho = n - 1
while poco + 1 < mucho:
medio = (poco + mucho) // 2
if a[medio] <= x:
poco = medio
else:
mucho = medio
# ahora comparar x con a[mucho] y con a[poco]
y usarlo para definir una función busbin(a, x) para buscar
un elemento en una lista (¡ordenada no decrecientemente!)
retornando False o True y en este caso imprimiendo su posi-
ción.
d) Probar busbin(a, x) cuando a es una lista ordenada de 100
números enteros elegidos al azar entre 1 y 1000 (posiblemente
repetidos), en los siguientes casos:
i) x es elegido aleatoriamente en el mismo rango pero puede
no estar en la lista a (hacerlo varias veces).
ii) x = 0.
iii) x = 1001.
e) ¿Cómo se relacionan el método de búsqueda binaria (en este
ejercicio) y el del regalo en las cajas (ejercicio 12.11)? Por ejemplo,
¿cuál sería la lista ordenada?
- Python tiene distintas variantes y aplicaciones de búsqueda bi-
naria en el módulo estándar bisect, que no veremos en el curso
(consultar el manual de la biblioteca). ¡
12.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
Pág. 154 Capítulo 12. Clasificación y búsqueda
q
(3)
A veces traducidas como transformaciones de llave.
Parte II
Popurrí
Bb
Capítulo 13
El largo y serpenteante
recorrido
n a = fn b = f n−1
2 1 1
3 2 1
4 3 2
5 5 3
x 2 = x + 1,
y la otra solución es
⌋︂
1− 5
τ = ′
= −τ −1 .
2
De la teoría general de relaciones de recurrencia, se ve que
⌋︂ n ⌋︂ n
τ n − (τ ′ )n (1 + 5) − (1 − 5)
fn = ⌋︂ = ⌋︂ , (13.3)
5 2n 5
relación comúnmente llamada de Binet o de Euler-Binet. En particular,
esta relación muestra que f n crece exponencialmente, ya que τ > 1,
⋃︀τ ′ ⋃︀ < 1, y f n ≈ τ n para n grande.
- ¡El miembro derecho en (13.3) es un número entero!
Podemos una matriz de Rm×n como una lista de m listas que son
las filas o renglones, y cada uno de éstas es una lista de n números.
Recordemos que la transpuesta de una matriz A = )︀a i j ⌈︀ ∈ Rm×n es
la matriz B = )︀b i j ⌈︀ ∈ Rn×m , donde
b i j = a ji para 1 ≤ i ≤ n, 1 ≤ j ≤ m.
13.2.2. Relojeando
Supongamos que tenemos un tiempo expresado en horas, minu-
tos y segundos, por ejemplo, 12 hs 34 m 56.78 s y queremos pasarlo a
segundos.
- En el ejercicio 7.8 hicimos algo parecido.
12 hs = 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,
Entonces para n = 1, 2, . . . ,
r n−1 r n−1
vn = c n−1 + c n−1 × = c n−1 × (1 + ), (13.8a)
100 100
c0 = d0 , y c n = vn + d n para n = 1, 2, . . . (13.8b)
donde
• r = [r[0], r[1],...] son las tasas de interés (en porciento)
de los períodos, y
• d = [d[0], d[1],...] son los depósitos periódicos (d[0] es
el inicial y d[i] el que se hace al final del período i si i ≥ 1).
Observar que en el esquema (13.9), d tiene un elemento más que
la lista r. Si lo que queremos es el monto que podríamos retirar del
banco al vencer el certificado del período n, tenemos que cambiar el
esquema:
13.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 (13.14)
= 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
aproximaciones como para el seno o el logaritmo).
Además los usamos diariamente: un número en base 10 es en reali-
dad un polinomio evaluado en 10,
1234 = 1 × 103 + 2 × 102 + 3 × 10 + 4.
Nuestra primer tarea será evaluar un polinomio en forma eficiente,
para lo cual observamos que sacando factor común en expresiones
cada vez más pequeñas,
P(x) = a n x n + a n−1 x n−1 + ⋅ ⋅ ⋅ + a0 ,
= (a n x n−1 + a n−1 x n−2 + ⋅ ⋅ ⋅ + a1 ) x + a0 ,
= ((a n x n−2 + a n−1 x n−3 + ⋅ ⋅ ⋅ + a2 ) x + a1 ) x + a0 ,
⋮
llegamos a la regla de Horner,
P(x) = ((⋯((a n x + a n−1 ) x + a n−2 ) + ⋯ ) x + a1 ) x + a0 . (13.15)
E 13.10 (regla de Horner). Construir una función que dada una lista
de coeficientes (reales) (a0 , a1 , a2 , . . . , a n ) y un número x ∈ R, evalúe
el polinomio P(x) en la ecuación (13.14).
Hacerlo de tres formas:
Pág. 168 Capítulo 13. El largo y serpenteante recorrido
Algunos comentarios:
• La regla de Horner tiene similitudes con otros esquemas que
hemos visto: en los esquemas (13.7) o (13.9) multiplicamos y
sumamos cosas variables, en la ecuación (13.12) se multiplican y
suman cantidades constantes, y ahora multiplicamos por algo
fijo y sumamos algo variable.
• En la regla de Horner empezamos multiplicando el coeficiente
más importante a n (el que le da el grado al polinomio) y termi-
namos sumando el menos importante, a0 . En cambio, en las dos
13.3. Polinomios Pág. 169
(2)
Bah, ¡a lo bestia!
(3)
¡En el ejercicio 3.10 también comprábamos botellas!
Pág. 172 Capítulo 13. El largo y serpenteante recorrido
True
>>> (10**20 - 1)//10**20 # entero
0
13.5. Cribas
Una criba (o cedazo o tamiz) es una selección de elementos de una
lista según un criterio que depende de otros elementos de la lista.
Quizás la más conocida de las cribas sea la atribuida a Eratóstenes
(276 a. C.–194 a. C.) para encontrar los números primos entre 1 y n
(n ∈ N), donde el criterio para decidir si un número k es primo o no
es la divisibilidad por los números que le precedieron.
Como ya mencionamos (página 83), para nosotros un número
entero p es primo si 1 < p y sus únicos divisores positivos son 1 y p, y
será conveniente tener presente la siguiente propiedad de demostración
sencilla:
13.15. Propiedad. Consideremos a, b y n enteros positivos.
⌋︂ ⌋︂
a) Si a × b = n, entonces o a ≤ n o b ≤ n.
⌋︂
b) n no es primo si y sólo si existe a ∈ N, 1 < a ≤ n tal que a ⋃︀ n.
E 13.16 (criba de Eratóstenes). Supongamos que queremos encontrar
todos los primos menores o iguales que un dado n ∈ N. Recordando
que 1 no es primo, empezamos con la lista
2 3 4 . . . n.
Recuadramos 2, y tachamos los restantes múltiplos de 2 de la lista,
que no pueden ser primos, quedando
2 3 4⇑ 5 6⇑ . . .
Ahora miramos al primer número que no está marcado (no tiene
recuadro ni está tachado) y por lo tanto no es múltiplo de ningún
número menor: 3. Lo recuadramos, y tachamos de la lista todos los
múltiplos de 3 que quedan sin marcar. La lista ahora es
Pág. 176 Capítulo 13. El largo y serpenteante recorrido
2 3 4⇑ 5 6⇑ 7 8⇑ 9⇑ 10
⇑ 11 12
⇑ ...
y seguimos de esta forma, recuadrando y tachando múltiplos hasta
agotar la lista. Los números recuadrados serán todos los primos que
no superan n.
a) La función criba en el módulo eratostenes es una implementa-
ción de esta idea, donde indicamos que un número está tachado
o no con el arreglo esprimo que tiene valores lógicos.
⌋︂
b) Una vez que i en el lazo principal supera a n, no se modificará
su condición de ser primo o no, por la propiedad 13.15.
Por lo tanto, podemos reemplazar range(2, n + 1) en el
⌋︂
lazo principal por range(2, s + 1), donde s = ⟨︀ n⧹︀.
- Recordar que para a > 0, int(a) da por resultado ⟨︀a⧹︀.
Como hemos mencionado, si n ∈ N es muy grande es
⌋︂
posible que el valor de int(sqrt(n)) no sea el teórico
⟨︀ n⧹︀.
Hacer estos cambios, viendo que para n = 10, 100, 1000 se
obtienen los mismos resultados.
- La criba de Eratóstenes es muy eficiente. La cantidad de pasos
que realiza es del orden de n log(log n), mientras que la cantidad
de primos que no superan n, π(n), es del orden de n⇑ log n según
el teorema de los números primos. Es decir, el trabajo que realiza
la criba es prácticamente lineal con respecto a la cantidad de
elementos que encuentra. ¡
E 13.17. En la cárcel había n celdas numeradas de 1 a n, cada una
ocupada por un único prisionero. Cada celda podía cambiarse de
abierta a cerrada o de cerrada a abierta dando media vuelta a una llave.
Para celebrar el Centenario de la Creación de la República, se resolvió
dar una amnistía parcial. El Presidente envió un oficial a la cárcel con
la instrucción:
4
1 2
3
1 2
4
5 5
3
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 .
Pág. 180 Capítulo 13. El largo y serpenteante recorrido
13.8. Comentarios
• En cursos de matemática discreta es usual estudiar las relaciones
de recurrencia lineales, homogéneas y con coeficientes constantes,
Recursión
recursivo, va. 1. adj. ver recursivo.
14.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, . . . ,
return 1
return n * factorial(n-1)
f2 → 1
f3 = f2 + f1
f2 → 1
f1 → 1
realizando un total de 8 llamadas (haciendo otras tantas copias) además
de la inicial.
Una forma intuitiva de ver la ineficiencia de la recursión, es cal-
cular f n con las dos versiones del ejercicio 13.1, comparando «a ojo»
el tiempo que tarda cada una cuando n es aproximadamente 30 o 35
(dependiendo de la rapidez de la máquina).
Otra forma más científica es mediante el siguiente ejercicio.
cont = 0
sol = fibc(n)
print("Se hicieron", cont, "llamadas")
return sol
donde la función interna es algo como:
def fibc(n):
"""Fibonacci recursivo con contador global."""
global cont
cont = cont + 1 # pasó por acá: incrementar
if n < 3:
return 1
return fibc(n - 1) + fibc(n - 2)
Pág. 190 Capítulo 14. Recursión
función pasar(n):
# pasar n discos de una aguja a otra
si n = 1:
pasar el disco 1
en otro caso:
pasar(n − 1)
pasar el disco n
pasar(n − 1)
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)
Por ejemplo:
(1)
¡Y que no hay cortes de luz!
Pág. 194 Capítulo 14. Recursión
>>> hanoi(3)
Paso 0
a: [3, 2, 1]
b: []
c: []
Paso 1
a: [3, 2]
b: [1]
c: []
Paso 2
a: [3]
b: [1]
c: [2]
...
Sugerencia: usar pop para sacar un elemento de una lista y
append para agregarlo a otra.
- Hay muchas variantes del problema. Por ejemplo, que los discos
no estén inicialmente todos sobre una misma aguja, o que haya
más de tres agujas.
- «Las torres de Hanoi» es un juego inventado en 1883 por el ma-
temático francés Édouard Lucas (1842–1891), quien agregó la
«leyenda».
El juego, ilustrado en la figura 14.1, usualmente se les da a los
chicos con entre 4 y 6 discos, a veces de distintos colores. Notable-
mente, variantes del juego se usan en tratamiento e investigación
de psicología y neuro-psicología.
Lucas es más conocido matemáticamente por su test de pri-
malidad —variantes del cual son muy usadas en la actualidad—
para determinar si un número es primo o no.
- Python tiene una ilustración animada del problema con 6 discos
en el módulo minimal_hanoi.
En MS-Windows, buscarlo en \Lib\turtledemo dentro del
directorio donde está instalado Python. ¡
14.5. Ejercicios adicionales Pág. 195
14.6. Comentarios
• Las imágenes de la figura 14.1 fueron tomadas respectivamente
de(2)
– http://www.cs.wm.edu/~pkstoc/
– http://en.wikipedia.org/wiki/Tower_of_Hanoi.
q
(2)
Enlaces válidos a febrero de 2019.
Capítulo 15
Grafos
3 2
4 1
5 6
E 15.3. Definir una función para que dada la lista de vecinos imprima,
para cada vértice, los vértices que son adyacentes.
Así, para el grafo del ejemplo 15.1 la salida debería ser algo como
Vértice Vecinos
1 2 3
2 1 3 6
3 1 2 4 6
4 3 6
5
6 2 3 4 ¡
a r
v r a a
a v
Por ejemplo, en la figura 15.2 asignamos los «colores» 'a', 'r' y 'v' a
un grafo, siendo el de la izquierda un coloreo pero no el de la derecha.
Definir una función escoloreo(n, aristas, colores) que de-
cide si la lista colores es un coloreo del grafo asociado: aristas es la lista
de aristas de un grafo de vértices {1, . . . , n}, y colores es una lista de
longitud n + 1 de la forma [colores[0],...,colores[n]].
- Los valores que toman los elementos de la lista colores es irrele-
vante: podrían ser letras, números o expresiones más complica-
das.
- Como no necesitamos el valor de colores[0], podemos suponer
que es None, pero no es necesario. ¡
in) es el primero en salir (first out). Son las colas que normal-
mente llamamos... colas, como la del supermercado.
Cola con prioridad: Los elementos van saliendo de la cola de
acuerdo a cierto orden de prioridad. Por ejemplo, las mamás
con bebés se atienden antes que otros clientes.
- Muchos autores restringen la palabra cola a lo que acá llamamos
cola fifo (la del súper).
- La lista quedan en el esquema (13.18) para el problema de Flavio
Josefo puede considerarse como una cola: individuos que van
saliendo de acuerdo a cierto criterio, aunque no es exactamente
de ninguno de los tipos mencionados (fifo, lifo o con prioridad).
3 2
1 cola
3 4
hijo - padre
árbol
4 2 1 elegido
arista sacada
n orden de agregado
5 6
Figura 15.4: Recorrido lifo del grafo del ejemplo 15.1 tomando raíz 1.
1 2 3 4 6
Orden de salida de la cola:
1 3 6 4 2
Sugerencia: agregar dos listas, digamos entrada y salida, e ir
incorporando a cada una los vértices que entran o salen de la cola.
- Repasar la lista salio del ejercicio 13.18.c). ¡
3 2
2 cola
4 1
hijo - padre
árbol
4 1 elegido
3
arista sacada
n orden de agregado
5 6
Figura 15.5: Recorrido fifo del grafo del ejemplo 15.1 tomando raíz 1.
Para demostrar que un grafo conexo con todos los vértices de grado
par tiene un ciclo de Euler, se comienza a partir de un vértice y se van
recorriendo aristas, borrándolas, hasta que volvamos al vértice original,
formando un ciclo. Esto debe suceder porque todos los vértices tienen
grado par. Puede ser que el ciclo no cubra a todas las aristas, pero como
el grafo es conexo, en ese caso debe haber un vértice en el ciclo construi-
do que tenga al menos dos aristas (aún no eliminadas) incidentes en él,
a partir del cual podemos formar un nuevo ciclo, agregarlo al anterior
y continuar con el procedimiento hasta haber recorrido y eliminado
todas las aristas.
Esta demostración es bien constructiva, y podemos implementar
los ciclos como listas, sólo hay que tener cuidado al «juntarlas».
Definir una función para decidir si un grafo es conexo y todos los
vértices tienen grado par (ejercicio 15.16), y en caso afirmativo construir
e imprimir un ciclo de Euler.
Sugerencia: para borrar una arista o un vecino de la lista de veci-
nos usar la función sacar del ejercicio 10.12.c), y para «pegar» ciclos
podría usarse una construcción del tipo ciclo1[:i-1] + ciclo2 +
ciclo1[i+1:]. ¡
15.5. Comentarios
• La presentación de la función recorrido y del algoritmo 15.3
están basadas en la de Papadimitriou y Steiglitz (1998).
q
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, se decidió no hacer algo similar con
los decimales, que también mediante fraccionamiento y rearmado
podrían tener tanta precisión como se quisiera. Esto es lo que
hace el módulo estándar decimal, que no veremos en el curso.
1 2 4 8 16
2 * x # -> inf
x < y # -> verdadero
y < 2 * x # -> verdadero
2 * x < 2 * y # -> falso
2 * x > 2 * y # -> verdadero
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. ¡
ser como los anteriores sólo que divididos por 100 (es decir,
0.09).
Ver que esto no es cierto: para mcd1 se alcanza el máximo
número de iteraciones (1000) y los valores finales de a y b son
muy distintos (y queremos que sean iguales), mientras que
para mcd2 los valores finales de a y b son demasiado pequeños
comparados con la solución 0.09.
Explorar las causas de los problemas, por ejemplo impri-
miendo los 10 primeros valores de a y b en cada función.
c) Repetir a) con las entradas 6125 y 4500 y luego b) con las en-
tradas 6.125 y 4.5. ¿Qué está pasando?
d) En las funciones mcd3 y mcd4 evitamos las comparaciones di-
rectas, incorporando una tolerancia o error permitido. Ver que
estas funciones dan resultados razonables para las entradas
anteriores. ¡
d = b2 − 4ac
E 16.12 (la pelota elástica). Una pelota muy elástica va y viene rebo-
tando entre dos paredes que distan un metro entre sí. Cada vez que
rebota, la pelota incrementa su velocidad en 1 m/s, siendo su velocidad
inicial de 1 m/s.
Suponiendo que:
• la velocidad permanece constante entre un rebote y otro,
• no hay demoras al dar la vuelta, el cambio de dirección es ins-
tantáneo,
16.2. Errores numéricos Pág. 229
h n ≈ log n + γ, (16.3)
γ = 0.577215664901 . . .
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
E 16.17 (punto fijo de f (x) = cos x). Con las notaciones anteriores
para f (x) = cos x y x k (k ≥ 0):
a) Usando un lazo for, construir una función que dados x0 y n
calcule x n , y observar el comportamiento para distintos valores
de x0 y n.
b) Modificar la función para que también imprima cos x n y com-
probar que para n más o menos grande se tiene x n ≈ cos x n .
c) Modificar la función para hacer 200 iteraciones, mostrando
los resultados intermedios cada 10. Observar que después de
cierta cantidad de iteraciones, los valores de x k no varían.
Pág. 234 Capítulo 16. Cálculo numérico elemental
f (x + h) ≈ f (x) + f ′ (x) h,
y como h = x ∗ − x, queda
Aproximando la tangente
y
f (x + h) − f (x)
− f ′ (x) = O(h),
h
mientras que el error en (16.8)
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.
-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
- En la función newton no consideramos la posibilidad f ′ (x) = 0.
a = a0 c2 b = b0 = b1
c0 = a 1 = a 2 c1 = b2
f (x) = x (x + 1) (x + 2) (x − 4⇑3),
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
mucho − poco ≤ 1.
16.6. Comentarios
• Los temas presentados en este capítulo no están tomados de
ninguna fuente en particular: cualquier cita nos llevaría a cosas
mucho más profundas de las que vimos.
Más aún, no hemos tocado en absoluto temas típicos de cursos
de cálculo numérico como integración numérica, resolución de
ecuaciones diferenciales o sistemas lineales.
• El ejercicio 16.12 es una variante de uno que aparece en la versión
inglesa de Wikipedia,(2) y desconozco su autor.
• El método de Newton o variantes se generaliza a varias variables
(reemplazando adecuadamente la derivada unidimensional), e
inclusive a variables complejas.
En cambio, es muy difícil generalizar el método de la bisección
a más de una dimensión.
• Los métodos iterativos están íntimamente relacionados con los
conjuntos fractales, como el de la figura 16.7.
Para hacer estos gráficos usamos el método de Newton bus-
cando las raíces (complejas) del polinomio z 3 − 1, marcando con
⌋︂
rojo (resp. azul o verde) los puntos que cuando tomados como
iniciales el método converge hacia 1 (resp. −1⇑2 ± i 3⇑2).
https://en.wikipedia.org/wiki/Harmonic_series_(mathematics)
(2)
16.6. Comentarios Pág. 249
2z + 1⇑z 2
g(z) = ,
3
que está definida para z ≠ 0, y sobre la recta real todos los puntos
están marcados en rojo (salvo 0).
A la izquierda de la figura vemos el gráfico en el cuadrado de
centro 0 y lado 4, y a la derecha un detalle del cuadrado centrado
en 0.3765 + 0.2445 i (punto resaltado a la izquierda en blanco) y
lado 0.004.
El gráfico a la derecha es un «zoom» por un factor de 1000 del
gráfico a la izquierda, lo que indica que las propiedades del gráfi-
co no resultan de errores numéricos sino que son una propiedad
intrínseca.
Este es un ejemplo extremo de lo expresado en el «cartel» de la
página 236, sobre cómo depende la solución obtenida del punto
inicial.
• El muy difundido conjunto de Mandelbrot, reproducido en la
figura 16.8, también es un conjunto fractal relacionado con las
Pág. 250 Capítulo 16. Cálculo numérico elemental
iteraciones: son los puntos c del plano complejo para los cuales
tomando como punto inicial z0 = 0, las iteraciones de f c (z) =
z 2 + c permanecen acotadas.
Más información sobre este conjunto se puede obtener en
internet, por ejemplo en Wikipedia.(3)
q
https://es.wikipedia.org/wiki/Conjunto_de_Mandelbrot
(3)
Capítulo 17
Objetos combinatorios
n n n n−1 n−1
( )=( )=1 y ( )=( )+( ) si 0 < k < n. (17.1)
0 n k k−1 k
1
/ \
1 1
/ \ / \
1 2 1
/ \ / \ / \
1 3 3 1
/ \ / \ / \ / \
1 4 6 4 1
E 17.1. Definir una función recursiva para calcular (nk) basada en las
relaciones (17.1).
- Observar que en este caso el paso base es en realidad dos: cuando
k = 0 y cuando k = n. ¡
1 4 10 20 35
1 3 6 10 15
1 2 3 4 5
1 1 1 1
17.3. yield
Hay distintas técnicas para construir los objetos uno a la vez, evi-
tando generar la «gran lista». Por ejemplo, podemos poner una fun-
ción dentro de otra envolvente, como hicimos en la función hanoi del
ejercicio 14.7. 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)
(2)
Tener en cuenta que al pasar de n a n + 1, básicamente se duplican el tiempo que
se tarda y la memoria que se necesita.
17.3. yield Pág. 257
E 17.6.
a) Definir la función fibgen según el esquema (17.3) en un mó-
dulo, y ejecutarlo.
b) fibgen en principio es una función como cualquier otra. Pero
a pesar de que no tiene un return explícito, su resultado no es
None sino un objeto de tipo o clase generator (generador).
Poner en la terminal:
fibgen
type(fibgen)
fibgen(10)
type(fibgen(10))
[x for x in fibgen(10)]
for x in fibgen(5):
print(x)
it = periodico(7)
[next(it) for k in range(20)]
E 17.9. Repetir el ejercicio 17.5.c) ahora con subs(n) para n = 18, 19,
20, . . . , comparando los resultados en uno y otro caso.
- La versión con «gran lista» para n = 23 cabe en la memoria
principal de mi máquina, pero tarda entre 4 y 5 veces lo que tarda
la versión con yield. ¡
Pág. 262 Capítulo 17. Objetos combinatorios
E 17.10. Repetir los apartados del ejercicio 17.8, cambiando subs por
subsnk(6, 3) y perms(4) en los lugares adecuados.
(︀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'],
17.6. Comentarios Pág. 265
17.6. Comentarios
• En este capítulo vimos que si bien recursión en general es inefi-
ciente, se puede mejorar su desempeño con distintas técnicas.
También vimos que, de cualquier forma, siempre nos topa-
mos con la denominada «explosión combinatoria»: la cantidad
exponencial de objetos a examinar cuando usamos técnicas de
barrido.
Uno de los grandes desafíos de las matemáticas es encontrar
algoritmos eficientes para resolver problemas asociados, aun-
que —como ya mencionamos— difícilmente existan algoritmos
verdaderamente eficientes: entre los problemas del milenio(3) (re-
medando los problemas planteados por Hilbert un siglo antes)
se encuentra justamente decidir si P ≠ NP.
• Los generadores vía yield son variantes de las corutinas, que
existen desde hace varios años en algunos lenguajes de programa-
ción, estando Simula y Modula-2 entre los primeros en usarlas.
Simula fue desarrollado en los 60 extendiendo el lenguaje
Algol, del cual desciende también Pascal. A su vez, Modula-2
fue desarrollado a fines de los 70 por N. Wirth como sucesor
http://es.wikipedia.org/wiki/Problemas_del_milenio
(3)
Pág. 266 Capítulo 17. Objetos combinatorios
q
Parte III
Apéndices
Bb
Apéndice A
Módulos y archivos
mencionados
lectura.close() # y cerrarlo
(1)
http://oma.org.ar/invydoc/libro-prog.html
Pág. 270 Apéndice A. Módulos y archivos mencionados
Para curiosos:
def epsi(x):
"""Menor potencia de 2 que sumada a x da mayor que x.
if x == float('inf'): # salir
print(x, 'es demasiado grande')
return
x = float(x) # para evitar lazo infinito
decimales Pág. 271
y = 1.0
# ver si hay que agrandar o achicar y
if x + y > x: # achicar y
while x + y > x:
z, y = y, y/2
return z
# agrandar y
while x + y == x:
y = 2 * y
return y
epsmaq = epsi(1.0)
epsmin = epsi(0.0)
def maxpot2calc():
"""Cálculo de máxima potencia de 2 representable como float."""
x = 1.0
while 2 * x > x:
x, s = 2 * x, x
return s
maxpot2 = maxpot2calc()
def maxnumcalc():
"""Cálcular el máximo número decimal representable."""
global maxnum
x = maxpot2
p = maxpot2 / 2
while x + p > x:
s = x
x = x + p
p = p / 2
return s
maxnum = maxnumcalc()
Pág. 272 Apéndice A. Módulos y archivos mencionados
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):
esprimo[j] = False
#----------------------------------------------
# salida
# observar el uso del filtro
return [i for i in range(2, n + 1) if esprimo[i]]
# tolerancia permitida
tol = 10**(-7)
def f(x):
"""Suma 1 al argumento."""
flocal Pág. 275
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)
def devecinosaaristas(vecinos):
"""Pasar de lista de vecinos a lista de aristas."""
ngrafo = len(vecinos) - 1 # índices para vértices desde 1
aristas = []
for v in range(1, ngrafo): # no usamos vecinos[0]
for u in vecinos[v]: # y u <= ngrafo
# guardamos arista sólo si v < u para no duplicar
if v < u:
aristas.append([v, u])
return aristas
ifwhile (capítulo 8)
"""Ejemplos sencillos de if y while."""
def espositivo(x):
"""Decidir si el número es positivo o no.
def piso(x):
"""Encontrar el piso de un número."""
Pág. 278 Apéndice A. Módulos y archivos mencionados
def cifras(n):
"""Cantidad de cifras del entero n (en base 10)."""
# 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
mcddr(0, 0) = 0.
"""
# lazo principal
while b != 0:
r = a % b
a = b
b = r
# acá b == 0
# salida
return a
- puntofijo
- newton
- biseccion
"""
# 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.
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
def fp(x):
return (func(x + dx/2) - func(x - dx/2))/dx
# 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
Pág. 282 Apéndice A. Módulos y archivos mencionados
return mucho
# salida
return medio
- factorial: n!
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
def hanoi(n):
"""Solución recursiva a las torres de Hanoi.
- n es la cantidad de discos.
# función interna
Pág. 284 Apéndice A. Módulos y archivos mencionados
# 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__)
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()
http://www.humancomp.org/unichtm/unilang8.htm
http://oma.org.ar/invydoc/docs-libro/unilang8.txt
外国語の学習と教授
Language Learning and Teaching
Изучение и обучение иностранных языков
Tere Daaheng Aneng Karimah
語⽂文教學・语⽂文教学
Enseñanza y estudio de idiomas
Изучаване и Преподаване на Чужди Езици
ქართული ენის შესწავლა და სწავლება
'læŋɡwidʒ 'lɘr:niŋ ænd 'ti:tʃiŋ
Lus kawm thaib qhia
Ngôn Ngữ, Sự học,
ללמוד וללמד את השֵפה
L'enseignement et l'étude des langues
말배우기와 가르치기
Nauka języków obcych
Γλωσσική Εκμὰθηση και Διδασκαλία
ﺗﺪرﯾﺲ و ﯾﺎدﮔﯿﺮی زﺑﺎن
Sprachlernen und -lehren
ﺗﻌﻠﻢ وﺗﺪرﯾﺲ اﻟﻌﺮﺑﯿﺔ
เรียนและสอนภาษา
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.
B.2. Conjuntos Pág. 289
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.
)︀
⌉︀ si x > 0,
⌉︀
⌉︀
⌉︀
1
signo(x) = ⌋︀0 si x = 0,
⌉︀
⌉︀
⌉︀
⌉︀
]︀−1 si x < 0.
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
Parte IV
Índices
Bb
Comandos de Python que
usamos
!=, 31 \\, 38
", 34 *, 18
""" (documentación), 51 para cadenas, 37
+, 18 **, 18
concatenación ', 34
de cadenas, 35
abs, 21
de sucesiones, 102
and, 31
-, 18
append, 96
/, 18
//, 18 bool, 30
<, 31 break, 81
<=, 31
=, 39 close, 129
y ==, 31 continue, 82
==, 31
def, 58
>, 31
divmod, 92
>=, 31 __doc__ (documentación), 51
# (comentario), 53
%, 18 e (notación científica), 23
\, 37 elif, 74
\n, 37 else, 73
Pág. 296 Comandos de Python que usamos
y math.trunc, 25
sep
en print, 125
en split, 136
sort (clasificar), 140
sorted (clasificar), 140
split, 134
sep, 136
str, 30
sum, 110
True, 30
tuple, 90
type, 22
while, 77
write, 133
yield, 256
Índice de figuras y cuadros
de Tartaglia, 251
tupla (tuple), 88, 90
clasificación, 140
variable, 40
global, 56, 64
local, 56, 64
vértice
aislado, 197
vínculo, véase referencia
von Neumann
arquitectura, 13
o