Construcción de una calculadora I

Contenidos

Introducción

Vamos a usar el método de Newton para construir una calculadora sencilla que calcule, de momento, el inverso, la raíz cuadrada y la raíz cúbica de un número dado.

Solo se podrán usar sumas, restas y multiplicaciones para aproximar el resultado.

Para la interfaz vamos a usar PyQt, un "biding" de Python para Qt. El código del modelo, implementando una calculadora sencilla se puede bajar aquí (Qt4) y aquí (Qt5 ).

Comprueba la versión que necesitas escribiendo en el terminal

$ qmake --version

Una vez guardado el fichero en una carpeta, abrir el terminal y ejecutarlo:

$ python calculadora0_Qt4.py

Cálculo del inverso de un número

El ejercicio consiste en sustituir la función división "/" en calculadora0.py por una función definida por el alumno basada en el método de Newton que sólo utilice sumas y multiplicaciones.

Después de la suma y la multiplicación, la siguiente operación de bajo nivel entre dos números es la división.

Para calcular $\displaystyle\frac{a}{b}$ haremos $\displaystyle\frac{a}{b} = a \frac{1}{b}$ (multiplicación de dos números).

Entonces, para calcular $\displaystyle\frac{1}{b}$ definimos la función $\displaystyle f(x) = \frac{1}{x} -b$, de forma que $\displaystyle f(\alpha) = 0$ implica $ \displaystyle \alpha = \frac{1}{b}$.

Se puede deducir facilmente que entonces, la fórmula iterativa correspondiente para calcular la raíz de $f(x)=0$. La función de iteración de Newton será

$$ g(x)=x-\frac{f(x)}{f'(x)} = x-\frac{\frac{1}{x} -b}{-\frac{1}{x^2}} = x-\frac{x-bx^2}{-1} = x+(x-bx^2)=2x-bx^2=x(2-bx) $$

es decir, podemos obtener el inverso de $b$ utilizando la sucesión

$$ x_{n+1} = x_n (2-b x_n), $$

que sólo utiliza sumas y multiplicaciones.

La convergencia del método de Newton depende de la elección del dato inicial $x_0$. ¿Cómo lo elegimos?

La fórmula de arriba se corresponde con una iteración de punto fijo de la función $g(x) = x(2-bx)$. Por lo tanto, si $\left|g'(x)\right| < 1$ sabemos que el método es convergente. Esto nos lleva a establecer la condición

$$ \frac{1}{2b} < x_0 < \frac{3}{2b},$$

y entonces, un buen punto inicial es el inverso de la potencia de diez mayor que el número más cercana.

Por ejemplo, si $b=345$, tomamos $x_0 = 0.001$, porque $0.001$ es el inverso de $1000$, que es la potencia de diez mayor más cercana por arriba al número, $345\lt 1000 = 10^3$. Aunque la condición suficiente no se satisface en este caso, no está lejos de cumplirse.


Ejercicio 1

Escribir una función que calcule el inverso de un número por el método de Newton. De momento, escribir la función de Python que calcula el inverso. Guardarla en un fichero llamado libCalculadora.py (vamos a ir almacenando en este fichero las funciones para la calculadora).

El argumento de entrada debe ser un string que contenga el número, como '-73.034' y la salida debe ser un número en punto flotante. Como criterio de parada, usar el error absoluto entre dos iteraciones con tolerancia tol = 1.e-16.

La primera parte es calcular el punto inicial, $x_0$. Será siempre una potencia de $10$, donde la potencia es un entero con signo determinado por el "orden" de $b$.

Para ello:

  • Quita el signo del string (si lo tiene) y guarda su valor como 1 ó -1 en una variable.
  • Localiza el punto del número (si lo tiene)
    • Si no hay punto, estudia si tiene ceros a la izquierda $b=003456$ y quítaselos. Una vez quitados, el número es entero y su orden es el número de dígitos. Por ejemplo, para $b=345$ el orden es $e=3$.
    • Si el punto está en la primera posición, como en $.0023$, entonces tenemos que localizar la posición del primer dígito no nulo y definir la $e$ correspondiente. Por ejemplo, para $.0023$ se tiene que $e=-2$.
    • Si el punto está en otra posición, y hay ceros antes del punto, como en $0.0023$ o en $000.0023$, tenemos que localizar la posición del primer dígito distinto de cero y definir el $e$ correspondiente.
    • En otro caso, el número contiene una parte entera distinta de cero. Debemos contar cuantos dígitos contiene. Por ejemplo, $b=34.2321$ or $b=0034.2321$, tenemos $e=2$
  • Definimos $x_0 = 10^{-e}$

La segunda parte es usar el método de Newton para aproximar la raíz de la función $f(x)$ dada anteriormente, utilizando, para ello la función de iteración de punto fijo $g(x)=x(2-bx)$. Cuando se dé el resultado, recordar multiplicar por el signo del argumento de entrada.

Un ejemplo de ejecución de la función es la siguiente:

In [1]:
from libCalculadora import inverso    # Función inversa contenida en nuestro módulo libCalculadora
numero0 = '-0.02'
x0 = inverso(numero0)
signo = -1
primer dígito distinto de cero (sin contar el signo) = 3
exponente = -1
punto inicial = 10.000000
número de iteraciones (Newton) = 9
solución = -50.000000

Más ejemplos:

In [2]:
numero0 = '-.02'
x0 = inverso(numero0)
signo = -1
primer dígito distinto de cero (sin contar el signo) = 2
exponente = -1
punto inicial = 10.000000
número de iteraciones (Newton) = 9
solución = -50.000000
In [3]:
numero0 = '-0000.01'
x0 = inverso(numero0)
signo = -1
primer dígito distinto de cero (sin contar el signo) = 6
exponente = -1
punto inicial = 10.000000
número de iteraciones (Newton) = 11
solución = -100.000000
In [4]:
numero0 = '-0.01'
x0 = inverso(numero0)
signo = -1
primer dígito distinto de cero (sin contar el signo) = 3
exponente = -1
punto inicial = 10.000000
número de iteraciones (Newton) = 11
solución = -100.000000
In [5]:
numero0 = '-23.01'
x0 = inverso(numero0)
signo = -1
primer dígito distinto de cero (sin contar el signo) = 0
exponente = 2
punto inicial = 0.010000
número de iteraciones (Newton) = 9
solución = -0.043459
In [6]:
numero0 = '-0023.01'
x0 = inverso(numero0)
signo = -1
primer dígito distinto de cero (sin contar el signo) = 2
exponente = 2
punto inicial = 0.010000
número de iteraciones (Newton) = 9
solución = -0.043459

Ejercicio 2

Usar la función del ejercicio anterior para empezar a construir la calculadora sustituyendo la función "/" en calculadora0.py por la función inverso. Llamar a este programa calculadoraNewton.py.

Cálculo de la raíz cuadrada y cúbica


Ejercicio 3

Continuar la construcción de la calculadora añadiéndole la raíz cuadrada y la cúbica. Guardar las funciones correspondientes en el fichero libCalculadora.py. Recordar que sólo se pueden usar sumas y multiplicaciones. Por lo tanto, para la división, usar la función definida para calcular el inverso de un número.

Una vez construídas las funciones, añadir los botones correspondientes en el fichero calculadoraNewton.py.