En este capítulo se completa el repaso de las estructuras iterativas, con algunos ejemplos donde se programan series de Taylor y se emplea la estructura for para resolver problemas que implican sumatorias/productorias.
En este ejemplo se elabora una función que calcula el exponente de un número "x", empleando la serie de Taylor respectiva:
| \[ \text{e}^x = 1+x+\dfrac{x^2}{2!}+\dfrac{x^3}{3!}+\dfrac{x^4}{4!}+\dots + \infty \] |
En consecuencia, el problema se reduce a calcular el valor de una sumatoria, sin embargo, como las series de Taylor son sumatorias infinitas, no es posible calcularlas directamente. En su lugar se sigue un proceso iterativo: a) Se calcula y asigna el primer término de la serie a la variable "ter"; b) Se inicia el valor de la sumatoria "s1" en el primer término "ter" de la serie (s1=ter); c) Se calcula el nuevo término de la serie "ter", empleando su valor anterior (ter = ter*...); d) Con "s1" y el nuevo término de la serie "ter", se calcula el nuevo valor de la serie "s2" (s2 = s1+ter); e) Se compara el valor anterior de la serie "s1", con el valor nuevo "s2" (Math.abs(s1/s2-1)<1e-n); f) Si "s1" y "s2" son iguales en el número "n" de dígitos establecido, el proceso termina, siendo la solución el valor de "s2"; f) Caso contario, "s1" toma el valor de "s2" (s1 = s2), se actualizan variables y se repite el proceso desde el paso c.
En consecuencia, para resolver una serie, básicamente el problema radica en deducir la regla que permite calcular el nuevo término en base a su término anterior.
Para ello se analizan dos términos consecutivos. Por ejemplo (en el caso del exponente) el cálculo del cuarto término, en base al tercero, requiere las siguientes operaciones:
| \[ \dfrac{x^3}{3!} \cdot \dfrac{x}{4} = \dfrac{x^4}{4!} \] |
Y para calcular el quinto, en base al cuarto, las siguientes:
| \[ \dfrac{x^4}{4!} \cdot \dfrac{x}{5} = \dfrac{x^5}{5!} \] |
Por tanto, el nuevo término se calcula multiplicando el término anterior por \(\dfrac{x}{i}\). Al multiplicar el numerador por "x" se consigue la siguiente potencia (porque xn = xn-1*x1) y al multiplicar el denominador por "i" se consigue el siguiente factorial (porque n! = (n-1)!*n). El contador "i" (en este caso) debe iniciar en 1 e incrementar en 1 en cada iteración.
Siempre que se pueda, en las series infinitas se deben evitar las restas, porque en las series los números crecen rápidamente y la resta de números muy grandes producen errores de redondeo muy grandes, dando lugar a resultados erróneos. Si no es posible evitar las restas se debe tratar de trabajar con números o muy grandes o muy pequeños.
En el caso del exponente, si el número (x) es negativo, las potencias impares son negativas y en consecuencia en la serie aparecen restas. Para evitar las restas, se trabaja con el valor positivo del número. En este caso es posible hacerlo porque en las potencias se cumple que:
| \[ \text{e}^{-x} = \dfrac{1}{\text{e}^x} \] |
Entonces, si el número es negativo, se trabaja con el valor positivo y antes de devolver el resultado, si el número era negativo en se devuelve la inversa del resultado calculado, caso contrario se devuelve el valor resultado calculado. Sin embargo, se aclara que esta relación sólo es válida para las potencias. No puede ser empleada en otros casos.
El código respectivo, empleando la estructura do-while y el comando break, es:
Llamando a la función, con los valores de prueba, se obtienen los resultados correctos:
En este ejemplo se programa una función que recibe un ángulo en radianes y devuelve el seno de ese ángulo, empleando la serie de Taylor:
| \[ \sin(x) = x-\dfrac{x^3}{3!}+\dfrac{x^5}{5!}-\dfrac{x^7}{7!} +\cdots \infty \] |
Como en el ejemplo anterior, el problema radica en deducir la regla que permite calcular un nuevo término en base al anterior. Por ejemplo, para calcular el tercer término, a partir del segundo, las operaciones son:
| \[ -\dfrac{x^3}{3!} \cdot \left( -\dfrac{x^2}{4 \cdot 5}\right) = \dfrac{x^5}{5!} \] |
Y para calcular el cuarto término, a partir del tercero, las operaciones son:
| \[ \dfrac{x^5}{5!} \cdot \left( -\dfrac{x^2}{6 \cdot 7}\right) = -\dfrac{x^7}{7!} \] |
De donde se deduce que el nuevo término se calcula multiplicando el término anterior por:
| \[ \left(-\dfrac{x^2}{i \cdot j}\right) \] |
Donde el signo negativo hace que el símbolo intercale (en cada iteración) de positivo a negativo y viceversa, "i" y "j" son dos contadores que comienzan en 2 y 3 y que incrementan de 2 en 2 en cada repetición del ciclo. Por supuesto, en lugar de dos contadores, se puede emplear solo uno "i", cambiando las operaciones del denominador por: i*(i+1).
En este caso las potencias son impares y la serie en sí tiene restas, por lo que no es posible evitarlas. Pero, para reducir los errores de redondeo, se puede evitar trabajar con números muy grandes, recordando que las funciones trigonométricas son cíclicas y un ángulo mayor o igual a 360 grados (mayor a 2*π), puede ser reducido a su equivalente entre 0 y 360 grados (entre 0 y 2*π), simplemente trabajando con el residuo de su división entre 2*π.
La función estándar que resuelve el problema, empleando la estructura for y el comando break, es:
Llamando a la función con los valores de prueba, se obtiene:
La función flecha que resuelve el problema, empleando un solo contador, la estructura while y el comando break con la estructura try-catch, es:
Con la cual, por supuesto, se obtienen los mismos resultados.
En este ejemplo se programa un método para calcular el resultado de la siguiente productoria:
| \[ \prod_{x=1,2,3}^{n} \prod_{y=1,3,5}^{m}{\sqrt[3]{x+y}} \] |
La solución de problemas que implican productorias o sumatorias con límites definidos, como en este ejemplo, puede ser implementada directamente con la estructura for: el contador de la productoria es el contador del ciclo, el límite inferior es el valor inicial del contador, el límite superior es el valor final del contador (la condición de finalización del ciclo), la diferencia entre dos valores consecutivos es el incremento del ciclo y la expresión dentro de la productoria (en este ejemplo la raíz cúbica), es la instrucción a programar dentro del ciclo interno.
Adicionalmente, si se trata de una productoria, el acumulador tiene que iniciar en 1 (el número neutro de la multiplicación), mientras que si es una sumatoria, el acumulador tiene que iniciar en 0 (el número neutro de la suma).
Así, en este ejemplo, al ser dos productorias, se requieren dos ciclos for anidados, con dos acumuladores: "p1" para el ciclo externo y "p2" para el interno. El contador del ciclo externo es "x" y va desde 1 hasta "n", con un incremento de uno en uno, mientras que el contador del ciclo interno es "y" y va desde 1 hasta "m", con un incremento de dos en dos.
La función anónima que resuelve el problema, es:
Llamando al método con algunos valores de prueba, se obtiene: