{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\"AeroPython\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Ejercicios bucles y condicionales" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "_Vamos a afianzar los conocimientos de Python que acabamos de adquirir haciendo algunos ejercicios, y así retener las peculiaridades de la sintaxis y aclarar algunos detalles a tener en cuenta cuando se trabaja en modo interactivo._" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Ejercicio 1: Sumatorio" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Vamos a escribir ahora una función que sume los `n` primeros números naturales. Observa que podemos escribir una **cadena de documentación** (_docstring_) justo debajo de la definición de la función para explicar lo que hace." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def sumatorio(num):\n", " \"\"\"Suma los `num` primeros números.\n", "\n", " Ejemplos\n", " --------\n", " >>> sumatorio(4)\n", " 10\n", "\n", " \"\"\"\n", " suma = 0\n", " for nn in range(1, num + 1):\n", " suma = nn + suma\n", " return suma" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lo que hemos hecho ha sido inicializar el valor de la suma a 0 e ir acumulando en ella los `num` primeros números naturales." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "10" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sumatorio(4)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on function sumatorio in module __main__:\n", "\n", "sumatorio(num)\n", " Suma los `num` primeros números.\n", " \n", " Ejemplos\n", " --------\n", " >>> sumatorio(4)\n", " 10\n", "\n" ] } ], "source": [ "help(sumatorio)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Observa lo que sucede si no inicializamos la suma:
" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def sumatorio_mal(num):\n", " for nn in range(1, num + 1):\n", " suma = nn + suma\n", " return suma" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "ename": "UnboundLocalError", "evalue": "local variable 'suma' referenced before assignment", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mUnboundLocalError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0msumatorio_mal\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m4\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m\u001b[0m in \u001b[0;36msumatorio_mal\u001b[0;34m(num)\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0msumatorio_mal\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnum\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mnn\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnum\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0msuma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnn\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0msuma\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0msuma\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mUnboundLocalError\u001b[0m: local variable 'suma' referenced before assignment" ] } ], "source": [ "sumatorio_mal(4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Para comprobar el resultado correcto, nada como acudir a la función `sum` de Python, que suma los elementos que le pasemos:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[1, 2, 3, 4]" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(range(1, 4 + 1))" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "10" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sum(range(1, 4 + 1))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Ejercicio 2: Sumatorio con cota superior" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ahora nuestra función es un poco más rara: tiene que sumar números naturales consecutivos y no pasarse de un determinado límite. Además, queremos el valor de la suma." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def suma_tope(tope):\n", " \"\"\"Suma números naturales consecutivos hasta un tope.\n", "\n", " \"\"\"\n", " suma = 0\n", " nn = 1\n", " while suma + nn <= tope:\n", " suma = suma + nn\n", " nn += 1\n", " return suma" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "6" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "suma_tope(9)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "suma_tope(9) == 1 + 2 + 3" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "suma_tope(10) == 1 + 2 + 3 + 4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "La palabra clave `assert` recibe una expresión verdadera o falsa, y falla si es falsa. Si es verdadera no hace nada, con lo cual es perfecto para hacer comprobaciones a mitad del código que no estorben mucho." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [], "source": [ "assert suma_tope(11) == 1 + 2 + 3 + 4" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "ename": "AssertionError", "evalue": "", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0msuma_tope\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m10\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m1\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m2\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m3\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m4\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAssertionError\u001b[0m: " ] } ], "source": [ "assert suma_tope(10 + 5) == 1 + 2 + 3 + 4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Ejercicio 3: Normativa de exámenes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "La normativa de exámenes es: *\"si un examen dura más de 3 horas, entonces debe tener un descanso\"*. Los argumentos de la función son el tiempo en horas y un valor `True` o `False` que indica si hay descanso o no." ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def cumple_normativa(tiempo, descanso):\n", " \"\"\"Comprueba si un examen cumple la normativa de la UPM.\n", "\n", " \"\"\"\n", " if tiempo <= 3:\n", " return True\n", " else:\n", " #if descanso:\n", " # return True\n", " #else:\n", " # return False\n", " return descanso # ¡Equivalente!" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cumple_normativa(2, False)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "¡Habla con DA!\n" ] } ], "source": [ "if not cumple_normativa(5, descanso=False):\n", " print(\"¡Habla con DA!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Ejercicio 4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Hallar $x = \\sqrt{S}$.\n", "\n", "1. $\\displaystyle \\tilde{x} \\leftarrow \\frac{S}{2}$.\n", "2. $\\displaystyle \\tilde{x} \\leftarrow \\frac{1}{2}\\left(\\tilde{x} + \\frac{S}{\\tilde{x}}\\right)$.\n", "3. Repetir (2) hasta que se alcance un límite de iteraciones o un criterio de convergencia.\n", "\n", "http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def raiz(S):\n", " x = S / 2\n", " while True:\n", " temp = x\n", " x = (x + S / x) / 2\n", " if temp == x:\n", " return x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Aquí estoy usando un truco de la aritmética en punto flotante: como la convergencia se alcanza rápidamente, llega un momento en que el error es menor que la precisión de la máquina y el valor no cambia de un paso a otro." ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "3.162277660168379" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "raiz(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Se deja como ejercicio implementar otras condiciones de convergencia: error relativo por debajo de un umbral o número máximo de iteraciones.
" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "3.1622776601683795" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import math\n", "math.sqrt(10)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "9.999999999999998" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "raiz(10) ** 2" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "10.000000000000002" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "math.sqrt(10) ** 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ahora tienes curiosidad, ¿verdad? :) http://puntoflotante.org/" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Ejercicio 5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Secuencia de Fibonacci: $F_n = F_{n - 1} + F_{n - 2}$, con $F_0 = 0$ y $F_1 = 1$.\n", "\n", "$$0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Con iteración:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def fib(n):\n", " a, b = 0, 1\n", " for i in range(n):\n", " a, b = b, a + b # Bendita asignación múltiple\n", " return a" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(0, 2, 55)" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fib(0), fib(3), fib(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Con recursión:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def fib_recursivo(n):\n", " if n == 0:\n", " res = 0\n", " elif n == 1:\n", " res = 1\n", " else:\n", " res = fib_recursivo(n - 1) + fib_recursivo(n - 2)\n", " return res" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Imprimir una lista con los $n$ primeros:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def n_primeros(n):\n", " F = fib_recursivo\n", " lista = []\n", " for ii in range(n):\n", " lista.append(F(ii))\n", " return lista" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "n_primeros(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Ejericio 6 Ley d'Hondt " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Implementar el sistema de reparto de escaños d'Hondt. Dicho sistema se basa en ir repartiendo escaños consecutivamente al partido con el máximo coeficiente, $c_i = \\frac{V_i}{s_i + 1}$, donde $V_i$ es el número total de votos obtenido por del partido $i$, mientras que $s_i$ es el número de escaños asignados dicho partido (0 al comenzar el reparto).\n", "\n", "Veamos por ejemplo el caso expuesto en [Wikipedia](https://es.wikipedia.org/wiki/Sistema_d'Hondt):\n", "\n", "| *Partido* | Partido A | Partido B | Partido C | Partido D | Partido E |\n", "|:----------|----------:|----------:|----------:|----------:|----------:|\n", "| *Votos* | 340000 | 280000 | 160000 | 60000 | 15000 |\n", "\n", "Todavía no hay ningún escaño asignado, así que los votos de cada partido se dividen por 1:\n", "\n", "| *Partido* | Partido A | Partido B | Partido C | Partido D | Partido E |\n", "|:-----------|-----------:|-----------:|-----------:|-----------:|-----------:|\n", "| *Votos* | 340000 | 280000 | 160000 | 60000 | 15000 |\n", "| *Escaño 1* | **340000** | 280000 | 160000 | 60000 | 15000 |\n", "\n", "Y por tanto el partido A recibe el primer escaño. Para repartir el segundo escaño se vuelven a dividr por 1 los votos de cada partido, salvo el partido A que se divide por 2, pues ya tiene un escaño:\n", "\n", "| *Partido* | Partido A | Partido B | Partido C | Partido D | Partido E |\n", "|:-----------|-----------:|-----------:|-----------:|-----------:|-----------:|\n", "| *Votos* | 340000 | 280000 | 160000 | 60000 | 15000 |\n", "| *Escaño 1* | **340000** | 280000 | 160000 | 60000 | 15000 |\n", "| *Escaño 2* | 170000 | **280000** | 160000 | 60000 | 15000 |\n", "\n", "Así pues, el segundo escaño va para el partido B. Si se reparten 7 escaños como en el ejemplo de Wikpedia, la tabla final quedaría como sigue:\n", "\n", "| *Partido* | Partido A | Partido B | Partido C | Partido D | Partido E |\n", "|:-----------|-----------:|-----------:|-----------:|-----------:|-----------:|\n", "| *Votos* | 340000 | 280000 | 160000 | 60000 | 15000 |\n", "| *Escaño 1* | **340000** | 280000 | 160000 | 60000 | 15000 |\n", "| *Escaño 2* | 170000 | **280000** | 160000 | 60000 | 15000 |\n", "| *Escaño 3* | **170000** | 140000 | 160000 | 60000 | 15000 |\n", "| *Escaño 4* | 113333 | 140000 | **160000** | 60000 | 15000 |\n", "| *Escaño 5* | 113333 | **140000** | 80000 | 60000 | 15000 |\n", "| *Escaño 6* | **170000** | 93333 | 80000 | 60000 | 15000 |\n", "| *Escaño 7* | 85000 | **93333** | 80000 | 60000 | 15000 |\n", "\n", "Así que los partidos A y B obtendrían 3 escaños, mientras que el partido C obtendría 1 único escaño, quedando el resto de partidos fuera del proceso." ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def hondt(votos, n):\n", " s = [0] * len(votos)\n", " for i in range(n):\n", " c = [v[j] / (s[j] + 1) for j in range(len(s))]\n", " s[c.index(max(c))] += 1\n", " return s" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[3, 3, 1, 0, 0]" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v = [340000, 280000, 160000, 60000, 15000]\n", "n = 7\n", "hondt(v, n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "_En esta clase hemos visto cómo crear funciones que encapsulen tareas de nuestro programa y las hemos aplicado para respondernos ciertas preguntas sencillas._\n", "\n", "**Referencias**\n", "\n", "* Libro \"Learn Python the Hard Way\" http://learnpythonthehardway.org/book/\n", "* Python Tutor, para visualizar código Python paso a paso http://pythontutor.com/\n", "* Libro \"How To Think Like a Computer Scientist\" http://interactivepython.org/runestone/static/thinkcspy/toc.html\n", "* Project Euler: ejercicios para aprender Python https://projecteuler.net/problems\n", "* Python Challenge (!) http://www.pythonchallenge.com/" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "
\n", "####

¡Síguenos en Twitter!\n", "
\n", "###### Follow @AeroPython \n", "
\n", "###### Este notebook ha sido realizado por: Juan Luis Cano, Jose Luis Cercós y Álex Sáez \n", "
\n", "##### \"Licencia
Curso AeroPython por Juan Luis Cano Rodriguez y Alejandro Sáez Mollejo se distribuye bajo una Licencia Creative Commons Atribución 4.0 Internacional." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "_Las siguientes celdas contienen configuración del Notebook_\n", "\n", "_Para visualizar y utlizar los enlaces a Twitter el notebook debe ejecutarse como [seguro](http://ipython.org/ipython-doc/dev/notebook/security.html)_\n", "\n", " File > Trusted Notebook" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "/* This template is inspired in the one used by Lorena Barba\n", "in the numerical-mooc repository: https://github.com/numerical-mooc/numerical-mooc\n", "We thank her work and hope you also enjoy the look of the notobooks with this style */\n", "\n", "\n", "\n", "El estilo se ha aplicado =)\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Esta celda da el estilo al notebook\n", "from IPython.core.display import HTML\n", "css_file = '../styles/aeropython.css'\n", "HTML(open(css_file, \"r\").read())" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python [default]", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.5.2" } }, "nbformat": 4, "nbformat_minor": 0 }