Download 1 explora la matemática con python cero, python esencial La

Document related concepts
Transcript
explora la matemática con python
cero, python esencial
La computadora es una máquina universal, capaz de ejecutar instrucciones precisas a velocidad de vértigo,
aunque eso sí, insiste en hacerlo a su manera. Afortunadamente, se han creado los llamados lenguajes de
programación de alto nivel, que permiten a cualquiera escribir estas instrucciones que una computadora
puede seguir, una vez traducidas o compiladas a su dialecto. Un lenguaje que goza de gran popularidad en
estos días en la industria es Python, creado en los años 80, pero que sigue evolucionando.
print()
Consideremos nuestro primer programa en Python,
print("hola, mundo.")
Si mediante nuestro buscador entramos a la página www.ideone.com, disponemos de un entorno de
desarrollo integrado, ide, en que podemos verificar el funcionamiento de nuestro programa. Para ello
ubicamos en la parte superior de la pantalla una caja de texto en la que aparece el texto “# Your code goes
here.” y lo remplazamos por print("hola, mundo.").
Buscamos, hacia abajo y a la izquierda, un botón verde que índice el lenguaje de programación a usar y nos
aseguramos que sea Python, y en la misma línea, a la derecha, pulsamos el botón Run (correr, ejecutar).
El programa será enviado a idone.com y luego de unos segundos, según la calidad de nuestra conexión a
Internet, aparece el texto “hola, mundo.” en una caja de texto llamada stdout (salida estándar). Esto es lo que
este programa hace desplegar el mensaje “hola, mundo.”. Para modificar nuestro programa vamos a la
esquina superior izquierda y pulsamos el botón con un icono de lápiz, Editar, y entonces el texto se vuelve
editable.
Nuestro segundo programa logrará el mismo resultado que el primero, pero cumple un acuerdo que queda
establecido en lo adelante entre nosotros, y es que cada uno de nuestros programas empieza con un
comentario que anticipa el propósito u objetivo del mismo,
# despliega "hola, mundo."
print("hola, mundo.")
1
Copiamos este texto encima del anterior, remplazándolo. Ejecutamos este nuevo programa (pulsando Run o
Ideoneit!) y verificamos que el resultado es el mismo que el del programa anterior. Veamos otro programa,
# los primeros 3 números naturales
print(1, 2, 3)
Lo ejecutamos en ideone y comprobamos que en la caja de texto de salida estándar (stdout) se lee,
1 2 3
Se invita al lector a redactar y ejecutar variantes de este programa, manteniendo la misma estrategia, para
obtener los primeros 5, 10, 20 naturales, modificando la segunda línea de nuestro programa. Puede ser
tedioso, ¡pero funciona!
variable
Python incluye un poderoso concepto para explorar la matemática, a saber, el concepto de variable. Una
variable es una abstracción sobre los elementos de un conjunto, eso es, podemos crear una variable como un
símbolo que representa a un elemento arbitrario, a cualquiera de los elementos de un conjunto dado.
En nuestro ejemplo actual, 1 2 3 son números naturales. Así que definamos la variable n para referirnos a
cualquiera de ellos. Para ver esto en acción, redactamos el programa,
# los primeros 3 números naturales
n = 1 # natural
print(n)
n = n + 1
print(n)
n = n + 1
print(n)
Al escribir n = 1, le estamos diciendo a Python que aparte en la memoria de la computadora un espacio para
guardar un numero cualquiera del mismo conjunto al que pertenece el 1, en este caso, un número natural.
“print(n)” le dice a Python que escriba el valor que en ese momento tiene la variable n, que es 1, por ahora.
Así que nuestro programa crea la variable n y guarda en ella el numero natural 1. Lo escribe, luego va a la
memoria y recupera el valor actual de n (que es 1) le suma 1 (dando 2) y lo guarda donde estaba el 1, esto es,
remplaza el 1 por un 2, que es el nuevo valor de n.
2
Luego escribe el valor de n (2). A seguidas remplaza el 2 que ahora hay en n por un 3 y lo escribe, y termina
el programa.
Se puede ejecutar este programa en ideone y comprobar que produce el mismo resultado que el anterior:
1
2
3
Ahora, copiando y pegando las líneas que rezan “n = n + 1” y “print(n)” se pueden desplegar otros
números naturales. Pero sigue siendo algo tedioso. Así que sigamos explorando la matemática con Python,
while
# primeros 3 números naturales
n = 1 # natural
while n <= 3:
print(n)
n = n + 1
Se inicia a n con el valor 1, y como en el ejemplo anterior, pero ahora usando la sentencia while (mientras)
decimos a Python que repita la ejecución de las sentencias “print(n)” y “n = n + 1” mientras la condición
“n <= 3” sea verdadera. Veamos.
Se asigna 1 a la variable n. Se evalúa la condición n <= 3, y como 1 <= 3, se escribe el 1 y n pasa a ser 2.
Se verifica si todavía el valor n (2) es menor o igual que 3, y como es así, se vuelven a ejecutar las dos
sentencias dentro del ciclo while, por lo que se escribe 2 y n pasa a ser 3.
Se vuelve a verificar si n <= 3, y como 3 <= 4, se escribe 3 y n se hace 4. Pero al volver a verificar la
condición, resulta ser falsa, por lo que se abandona el ciclo y se termina el programa.
Este programa logra el mismo resultado que los dos anteriores, pero usando una herramienta más avanzada.
Para el usuario es la misma experiencia, no así pero para el programador. Así que sentarse en la silla del
desarrollador puede ser muy divertido también, ¡y da una maravillosa sensación de poder!
3
Se puede notar que si deseamos obtener los primeros 100 números naturales, basta ahora cambiar el 3 por
un 100. Y podemos poner cualquier valor hasta donde el tiempo que da ideone lo permita. Tenemos un código
más general y flexible. Estamos, pues, explorando la matemática con Python.
contador
En nuestro programa,
# los primeros 3 números naturales
n = 1 # naturales
while n <= 3:
print(n)
n = n + 1
Decimos que la variable n es un contador porque se inicia a n con el valor 1 y cada vez que se ejecuta el ciclo
n es incrementada en un valor fijo, en este caso, 1.
Si en lugar de contar de 1 a 3 (en realidad 4, ya que n debe llegar a 4 para que la condición del ciclo se haga
falsa y poder abandonarlo) queremos empezar en 5 e ir de 5 hasta 100, modificamos el programa,
# los números naturales de 5 a 100
n = 5 # naturales
while n <= 100:
print(n)
n = n + 5
Ahora n empieza con 5, que como es menor o igual que 100, se entra en el ciclo y no abandona hasta que n
sobrepase a 100. Dentro del ciclo se escribe el 5 inicial y n es incrementado en 5 cada vez, de forma que
toma los valores 10 15... 100 105.
Pero 105 no se escribe porque cuando n toma este valor el ciclo es abandonado y el último en escribirse es el
100, como queremos.
acumulador
Si en lugar de escribir cada uno de los valores que toma el contador deseamos la suma de todos esos
valores, acudimos al concepto de acumulador, similar al de contador, pero la cantidad que se añade puede no
ser fija,
4
# suma de los primeros 100 números naturales
s = 0 # suma
n = 1 # naturales
while n <= 100:
s = s + n
n = n + 1
print(s)
Ahora se ha introducido la variable s para acumular la suma, y inicia con 0 para asegurar que su valor final
sea correcto, porque si no, podría llegar a ser la suma de los valores deseados más un valor desconocido
inicial, lo cual sería erróneo.
Se inicia n con 1, como antes y dentro del ciclo se incrementa en uno como antes. Lo nuevo es que dentro del
ciclo no se van escribiendo los valores de n, y en vez se van aculando los valores de c en s mediante la
sentencia s = s + c, que significa que remplace el valor actual de s por el valor actual de s sumándole el
actual de n.
La primera vez que se ejecute el ciclo, s pasa de 0 a 0 + 1 (dando 1). La segunda vez de 1 a 1 + 2 (dando
3). La tercera de 3 a 3 + 3 (dando 6). Y así se sigue, hasta acumular en s la suma de los primeros 100
números naturales, como queremos.
Como se puede apreciar, los conceptos de variable, ciclo, contador y acumulador usados en adecuada
combinación nos permiten convertir a nuestro dispositivo dotado de procesador electrónico y Python, un fiel y
poderoso asistente para explorar la matemática.
Podemos extender el acumulador a productos,
# factorial de n, n >= 0
f = 1 # factorial
n = 5 # natural
c = 1 # contador
while c <= n:
f = f * c
c = c + 1
print(f)
Se inicia en 1 la variable f, que acumulará el factorial mediante productos sucesivos. n es el número del cual
se va a calcular el factorial, 5 en este caso. c es el contador, que inicia en 1. El ciclo se ejecuta para los
valores 1 a 5, por lo que el valor acumulado en f es 1*1*2*3*4*5 = 120.
5
input
Hasta ahora, todos los valores usados en nuestros programas han sido dados por el programador u obtenidos
mediante cálculos a partir de valores dados por el programador. Pero es posible hacer que el usuario del
programa, ingrese uno o más valores para una o más variables. Veamos un ejemplo,
# factorial de n, n > 0
f = 1 # factorial
c = 2 # contador
n = input() # lee a n
while c <= n:
f = f * n
d += 1
print(f)
Aquí, el valor de n lo decide el usuario, se lee en la línea que reza n = input().
Si se va a probar este programa en ideone, se pulsa el botón stdin (entrada estándar) y se escribe el valor que
se le quiere dar a n, digamos 5. Cuando se pulse el botón Run (o ideonit!), este dato se envía junto con el
código y el programa se ejecuta usando este valor para n.
Cambiando el valor de n, podemos ejecutar el programa con distintos valores sin tener que modificarlo. Esto
añade flexibilidad al código, menor dependencia del programador.
Notamos que se si ingresa el valor 0 para n, el ciclo se salta, no se ejecuta, por lo que el valor de f queda en 1
y se escribe, lo cual correcto ya que 0! = 1.
Si n = 1, se salta el ciclo y se escribe 1, lo cual encaja ya que 1! = 1. Y si n = 2, se ejecuta el ciclo una
sola vez, ya que 2 <= 2, y se calcula 1*2, dando 2, el valor de d pasa ser 3, que no es menor 2 (n), por lo
que se abandona el ciclo y se escribe 2, y 2! = 2.
Para n = 5, se realiza el producto 1*1*2*3*4*5 = 120 (que se acumula en f y al salir del ciclo, cuando
con d = 6) se escribe 120, que es 5!.
6
función
Otra forma de hacer más flexible el código es mediante el uso de funciones, que son fragmentos autónomos
de código genérico reutilizable.
Una función es una solución general a un problema particular. Una de sus formas más usadas es aquella en
que se envía un valor a la función y ella retorna otro valor.
0, 1
Supongamos que hay una función llamada primo, recibe un número entero positivo y que retorna el número 1
para indicar que es verdad que el número recibido es primo, y en caso contrario retorna un 0. Con esto
acabamos de establecer un convenio para que en lo adelante 1 signifique verdadero, que algo es verdad, y
0 signifique que algo es falso, que no es verdadero.
if
La sentencia if nos permite decirle a Python que deseamos verificar si cierta condición sea verdadera
o no. Si la condición es verdadera, se ejecutan una o más acciones, pero no se ejecutan si la condición no es
verdadera.
Así que el siguiente programa escribe todos los números primos que son menores que 100.
# primos menores que 100
n = 1 # natural
while n < 100:
if primo(n):
print n,
n = n + 1
El ciclo se ejecuta para cada uno de los números naturales de 1 a 99, y cada uno de estos valores se pasa a
la función primo(), lo cual es indicado mediante la expresión primo(n). Por tanto, la función primo() va
recibir el valor que tenga n en el momento que la invocan y se ejecuta, verificando si el valor de n
corresponde a un número primo.
Si el valor de n es primo, la función retorna un 1, indicando que es verdad que n es primo, por lo que la
condición de la sentencia if es verdadera y se ejecuta la acción asociada, esto es, se escribe el valor de n,
que es un número primo.
7
Si el valor de n corresponde a un número que no es primo, entonces la función primo() retorna el valor 0,
indicando que no es verdadero que n sea primo, por lo que la condición de la sentencian if resulta no
verdadera, y no se ejecuta la escritura del valor de n. Los números no primos son ignorados, no se
escriben.
Por tanto, este programa escribe los números primos que son menores que 100, e ignora a los que no son
primos, como queremos.
Si queremos escribir los números feos menores que 1000, podemos escribir el siguiente programa.
# números feos menores que 1000
n = 1 # natural
while n < 1000:
if feo(n):
print n,
n = n + 1
El ciclo se ejecuta para cada uno de los números naturales de 1 a 999, pero sólo se escriben aquellos
números que resulten ser feos, cualquier cosa que ello signifique.
Los detalles para determinar si un número es feo estarían encapsulados, metidos en la caja negra que es la
función feo(). Similarmente ocurre con la función primo(), que encapsula los detalles para determinar si un
número es primo.
El uso de funciones nos permite, pues, descomponer la solución de un problema en bloques, facilitando la
redacción de la solución, aumentando la claridad, promoviendo la reutilización del código, entre otros
beneficios.
ejemplos
Python, programa, #, print, variable, asignación, contador, acumulador, while, 0, 1, if, función, son
herramientas para iniciar una exploración de matemática elemental. Veamos otros ejemplos.
# primeros t números naturales, t > 0
t = input() # tope
n = 1 # natural
while n <= t:
print(n)
n = n + 1
8
Este programa pide al usuario un valor para t (invocando la función input()) y en el ciclo se escriben los
números naturales de 1 a t. Si el valor dado para t es 100, se escriben los números naturales de 1 a 100. No
hay que realizar cambios en el programa, cada vez que se ejecuta el programa, el usuario elige el valor que
quiera para t. Otro ejemplo.
# primos menores que t > 0
t = input() # tope
c = 2 # candidato
while c < t:
if primo(c):
print c,
c = c + 1
Este programa pide al usuario un número natural, digamos 1000, entonces se escriben todos los números
primos que son menores que 1000. Para cada valor de c, se invoca a la función primo(), pasándole el valor
de c en ese momento; se ejecuta la función y ella devuelve un 1 si el valor de c corresponde a un número
primo, se escribe el número. Pero si el número no es primo, la función primo() retorna 0, y el valor de c no
se escribe.
El programa asume que hay una función primo(), que "sabe" determinar si un número natural es primo o no,
y que lo dice retornando 1 cuando lo sea, o 0 cuando no.
múltiplos
Queremos escribir los números múltiplos de 3 que son menores que t. Entonces redactamos el programa,
# múltiplos de 3 menores que t > 0
t = input() # tope
c = 3 # candidato
while c < t:
print(c)
c = c + 3
La variable c empieza con el valor 3, el primer natural múltiplo de 3 y en el ciclo se escribe el valor de c (3 la
primera vez) y se le suma 3 a c cada vez, obteniendo los números 6 9 12... y esto continua mientras el valor
de c siga siendo menor que t, el valor tope dado por el usuario. Es claro que si en lugar de dejar el 3 fijo, le
llamamos m y dejamos que sea el usuario que decida de que número desea obtener todos los múltiplos
menores que t (m < t, t > 0), nuestro programa serla más flexible y general.
9
# múltiplos de m menores que t > 1
t = input() # tope
p = input
# primer múltiplo, m < t
m = p
# múltiplos
while m < t:
print(m)
m = m + p
El usuario ingresa el valor de t > 1, y el valor de m < t. Se asigna el valor de p a m, el primer múltiplo. En el
ciclo se escribe el primer valor de m y se le acumula el mismo valor, p, por lo que todos los valores de m son
múltiplos de m: m + m, m + m + m, ...
perfecto
Un número perfecto es un número natural que es igual a la suma de sus divisores propios. Un divisor propio
de un número natural n es un natural menor que n y que divide a n exactamente. Los divisores propios de 6
son 1 2 3 , que sumados dan 6, por tanto, 6 es un número perfecto.
También 28 es un número perfecto porque sus divisores propios son 1 2 4 7 14, que sumados dan 28. Un
programa que obtiene los primeros 4 números perfectos,
# primeros 4 números perfecto
c = 0 # cantidad de perfectos
n = 2 # natural
while c < 4:
if perfecto(n):
print n,
c = c + 1
n = n + 1
c es la cantidad de números perfectos encontrados, que se inicia en 0. n recorre todos los números naturales
que se van a evaluar, mediante la función perfecto().
El ciclo no termina hasta que se hayan encontrado 4 números perfectos, ya que la variable c sólo se
incrementa cuando la función perfecto() retorna un valor verdadero, 1.
Pero la variable n se incrementa cada vez que se ejecuta el ciclo para así probar obtener cada número
natural, partiendo del 2, hasta que se hayan encontrado 4 números perfectos.
10
def, return
Para definir o especificar los detalles internos de una función, usamos la sentencia def.
La siguiente es una función que determina si un número natural n es perfecto. Retorna 1 cuando n es
perfecto, ó 0 en otro caso.
def perfecto(n):
# verifica si n > 0 es perfecto
p = 0 # perfecto - asume que no
s = 0 # suma divisores propios
d = 1 # divisor
while d <= n/2:
if n%d is 0:
s = s + d
d = d + 1
if s == n:
p = 1
return p
Se asume que n no es perfecto, asignando a p el valor 0, no verdadero.
A seguidas inicia la suma, s, con 0, para asegurar que al final sólo contenga la suma de los valores de d que
resulten ser divisores de n, sin contaminación.
El primer valor de d es 1 aunque es claro que todo n es múltiplo de 1, porque en el caso de que n sea 1 (que
cumple con ser natural) se mantendrá siendo no verdadero que n sea perfecto, pues no se ejecuta el ciclo.
Si n es mayor que 1, se ejecuta el ciclo y para cada valor de d que sea menor o igual a la mitad de n, se
verifica si d divide a n exactamente, lo cual ocurre cuando n%d == 0 (== se usa para verificar igualdad y =
para asignar un valor a una variable). La razón de no buscar divisores más allá de la mitad de n (n/2) es que
no los hay.
Por ejemplo, si n es 100, que es par, su mayor divisor es 50, la mitad de 100. Pero si n es 99, que no es par,
pero es múltiplo de 3, su mayor divisor es 33, que es menor que 50.
Así que cuanto mayor es el menor divisor de n, menor es su mayor divisor, por lo que el caso extremo es
cuando es par y en tal caso el mayor divisor es n/2. Por tanto, no hay divisores más allá de n/2.
11
En el ciclo, cuando aparece un divisor d de n, se acumula en s, por lo que al abandonar el ciclo (cuando d se
hace n/2 + 1) en s está acumulada la suma de los divisores propios de n.
Al salir del ciclo se verifica si s coincide con n, en cuyo caso se ha encontrado evidencia de que la premisa de
que n no era perfecto es falsa, y se procede a cambiar el valor de p a 1, significando que n, contrario a la
premisa, resultó ser perfecto.
Así que esta función siempre retorna 0, a menos que resulte ser que la suma de los divisores propios de n
coincida con n, lo cual es conforme a la definición de número perfecto.
Así que un programa completo que escribe los primeros 4 números perfectos es,
# primeros 4 números perfectos
def perfecto(n):
# verifica si n > 0 es perfecto
p = 0 # perfecto - asume que no
s = 0 # suma divisores propios
d = 1 # divisor
while d <= n/2:
if n%d is 0:
s = s + d
d = d + 1
if s is n:
p = 1
return p
c = 0
n = 2
while
if
# cantidad de perfectos
# natural
c < 4:
perfecto(n):
print(n)
c = c + 1
n = n + 1
La definición de la función perfecto() precede a la parte principal del programa para que antes de invocarla
se conozcan sus detalles. En realidad, la primera sentencia que se ejecuta en este programa es c = 0, la
primera después de la definición de la función. Un programa puede contener tantas funciones auxiliares como
se requiera, como iremos viendo.
promedio
Una función que retorne el promedio de dos números podría ser,
12
def prom2(a, b):
# promedio de a y b
p = (a + b)/2
return p
Se asume que se reciben dos números cualesquiera, a y b, que pueden ser enteros, o con parte decimal, se
suman, y la suma se divide por 2, para obtener el promedio, el cual se retorna por medio de la sentencia
return.
Para promediar tres números podemos extender el programa a,
def prom3(a, b, c):
# promedio de a, b y c
p = (a + b + c) / 3
return p
Podemos seguir con esta estrategia y hacer una función para 4, 5, 6, números, y otros casos. Esto es
agotador.
v[i]
Una solución que cubre muchos casos de un golpe es una que asuma que todos los valores a promediar
llegan a la función en una sola variable, digamos v, y que también recibe la cantidad de valores a promediar,
def promedio(v, c):
# promedio de los primeros c > 0 valores en v
p = 0.0 # promedio
i = 0 # índice o posición en v
while i < c:
s = s + v[i]
i = i + 1
return p/c
Si c es 5, el ciclo se ejecuta 5 veces, sumando los valores en las posiciones 0 a 4 que hay en v. Luego de
salir del ciclo se retorna la suma dividida por c (la cantidad de valores sumados) que es el promedio de los c
valores.
Es claro que c no puede ser 0, porque entonces no se podría efectuar la división para calcular el promedio,
por eso estamos suponiendo que c es mayor 0.
13
Así que tenemos una función definitiva para promediar una cantidad arbitraria de valores, siempre que lleguen
todos dentro de una sola variable, que en este ejemplo se llama v en el código de la función.
Consideremos una función leeVal() que permita al usuario introducir los c valores en la variable v,
def leeVal(v, c):
# lee c valores y los coloca en primeras c posiciones de v
i = 0.0 # indice o posición en v
while i < c:
v[i] = input()
i = i + 1
return v
El ciclo se ejecuta c veces y cada vez se lee un valor, el cual es colocado en una posición de la variable v,
desde la 0 a la c-1, que son c posiciones de otros tantos valores.
La función leeVal() retorna la misma variable v, pero ahora con las primeras c posiciones pobladas con los c
valores recién dados por el usuario.
Veamos ahora un programa que calcule el promedio de c números y que use las funciones leeVal() y
promedio().
# promedia c valores
c = input() # cantidad de valores a promediar, c > 0
v = [0.0 for i in range(c)] # variable para alojar c números
v = leeVal(v, c)
print promedio(v, c)
Se lee la cantidad de valores a promediar, que se asume es un número entero mayor que 0. Se define la
variable v para alojar c valores. Se invoca la función leeVal() para poblar la variable v con c números que
ingrese el usuario, y se reciben los c valores en la misma variable v. Se escribe el valor del promedio de los v
valores, enviados junto con c a la función promedio.
Una ventaja de descomponer esta solución en un programa que usa dos funciones, es que tales funciones se
convierten en recursos genéricos y flexibles que pueden reutilizarse en la solución de otros problemas sin
tener que hacerles cambio alguno, es decir, cada una es una solución general a un problema particular, que
puede ser una parte de la solución de otro problema, como ocurrió con las funciones primo(), perfecto() y
feo().
He aquí el programa completo, incluyendo las dos funciones auxiliares,
14
# promedia c valores
def leeVal(v, c):
# lee c valores y los coloca en primeras c posiciones de v
i = 0.0 # índice o posición en v
while i < c:
v[i] = input()
i = i + 1
return v
def promedio(v, c):
# promedio de los primeros c > 0 valores en v
p = 0.0 # promedio
i = 0
# índice o posición en v
while i < c:
s = s + v[i]
i = i + 1
return p/c
c = input() # cantidad de valores a promediar, c > 0
v = [0.0 for i in range(c)] # variable para alojar c números
v = lleva(v, c)
print promedio(v, c)
Hasta aquí el Python esencial.
ecabrera, sdqdr, junio 2015
15