Métodos iterativos 2

Con frecuencia, la lógica que resuelve el problema no se ajusta al flujo estándar de las estructuras iterativas. Por esa razón, la mayoría de los lenguajes (incluido JavaScript), cuentan con comandos que permiten alterar el flujo normal de las estructuras de control.

Dos de estos modificadores son: break y continue. El comando break, interrumpe inmediatamente la ejecución del ciclo y sale de la estructura iterativa. Continue, igualmente, interrumpe inmediatamente la ejecución del ciclo actual, pero no sale de la estructura iterativa, sino que pasa a ejecutar el siguiente ciclo de la estructura.

Aunque no son modificadores propiamente, los comandos return y throw, interrumpen igualmente la ejecución de cualquier estructura, por lo que pueden ser empleados para interrumpir, inmediatamente, la ejecución de cualquier ciclo o estructura (como se ha visto, por ejemplo, en la estructura switch).

El comando return, no sólo interrumpe la ejecución de la instrucción, sino también el de la función y devuelve el resultado de la misma.

De manera similar, el comando throw, no sólo interrumpe la ejecución de la instrucción, sino que además lanza un error, el cual puede ser atrapado (con catch) en la misma función o fuera de ella.

La modificación más frecuente corresponde a la siguiente lógica:

gojsGraph({divi, modelo: {"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Conditional","text":"condición","key":-5,"loc":"60.00000000000001 -272.7375317152156"},{"category":"Process","text":"instrucciones a","key":-2,"loc":"60.00000000000001 -335.0375675733699"},{"category":"Connector","text":"...","key":-8,"loc":"60 -392"},{"category":"Connector","text":"...","key":-4,"loc":"59.99999999999999 -118.4083489528922"},{"category":"Process","text":"instrucciones b","key":-6,"loc":"60.00000000000001 -195.37078137952224"}],"linkDataArray":[{"from":-8,"to":-2,"fromPort":"B","toPort":"T","points":[60,-377.3042461927547,60,-367.3042461927547,60,-364.8042461927547,60,-364.8042461927547,60,-362.3042461927547,60,-352.3042461927547]},{"from":-2,"to":-5,"fromPort":"B","toPort":"T","points":[60,-317.77088895398515,60,-307.77088895398515,60,-305.27088895398515,60,-305.27088895398515,60,-302.77088895398515,60,-292.77088895398515]},{"from":-5,"to":-6,"fromPort":"B","toPort":"T","visible":true,"points":[60,-252.7041744764461,60,-242.7041744764461,60,-232.67081723767654,60,-232.67081723767654,60,-222.63745999890702,60,-212.63745999890702],"text":"No"},{"from":-5,"to":-4,"fromPort":"R","toPort":"T","visible":true,"points":[124.49705505371094,-272.7375317152156,134.49705505371094,-272.7375317152156,163,-272.7375317152156,163,-157.79999923706055,60,-157.79999923706055,60,-143.1041027601375,60,-133.1041027601375],"text":"Si"},{"from":-6,"to":-2,"fromPort":"L","toPort":"L","points":[3.1953659057617188,-195.37078137952224,-6.804634094238281,-196.58539030829138,-49,-196.58539030829138,-49,-335.0375675733699,-6.4234771728515625,-335.0375675733699,3.5765228271484375,-335.0375675733699]}]} })

Es decir que las "instrucciones a" y las instrucciones "b" se repiten mientras la condición es falsa (No), pero la condición de finalización no está ni al principio (while) ni al final (do-while), sino al medio de las instrucciones.

Para implementar esta modificación, se crea un ciclo infinito y en su interior se escribe la condición de finalización, donde se emplea uno de los modificadores: break, return o throw, para salir del ciclo. Un ciclo infinito se crea simplemente escribiendo true en su condición (de esa manera la condición es siempre verdadera y en consecuencia, el ciclo se repite siempre):

while(true) { instrucciones a if (condición) [break|return|throw] instrucciones b }
do { instrucciones a if (condición) [break|return|throw] instrucciones b } while(true);

La estructura for cuenta con una sintaxis abreviada para crear un ciclo infinito:

for(;;) { instrucciones a if (condición) [break|return|throw] instrucciones b }

Tratamiento de errores

Hasta ahora, los errores lanzados en las funciones, han sido atrapados y mostrados por la calculadora JavaScript. En la práctica, esos errores deben ser atrapados en el método (o función) que los genera o, más frecuentemente, en el método o función que llama al método que lanza el error.

Los errores lanzados con throw son atrapado con catch, empleando la estructura try-catch-finally, que tiene la siguiente sintaxis:

try { instrucciones 1; } catch(e) { instrucciones 2; } finally { instrucciones 3; }

Donde instrucciones 1 son las instrucciones que resuelven el problema (las instrucciones que se escriben normalmente para resolver el problema); catch inicia el bloque donde se atrapa el error, siendo "e" el nombre de la variable temporal que guarda el error generado, instrucciones 2 son las instrucciones que se ejecutan cuando se atrapa el error y donde se puede emplear la variable temporal "e"; finally inicia el bloque de instrucciones (instrucciones 3) que se ejecutan siempre, sin importar si se ha lanzado o no un error.

La forma en que opera esta estructura es la siguiente: Si ocurre un error al ejecutar las instrucciones 1 o se ha lanzado un error en esas instrucciones (con throw), la ejecución se detiene y el programa salta al bloque catch, donde el error es atrapado y guardado en la variable "e", entonces se ejecutan las instrucciones 2. Si no se produce ningún error al ejecutar las instrucciones 1, las instrucciones del bloque catch (las instrucciones 2) son ignoradas. Finalmente, sin importar si se ha producido o no un error, el programa salta al bloque finally y ejecuta las instrucciones 3.

En esta estructura sólo es imprescindible uno de los bloques: o catch o finally, así es válida la forma:

try { instrucciones 1; } catch(e) { instrucciones 2; }

Y también la forma:

try { instrucciones 1; } finally { instrucciones 3; }

Se recalca que si existe el bloque finally, las instrucciones de ese bloque se ejecutan siempre, sin importar si se produce o no un error en el bloque try, mientras que las instrucciones del bloque catch sólo se ejecutan si se produce (o lanza) un error en el bloque try.

Ejemplos

Raíz cuadrada

En este ejemplo, se vuelve a resolver el problema de calcular la raíz cuadrada de un número real positivo, empleando la ecuación iterativa:

\[ x_2 = \dfrac{1}{2} \left( x_1 + \dfrac{n}{x_1}\right) \]

Sin embargo, ahora, se resuelve el problema siguiendo la lógica natural:

gojsGraph({divi, modelo: {"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Start","text":"raizCuadrada","key":-1,"loc":"172 -460"},{"category":"Input","text":"número positivo: n\nvalor asumido: x1(=1.1)","key":-3,"loc":"172 -401.69996414184567"},{"category":"Conditional","text":"n==0 o \nn==1","key":-5,"loc":"171.99999999999994 -321.0998924255372"},{"category":"Output","text":"n","key":-4,"loc":"328.99999999999994 -160.99999999999997"},{"category":"Process","text":"x2 = (x1+n/x1)/2","key":-2,"loc":"34.00000000000005 -271.79999995231645"},{"category":"Conditional","text":"abs(x1/x2-1)\n<1e-10","key":-6,"loc":"34.00000000000003 -191.96660685539257"},{"category":"Process","text":"x1=x2","key":-7,"loc":"34.00000000000001 -102.13321375846866"},{"category":"Start","text":"fin","key":-9,"loc":"171.99999999999994 45.000000000000085"},{"category":"Output","text":"x2","key":-10,"loc":"33.99999999999999 -30"}],"linkDataArray":[{"from":-5,"to":-4,"fromPort":"R","toPort":"T","visible":true,"points":[219.139663696289,-321.0998924255372,229.139663696289,-321.0998924255372,329.00000000000017,-321.0998924255372,329.00000000000017,-254.85551172892252,329.00000000000017,-188.6111310323079,329.00000000000017,-178.6111310323079],"text":"Si"},{"from":-5,"to":-2,"fromPort":"L","toPort":"T","visible":true,"points":[124.86033630371088,-321.0998924255372,114.86033630371088,-321.0998924255372,34.00000000000003,-321.0998924255372,34.00000000000003,-310.0832854986192,34.00000000000003,-299.06667857170123,34.00000000000003,-289.06667857170123],"text":"No"},{"from":-2,"to":-6,"fromPort":"B","toPort":"T","points":[34.00000000000003,-254.53332133293168,34.00000000000003,-244.53332133293168,34.00000000000003,-242.03332133293165,34.00000000000003,-242.03332133293165,34.00000000000003,-239.53332133293162,34.00000000000003,-229.53332133293162]},{"from":-6,"to":-7,"fromPort":"B","toPort":"T","visible":true,"points":[34.00000000000003,-154.3998923778535,34.00000000000003,-144.3998923778535,34.00000000000003,-136.89989237785346,34.00000000000001,-136.89989237785346,34.00000000000001,-129.3998923778534,34.00000000000001,-119.39989237785339],"text":"No"},{"from":-7,"to":-2,"fromPort":"L","toPort":"L","points":[5.357185363769538,-102.13321375846863,-4.642814636230462,-102.13321375846863,-74,-102.13321375846863,-74,-271.79999995231645,-37.67175292968747,-271.79999995231645,-27.67175292968747,-271.79999995231645]},{"from":-1,"to":-3,"fromPort":"B","toPort":"T","points":[172,-444.7333213806152,172,-434.7333213806152,172,-434.7333213806152,172,-434.7333213806153,172.00000000000003,-434.7333213806153,172.00000000000003,-424.7333213806153]},{"from":-3,"to":-5,"fromPort":"B","toPort":"T","points":[172.00000000000003,-378.66660690307623,172.00000000000003,-368.66660690307623,172,-368.66660690307623,172,-368.66660690307623,171.99999999999994,-368.66660690307623,171.99999999999994,-358.66660690307623]},{"from":-4,"to":-9,"fromPort":"B","toPort":"T","points":[329.00000000000017,-148.31998565673823,329.00000000000017,-138.31998565673823,329.00000000000017,6,171.99999999999997,6,171.99999999999997,19.73332138061528,171.99999999999997,29.73332138061528]},{"from":-6,"to":-10,"fromPort":"R","toPort":"T","visible":true,"points":[117.74560546875003,-191.96660685539257,127.74560546875003,-191.96660685539257,155,-191.96660685539257,155,-76,34,-76,34,-57.611131032307945,34,-47.611131032307945],"text":"Si"},{"from":-10,"to":-9,"fromPort":"B","toPort":"T","points":[34,-17.31998565673828,34,-7.319985656738279,34,6.2066678619385005,171.99999999999997,6.2066678619385005,171.99999999999997,19.73332138061528,171.99999999999997,29.73332138061528]}]} })

Donde, como se puede ver, se asume (como es natural) un valor inicial para "x1" (no para "x2").

Al ser un ciclo infinito, el algoritmo puede ser implementado con cualquiera de las estructuras iterativas, así con la estructura while y el comando break, el código añadido directamente como un método de la clase Number, es:

Number.prototype.raizCuadrada = function(x1=1.1) {
const n = this.valueOf();
if (n<0) throw new Error("El número debe ser positivo");
if (n===0 || n===1) return n;
let x2;
while (true) {
x2 = (x1+n/x1)/2;
if (Math.abs(x1/x2-1)<1e-10) break;
x1 = x2;
}
return x2;
};

En este caso, el método no puede ser getter, porque recibe un valor adicional: el valor inicial asumido (x1=1.1). Llamando al método con algunos valores de prueba, se obtiene:

(2).raizCuadrada()
(9.34).raizCuadrada()
(1).raizCuadrada()
(-7.45).raizCuadrada()

El mismo algoritmo implementado con la estructura do-while y el comando return, es:

Number.prototype.raizCuadrada = function(x1=1.1) {
const n = this.valueOf();
if (n<0) throw new Error("El número debe ser positivo");
if (n===0 || n===1) return n;
let x2;
do {
x2 = (x1+n/x1)/2;
if (Math.abs(x1/x2-1)<1e-10) return x2;
x1 = x2;
} while (true);
};

Y con la estructura for y la estructura try-catch, es:

Number.prototype.raizCuadrada = function(x1=1.1) {
const n = this.valueOf();
if (n<0) throw new Error("El número debe ser positivo");
try {
if (n===0 || n===1) return n;
let x2;
for (;;) {
x2 = (x1+n/x1)/2;
if (Math.abs(x1/x2-1)<1e-10) throw x2;
x1 = x2;
}
} catch(e) {
return e;
}
};

En este último ejemplo, para romper el ciclo, se lanza un error (throw) con el resultado calculado (x2), ese error es atrapado por catch en la variable e y devuelto como el resultado de la función. En JavaScript, el comando throw, como se puede ver en este ejemplo, no sólo puede lanzar (devolver) un objeto error (como se ha hecho en los anteriores capítulos), sino cualquier valor JavaScript válido, así, en este ejemplo lanza (devuelve) un número (el valor de la raíz cuadrada).

En una aplicación real, la estructura try-catch-finally, no se emplea para romper un ciclo y devolver un resultado, sino para capturar errores y ejecutar código en respuesta a esos errores, sin embargo, estos ejercicios ayudan a comprender como opera esta estructura y a utilizarla posteriormente en el tratamiento de errores.

Legendre enésimo de un número

En este ejemplo, se vuelve a resolver el problema de calcular el Legendre enésimo "n" de un número "x". La ecuación de definición del Legendre es:

\[ \begin{aligned} \text{Le}_n(x) &= \left( 2-\dfrac{1}{n}\right)\cdot x\cdot \text{Le}_{n-1}(x)-\left( 1-\dfrac{1}{n}\right)\cdot\text{Le}_{n-2}(x)\\ \text{Le}_0(x) &= 1\\ \text{Le}_1(x) &= x \end{aligned} \]

En este caso, como es natural, antes de realizar el cambio de variables, se verifica si dicho cambio será necesario, es decir si es necesario una nueva iteración:

gojsGraph({divi, modelo: {"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Process","text":"i = 2","key":-5,"loc":"-494.29796308782375 -156.1306334603216"},{"category":"Process","text":"i = i+1","key":-6,"loc":"-494.2979630878235 135.40272377844818"},{"category":"Start","text":"legendre","key":-1,"loc":"-331.9273938191614 -469.6705122545327"},{"category":"Start","text":"fin","key":-8,"loc":"-331.9273938191611 137.02945757902523"},{"category":"Input","text":"número real: x\norden (entero positivo): n","key":-3,"loc":"-331.9273938191615 -411.37047639637825"},{"category":"Conditional","text":"n==0","key":-4,"loc":"-331.9273938191615 -348.3037619188394"},{"category":"Output","text":"1","key":-12,"loc":"-203.676839362029 -124.32316063797148"},{"category":"Output","text":"le2","key":-13,"loc":"-383.9154855519391 30.67683936202876"},{"category":"Process","text":"le0 = 1","key":-14,"loc":"-494.2979630878238 -265.1973479378606"},{"category":"Process","text":"le1 = x","key":-15,"loc":"-494.29796308782386 -210.66399069909104"},{"category":"Process","text":"le2 = (2-1/i)*x*le1-(1-1/i)*le0","key":-16,"loc":"-494.29796308782375 -101.59727622155208"},{"category":"Process","text":"le0 = le1","key":-17,"loc":"-494.2979630878235 26.33600930090908"},{"category":"Process","text":"le1 = le2","key":-18,"loc":"-494.2979630878235 80.8693665396786"},{"category":"Conditional","text":"n==1","key":-19,"loc":"-414.8427253205203 -307.20773605765766"},{"category":"Output","text":"x","key":-20,"loc":"-331.9273938191614 -124.32316063797154"},{"category":"Conditional","text":"i==n","key":-21,"loc":"-494.29796308782375 -44.297240363397776"}],"linkDataArray":[{"from":-1,"to":-3,"fromPort":"B","toPort":"T","points":[-331.9273938191614,-454.4038336351479,-331.9273938191614,-444.4038336351479,-331.9273938191614,-444.4038336351479,-331.9273938191614,-444.4038336351479,-331.9273938191614,-444.4038336351479,-331.9273938191614,-434.4038336351479]},{"from":-3,"to":-4,"fromPort":"B","toPort":"T","points":[-331.9273938191614,-388.33711915760887,-331.9273938191614,-378.33711915760887,-331.9273938191614,-378.33711915760887,-331.9273938191614,-378.33711915760887,-331.9273938191614,-378.33711915760887,-331.9273938191614,-368.33711915760887]},{"from":-4,"to":-12,"fromPort":"R","toPort":"T","visible":true,"points":[-295.7680615437708,-348.3037619188393,-285.7680615437708,-348.3037619188393,-203.676839362029,-348.3037619188393,-203.676839362029,-250.11902679455937,-203.676839362029,-151.93429167027944,-203.676839362029,-141.93429167027944],"text":"Si"},{"from":-12,"to":-8,"fromPort":"B","toPort":"R","points":[-203.676839362029,-111.64314629470977,-203.676839362029,-101.64314629470977,-203.676839362029,137.0294575790252,-251.0223551702393,137.0294575790252,-298.3678709784496,137.0294575790252,-308.3678709784496,137.0294575790252]},{"from":-13,"to":-8,"fromPort":"B","toPort":"L","points":[-383.9154855519391,43.35685370529048,-383.9154855519391,53.35685370529048,-383.9154855519391,52,-383.9154855519391,52,-383.9154855519391,137.0294575790252,-365.4869166598732,137.0294575790252,-355.4869166598732,137.0294575790252]},{"from":-15,"to":-5,"fromPort":"B","toPort":"T","points":[-494.29796308782375,-193.39731207970635,-494.29796308782375,-183.39731207970635,-494.29796308782375,-183.39731207970635,-494.29796308782375,-183.39731207970635,-494.29796308782375,-183.39731207970635,-494.29796308782375,-173.39731207970635]},{"from":-14,"to":-15,"fromPort":"B","toPort":"T","points":[-494.29796308782375,-247.93066931847588,-494.29796308782375,-237.93066931847588,-494.29796308782375,-237.93066931847588,-494.29796308782375,-237.93066931847588,-494.29796308782375,-237.93066931847588,-494.29796308782375,-227.93066931847588]},{"from":-4,"to":-19,"fromPort":"L","toPort":"T","visible":true,"points":[-368.08672609455203,-348.3037619188393,-378.08672609455203,-348.3037619188393,-414.8427253205203,-348.3037619188393,-414.8427253205203,-342.7724276076333,-414.8427253205203,-337.2410932964272,-414.8427253205203,-327.2410932964272],"text":"No"},{"from":-19,"to":-20,"fromPort":"R","toPort":"T","visible":true,"points":[-378.68339304512966,-307.20773605765766,-368.68339304512966,-307.20773605765766,-331.9273938191614,-307.20773605765766,-331.9273938191614,-229.57101386396855,-331.9273938191614,-151.93429167027944,-331.9273938191614,-141.93429167027944],"text":"Si"},{"from":-19,"to":-14,"fromPort":"L","toPort":"T","visible":true,"points":[-451.0020575959109,-307.20773605765766,-461.0020575959109,-307.20773605765766,-494.29796308782375,-307.20773605765766,-494.29796308782375,-299.83588130745153,-494.29796308782375,-292.4640265572454,-494.29796308782375,-282.4640265572454],"text":"No"},{"from":-20,"to":-8,"fromPort":"B","toPort":"T","points":[-331.9273938191614,-111.64314629470977,-331.9273938191614,-101.64314629470977,-331.9273938191614,5.059816332465331,-331.9273938191614,5.059816332465331,-331.9273938191614,111.76277895964043,-331.9273938191614,121.76277895964043]},{"from":-5,"to":-16,"fromPort":"B","toPort":"T","points":[-494.29796308782375,-138.86395484093683,-494.29796308782375,-128.86395484093683,-494.29796308782375,-128.86395484093683,-494.29796308782375,-128.86395484093683,-494.29796308782375,-128.86395484093683,-494.29796308782375,-118.86395484093683]},{"from":-16,"to":-21,"fromPort":"B","toPort":"T","points":[-494.29796308782375,-84.3305976021673,-494.29796308782375,-74.3305976021673,-494.29796308782375,-74.3305976021673,-494.29796308782375,-74.3305976021673,-494.29796308782375,-74.3305976021673,-494.29796308782375,-64.3305976021673]},{"from":-21,"to":-13,"fromPort":"R","toPort":"T","visible":true,"points":[-462.8884782245425,-44.29724036339777,-452.8884782245425,-44.29724036339777,-383.9154855519391,-44.29724036339777,-383.9154855519391,-20.615766016838478,-383.9154855519391,3.065708329720813,-383.9154855519391,13.065708329720813],"text":"Si"},{"from":-21,"to":-17,"fromPort":"B","toPort":"T","visible":true,"points":[-494.29796308782375,-24.263883124628236,-494.29796308782375,-14.263883124628236,-494.29796308782375,-7.597276221551962,-494.2979630878235,-7.597276221551962,-494.2979630878235,-0.9306693184756867,-494.2979630878235,9.069330681524313],"text":"No"},{"from":-17,"to":-18,"fromPort":"B","toPort":"T","points":[-494.2979630878235,43.602687920293846,-494.2979630878235,53.602687920293846,-494.29796308782363,53.602687920293846,-494.29796308782363,53.602687920293846,-494.29796308782375,53.602687920293846,-494.29796308782375,63.602687920293846]},{"from":-18,"to":-6,"fromPort":"B","toPort":"T","points":[-494.29796308782375,98.13604515906337,-494.29796308782375,108.13604515906337,-494.29796308782375,108.13604515906337,-494.29796308782375,108.13604515906337,-494.29796308782375,108.13604515906337,-494.29796308782375,118.13604515906337]},{"from":-6,"to":-16,"fromPort":"L","toPort":"L","points":[-522.1344727924136,135.40272377844815,-532.1344727924136,135.40272377844815,-629,135.40272377844815,-629,-101.59727622155206,-604.9286088397769,-101.59727622155206,-594.9286088397769,-101.59727622155206]}]} })

El código respectivo, implementado como un método de la clase "Legendre", empleando las estructuras while y try-catch, es:

var Legendre = class { constructor(número) { this.num = número; } legendre(n=2) { const x = this.num; if (n%1!==0) throw new Error("El orden debe ser entero"); if (n<0) throw new Error("El orden debe ser positivo"); try { if (n===0) return 1; if (n===1) return x; let le2, le0=1, le1=x, i=2; while (true) { le2 = (2-1/i)*x*le1-(1-1/i)*le0; if (i===n) throw le2; le0 = le1; le1 = le2; i++; } } catch(e) { return e; } }; };

Con el cual se obtienen los resultados esperados:

(new Legendre(1.3)).legendre(2)
(new Legendre(1.5)).legendre(3)
(new Legendre(3.9)).legendre(7)
(new Legendre(2.1)).legendre(0)
(new Legendre(13.1)).legendre(1)
(new Legendre(6.1)).legendre(4.5)
(new Legendre(1.1)).legendre(-3)

Exponente de un número

En este ejemplo, se elabora un método que calcula el exponente de un número "x", aplicando, iterativamente, la siguiente serie de Taylor:

\[ \text{e}^x = 1+x+\dfrac{x^2}{2!}+\dfrac{x^3}{3!}+\dfrac{x^4}{4!}+\dots + \infty \]

Para resolver este tipo de problemas, se emplea un ciclo iterativo, donde, en cada iteración, se calcula y añade un nuevo término a la serie, hasta que, con el último valor añadido, la serie devuelve el mismo valor (o casi el mismo valor) que en la iteración anterior.

La principal dificultad, para programar una serie de Taylor, radica en deducir la regla para calcular el nuevo término de la serie.

Para ello se deben estudiar las operaciones que permiten calcular un nuevo término en base al anterior. Por ejemplo, para calcular el cuarto término, en base al tercero, se llevan a cabo 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!} \]

De donde se deduce que, para calcular un nuevo término, se debe multiplicar el término anterior por \(\dfrac{x}{i}\), siendo "i" un contador igual al número del término que está siendo calculado.

Una vez identificada la regla (prácticamente en todas las series) el algoritmo es el mismo: a) Asignar los valores iniciales a las variables; b) Repetir el ciclo, calculando y añadiendo un nuevo término a la serie, hasta que el último y penúltimo valores son iguales o casi iguales; c) Devolver el resultado calculado (llevando a cabo los cálculos adicionales que fueran necesarios).

El diagrama de flujo que resuelve el problema, es:

gojsGraph({divi, modelo: {"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Process","text":"s1 = ter","key":-5,"loc":"-487.297963087824 -208.13063346032135"},{"category":"Process","text":"i = i+1","key":-6,"loc":"-487.29796308782363 173.33600930090898"},{"category":"Start","text":"exponente","key":-1,"loc":"-331.9273938191614 -469.6705122545327"},{"category":"Start","text":"fin","key":-8,"loc":"-331.72397208529 194.8693665396786"},{"category":"Input","text":"número: y","key":-3,"loc":"-331.9273938191614 -420.1371550157632"},{"category":"Conditional","text":"y==0","key":-4,"loc":"-331.92739381916124 -365.8371191576089"},{"category":"Output","text":"1","key":-12,"loc":"-150.67683936202894 -85.32316063797131"},{"category":"Output","text":"1/s2","key":-13,"loc":"-247.43029420672423 121.6768393620288"},{"category":"Process","text":"x = abs(y)","key":-14,"loc":"-487.29796308782375 -317.1973479378604"},{"category":"Process","text":"ter = 1","key":-15,"loc":"-487.297963087824 -262.6639906990909"},{"category":"Process","text":"s2 = s1+ter","key":-16,"loc":"-487.297963087824 -44.530561744012786"},{"category":"Process","text":"s1 = s2","key":-17,"loc":"-487.29796308782386 118.80265206213954"},{"category":"Conditional","text":"abs(s1/s2-1)\n<1e-14","key":-19,"loc":"-487.297963087824 30.30283135291105"},{"category":"Process","text":"i = 1","key":-20,"loc":"-487.2979630878239 -153.59727622155182"},{"category":"Process","text":"ter = ter*x/i","key":-21,"loc":"-487.297963087824 -99.06391898278231"},{"category":"Conditional","text":"y<0","key":-18,"loc":"-323.97138612566954 71.09906556849037"},{"category":"Output","text":"s2","key":-22,"loc":"-393.91548555193907 121.6768393620288"}],"linkDataArray":[{"from":-1,"to":-3,"fromPort":"B","toPort":"T","points":[-331.9273938191616,-454.40383363514786,-331.9273938191616,-444.40383363514786,-331.92739381916147,-444.40383363514786,-331.92739381916147,-444.403833635148,-331.9273938191614,-444.403833635148,-331.9273938191614,-434.403833635148]},{"from":-3,"to":-4,"fromPort":"B","toPort":"T","points":[-331.9273938191614,-405.8704763963784,-331.9273938191614,-395.8704763963784,-331.92739381916135,-395.8704763963784,-331.92739381916135,-395.8704763963785,-331.92739381916124,-395.8704763963785,-331.92739381916124,-385.8704763963785]},{"from":-4,"to":-12,"fromPort":"R","toPort":"T","visible":true,"points":[-296.41311159259874,-365.8371191576089,-286.41311159259874,-365.8371191576089,-150.67683936202897,-365.8371191576089,-150.67683936202897,-239.38570541394412,-150.67683936202897,-112.93429167027932,-150.67683936202897,-102.93429167027932],"text":"Si"},{"from":-12,"to":-8,"fromPort":"B","toPort":"R","points":[-150.67683936202897,-72.64314629470965,-150.67683936202897,-62.64314629470965,-150.67683936202897,194.86936653967862,-224.4206443033035,194.86936653967862,-298.16444924457807,194.86936653967862,-308.16444924457807,194.86936653967862]},{"from":-15,"to":-5,"fromPort":"B","toPort":"T","points":[-487.297963087824,-245.39731207970615,-487.297963087824,-235.39731207970615,-487.297963087824,-235.39731207970613,-487.297963087824,-235.39731207970613,-487.297963087824,-235.39731207970613,-487.297963087824,-225.39731207970613]},{"from":-14,"to":-15,"fromPort":"B","toPort":"T","points":[-487.29796308782375,-299.9306693184756,-487.29796308782375,-289.9306693184756,-487.29796308782386,-289.9306693184756,-487.29796308782386,-289.9306693184757,-487.297963087824,-289.9306693184757,-487.297963087824,-279.9306693184757]},{"from":-4,"to":-14,"fromPort":"L","toPort":"T","visible":true,"points":[-367.44167604572374,-365.8371191576089,-377.44167604572374,-365.8371191576089,-487.29796308782375,-365.8371191576089,-487.29796308782375,-355.15057285742705,-487.29796308782375,-344.4640265572452,-487.29796308782375,-334.4640265572452],"text":"No"},{"from":-19,"to":-17,"fromPort":"B","toPort":"T","visible":true,"points":[-487.297963087824,67.86954583045011,-487.297963087824,77.86954583045011,-487.297963087824,84.70275963660245,-487.29796308782386,84.70275963660245,-487.29796308782386,91.53597344275478,-487.29796308782386,101.53597344275478],"text":"No"},{"from":-5,"to":-20,"fromPort":"B","toPort":"T","points":[-487.297963087824,-190.8639548409366,-487.297963087824,-180.8639548409366,-487.297963087824,-180.8639548409366,-487.297963087824,-180.8639548409366,-487.2979630878239,-180.8639548409366,-487.2979630878239,-170.8639548409366]},{"from":-20,"to":-21,"fromPort":"B","toPort":"T","points":[-487.2979630878239,-136.33059760216707,-487.2979630878239,-126.33059760216707,-487.297963087824,-126.33059760216707,-487.297963087824,-126.33059760216707,-487.297963087824,-126.33059760216707,-487.297963087824,-116.33059760216707]},{"from":-21,"to":-16,"fromPort":"B","toPort":"T","points":[-487.297963087824,-81.79724036339755,-487.297963087824,-71.79724036339755,-487.297963087824,-71.79724036339755,-487.297963087824,-71.79724036339755,-487.297963087824,-71.79724036339755,-487.297963087824,-61.79724036339755]},{"from":-16,"to":-19,"fromPort":"B","toPort":"T","points":[-487.297963087824,-27.263883124628016,-487.297963087824,-17.263883124628016,-487.297963087824,-17.263883124628016,-487.297963087824,-17.263883124628016,-487.297963087824,-17.263883124628016,-487.297963087824,-7.263883124628016]},{"from":-17,"to":-6,"fromPort":"B","toPort":"T","points":[-487.29796308782386,136.06933068152432,-487.29796308782386,146.06933068152432,-487.29796308782386,146.06933068152432,-487.29796308782386,146.06933068152432,-487.29796308782386,146.06933068152432,-487.29796308782386,156.06933068152432]},{"from":-6,"to":-21,"fromPort":"L","toPort":"L","points":[-515.1344727924137,173.3360093009091,-525.1344727924137,173.3360093009091,-524,173.3360093009091,-524,173.3360093009091,-580,173.3360093009091,-580,-99.06391898278231,-543.1735886981755,-99.06391898278231,-533.1735886981755,-99.06391898278231]},{"from":-19,"to":-18,"fromPort":"R","toPort":"T","visible":true,"points":[-406.00056928899585,30.30283135291105,-396.00056928899585,30.30283135291105,-323.97138612566954,30.30283135291105,-323.97138612566954,35.68426984131595,-323.97138612566954,41.06570832972085,-323.97138612566954,51.06570832972085],"text":"Si"},{"from":-18,"to":-13,"fromPort":"R","toPort":"T","visible":true,"points":[-296.9598962575055,71.09906556849037,-286.9598962575055,71.09906556849037,-247.43029420672423,71.09906556849037,-247.43029420672423,82.58238694910561,-247.43029420672423,94.06570832972085,-247.43029420672423,104.06570832972085],"text":"Si"},{"from":-18,"to":-22,"fromPort":"L","toPort":"T","visible":true,"points":[-350.9828759938336,71.09906556849037,-360.9828759938336,71.09906556849037,-393.91548555193907,71.09906556849037,-393.91548555193907,82.58238694910561,-393.91548555193907,94.06570832972085,-393.91548555193907,104.06570832972085],"text":"No"},{"from":-22,"to":-8,"fromPort":"B","toPort":"T","points":[-393.91548555193907,134.35685370529052,-393.91548555193907,144.35685370529052,-393.91548555193907,156.9797708127922,-331.72397208528986,156.9797708127922,-331.72397208528986,169.60268792029385,-331.72397208528986,179.60268792029385]},{"from":-13,"to":-8,"fromPort":"B","toPort":"T","points":[-247.43029420672423,134.35685370529052,-247.43029420672423,144.35685370529052,-247.43029420672423,156.9797708127922,-331.72397208528986,156.9797708127922,-331.72397208528986,169.60268792029385,-331.72397208528986,179.60268792029385]}]} })

Donde, en el ciclo, se trabaja con el valor absoluto del número (x=|y|), porque con valores negativos, la serie pasa de tener sólo sumas a tener sumas y restas y cuando se restan números muy grandes (como ocurre en las series), los errores de redondeo son muy grandes, dando lugar a resultados erróneos, por lo que, siempre que sea posible, se deben evitar las restas. De no ser posible, se debe tratar de evitar trabajar con número muy grandes o muy pequeños.

En este caso específico, se puede trabajar con valores positivos (con el valor absoluto del número) porque, para las potencias se cumple que:

\[ \text{e}^{-x} = \dfrac{1}{\text{e}^x} \]

Se recalca que esta relación (que es una propiedad matemática) es válida únicamente para las potencias, no puede ser aplicada a otros casos (como funciones trigonométricas, por ejemplo).

El código respectivo, añadido como un método getter de la clase "Expo" (la cual extiende a la clase "Number") empleando la estructura do-while y el comando break, es:

var Expo = class extends Number{ get exponente() { const y = this.valueOf(); if (y === 0) return 1; const x = Math.abs(y); let s2, ter = 1, s1 = ter, i = 1; do { ter *= x/i; s2 = s1+ter; if (Math.abs(s1/s2-1)<1e-14) break; s1 = s2; i++; } while (true); return y < 0 ? 1/s2 : s2; } }

Llamando a la función, con los valores de prueba, se obtienen los resultados correctos:

(new Expo(0)).exponente
(new Expo(2)).exponente
(new Expo(3.5)).exponente
(new Expo(4.7)).exponente
(new Expo(9.2)).exponente

Seno de un ángulo en radianes

En este ejemplo se calcula el seno de un ángulo en radianes, 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, primero se deduce la regla que permite calcular un nuevo término en base al anterior, analizando las operaciones necesarias para 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 para calcular un nuevo término, se debe multiplicar el anterior por:

\[ \left(-\dfrac{x^2}{i \cdot j}\right) \]

Donde "i" y "j" son dos contadores que comienzan en 2 y 3 respectivamente y que incrementan de 2 en 2, en cada repetición del ciclo.

En este caso la serie en sí tiene restas, por lo que no es posible evitarlas, entonces, para reducir los errores de redondeo, se debe evitar trabajar con números muy grandes. Dado que las funciones trigonométricas son cíclicas, un ángulo mayor o igual a 360 grados, 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*π, porque, con ese residuo, se obtiene el mismo resultado que con el ángulo original.

El diagrama de flujo que resuelve el problema, tomando en cuenta las anteriores consideraciones, es:

gojsGraph({divi, modelo: {"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Process","text":"i = 1","key":-5,"loc":"-487.29796308782386 -103.13063346032123"},{"category":"Process","text":"i = i+2","key":-6,"loc":"-487.29796308782386 278.3360093009089"},{"category":"Start","text":"seno","key":-1,"loc":"-331.9273938191614 -469.6705122545327"},{"category":"Start","text":"fin","key":-8,"loc":"-331.72397208529026 334.86936653967877"},{"category":"Input","text":"ángulo en radianes: x","key":-3,"loc":"-331.9273938191614 -420.1371550157632"},{"category":"Output","text":"0","key":-12,"loc":"-144.67683936202897 -1.3231606379712844"},{"category":"Process","text":"ter = x","key":-14,"loc":"-487.29796308782386 -212.13063346032135"},{"category":"Process","text":"s1 = ter","key":-15,"loc":"-487.2979630878241 -157.6639906990909"},{"category":"Process","text":"s2 = s1+ter","key":-16,"loc":"-487.297963087824 60.4694382559872"},{"category":"Process","text":"s1 = s2","key":-17,"loc":"-487.29796308782375 223.80265206213943"},{"category":"Conditional","text":"abs(s1/s2-1)\n<1e-14","key":-19,"loc":"-487.297963087824 135.30283135291108"},{"category":"Process","text":"j = 3","key":-20,"loc":"-487.29796308782375 -48.59727622155174"},{"category":"Process","text":"ter = ter*xx/(i*j)","key":-21,"loc":"-487.2979630878241 5.936081017217646"},{"category":"Output","text":"s2","key":-22,"loc":"-331.72397208529003 229.67683936202866"},{"category":"Process","text":"x = x%(2*PI)","key":-23,"loc":"-331.92739381916147 -368.6037977769936"},{"category":"Conditional","text":"x==0","key":-24,"loc":"-331.9273938191615 -311.3037619188392"},{"category":"Process","text":"xx = -x*x","key":-27,"loc":"-487.297963087824 -266.6639906990909"},{"category":"Process","text":"j = j+2","key":-25,"loc":"-487.29796308782386 332.8693665396785"}],"linkDataArray":[{"from":-1,"to":-3,"fromPort":"B","toPort":"T","points":[-331.9273938191614,-454.4038336351479,-331.9273938191614,-444.4038336351479,-331.92739381916147,-444.4038336351479,-331.92739381916147,-444.403833635148,-331.9273938191615,-444.403833635148,-331.9273938191615,-434.403833635148]},{"from":-12,"to":-8,"fromPort":"B","toPort":"R","points":[-144.67683936202897,11.35685370529043,-144.67683936202897,21.35685370529043,-144.67683936202897,20,-144.67683936202897,20,-144.67683936202897,334.8693665396786,-298.16444924457824,334.8693665396786,-308.16444924457824,334.8693665396786]},{"from":-15,"to":-5,"fromPort":"B","toPort":"T","points":[-487.2979630878241,-140.39731207970615,-487.2979630878241,-130.39731207970615,-487.2979630878241,-130.39731207970607,-487.29796308782386,-130.39731207970607,-487.29796308782386,-130.397312079706,-487.29796308782386,-120.397312079706]},{"from":-19,"to":-17,"fromPort":"B","toPort":"T","visible":true,"points":[-487.2979630878241,172.86954583045016,-487.2979630878241,182.86954583045016,-487.2979630878241,189.70275963660242,-487.29796308782386,189.70275963660242,-487.29796308782386,196.5359734427547,-487.29796308782386,206.5359734427547],"text":"No"},{"from":-5,"to":-20,"fromPort":"B","toPort":"T","points":[-487.29796308782386,-85.86395484093646,-487.29796308782386,-75.86395484093646,-487.2979630878238,-75.86395484093646,-487.2979630878238,-75.8639548409365,-487.29796308782375,-75.8639548409365,-487.29796308782375,-65.8639548409365]},{"from":-20,"to":-21,"fromPort":"B","toPort":"T","points":[-487.29796308782375,-31.330597602166968,-487.29796308782375,-21.330597602166968,-487.2979630878239,-21.330597602166968,-487.2979630878239,-21.33059760216713,-487.2979630878241,-21.33059760216713,-487.2979630878241,-11.330597602167131]},{"from":-21,"to":-16,"fromPort":"B","toPort":"T","points":[-487.2979630878241,23.2027596366024,-487.2979630878241,33.2027596366024,-487.2979630878241,33.20275963660242,-487.297963087824,33.20275963660242,-487.297963087824,33.20275963660245,-487.297963087824,43.20275963660245]},{"from":-16,"to":-19,"fromPort":"B","toPort":"T","points":[-487.297963087824,77.73611687537198,-487.297963087824,87.73611687537198,-487.297963087824,87.736116875372,-487.2979630878241,87.736116875372,-487.2979630878241,87.73611687537203,-487.2979630878241,97.73611687537203]},{"from":-17,"to":-6,"fromPort":"B","toPort":"T","points":[-487.29796308782386,241.06933068152424,-487.29796308782386,251.06933068152424,-487.29796308782386,251.06933068152424,-487.29796308782386,251.06933068152415,-487.29796308782386,251.06933068152415,-487.29796308782386,261.06933068152415]},{"from":-25,"to":-21,"fromPort":"L","toPort":"L","points":[-515.1051606586246,332.8693665396785,-525.1051606586246,332.3346924251127,-595,332.3346924251127,-595,5.936081017217635,-556.0597123554022,5.936081017217635,-546.0597123554022,5.936081017217635]},{"from":-22,"to":-8,"fromPort":"B","toPort":"T","points":[-331.72397208529003,242.35685370529052,-331.72397208529003,252.35685370529052,-331.72397208529003,252.35685370529052,-331.72397208529003,252.35685370529052,-331.72397208529003,309.6026879202938,-331.72397208529003,319.6026879202938]},{"from":-3,"to":-23,"fromPort":"B","toPort":"T","points":[-331.9273938191615,-405.8704763963784,-331.9273938191615,-395.8704763963784,-331.9273938191615,-395.87047639637836,-331.9273938191615,-395.87047639637836,-331.9273938191615,-395.8704763963783,-331.9273938191615,-385.8704763963783]},{"from":-23,"to":-24,"fromPort":"B","toPort":"T","points":[-331.9273938191615,-351.33711915760875,-331.9273938191615,-341.33711915760875,-331.9273938191615,-341.33711915760875,-331.9273938191615,-341.33711915760875,-331.9273938191615,-341.33711915760875,-331.9273938191615,-331.33711915760875]},{"from":-27,"to":-14,"fromPort":"B","toPort":"T","points":[-487.297963087824,-249.39731207970613,-487.297963087824,-239.39731207970613,-487.2979630878239,-239.39731207970613,-487.2979630878239,-239.39731207970613,-487.29796308782386,-239.39731207970613,-487.29796308782386,-229.39731207970613]},{"from":-14,"to":-15,"fromPort":"B","toPort":"T","points":[-487.29796308782386,-194.8639548409366,-487.29796308782386,-184.8639548409366,-487.297963087824,-184.8639548409366,-487.297963087824,-184.93066931847568,-487.2979630878241,-184.93066931847568,-487.2979630878241,-174.93066931847568]},{"from":-6,"to":-25,"fromPort":"B","toPort":"T","points":[-487.29796308782386,295.6026879202937,-487.29796308782386,305.6026879202937,-487.29796308782386,305.6026879202937,-487.29796308782386,305.6026879202937,-487.29796308782386,305.6026879202937,-487.29796308782386,315.6026879202937]},{"from":-24,"to":-27,"fromPort":"L","toPort":"T","visible":true,"points":[-367.32439699298965,-311.3037619188392,-377.32439699298965,-311.3037619188392,-487.297963087824,-311.3037619188392,-487.297963087824,-302.61721561865744,-487.297963087824,-293.9306693184757,-487.297963087824,-283.9306693184757],"text":"No"},{"from":-24,"to":-12,"fromPort":"R","toPort":"T","visible":true,"points":[-296.5303906453334,-311.3037619188392,-286.5303906453334,-311.3037619188392,-144.67683936202897,-311.3037619188392,-144.67683936202897,-170.1190267945592,-144.67683936202897,-28.934291670279237,-144.67683936202897,-18.934291670279237],"text":"Si"},{"from":-19,"to":-22,"fromPort":"R","toPort":"T","visible":true,"points":[-406.00056928899596,135.30283135291108,-396.00056928899596,135.30283135291108,-331.72397208529003,135.30283135291108,-331.72397208529003,168.68426984131597,-331.72397208529003,202.06570832972085,-331.72397208529003,212.06570832972085],"text":"Si"}]} })

El código respectivo, implementado como un método getter, añadido a la clase "Number", empleando la estructura for y el comando break, es:

Object.defineProperty(Number.prototype, "seno", { get() { const x = this.valueOf()%(2*Math.PI); if (x == 0) return 0; const xx = -x*x; let s2, ter = x, s1 = ter, i = 2, j = 3; for(;;) { ter *= xx/(i*j); s2 = s1+ter; if (Math.abs(s1/s2-1)<1e-14) break; s1 = s2; i += 2; j += 2; } return s2; }, configurable: true });

Llamando a las funciones con los valores de prueba, se obtiene:

(0).seno
(2.45).seno
(3.22).seno
(56.8).seno
(-83.1).seno
(127.4).seno

Doble productoria

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 (sin necesidad inclusive de un algoritmo): el contador de la productoria es el contador del ciclo, el límite inferior es el valor inicial del ciclo, el límite superior es la condición de finalización del ciclo, la diferencia entre dos valores consecutivos es el incremento del ciclo y la expresión de la productoria, es la instrucción a programar en el 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.

El diagram de flujo que resuelve este problema, es:

gojsGraph({divi, modelo: {"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Start","text":"dobleProductoria","key":-1,"loc":"172 -460"},{"category":"Input","text":"límite productoria externa: n\nlímite productoria interna: m","key":-3,"loc":"172 -401.69996414184567"},{"category":"Process","text":"p1 = p1*p2","key":-7,"loc":"172.00000000000003 82.60025100708006"},{"category":"Start","text":"fin","key":-9,"loc":"172.00000000000003 150.13360824584964"},{"category":"Output","text":"p1","key":-10,"loc":"323 10"},{"category":"Process","text":"p1 = 1","key":-11,"loc":"172.00000000000003 -341.39992828369145"},{"category":"Process","text":"x = 1","key":-12,"loc":"172.00000000000003 -286.8665710449219"},{"category":"For","text":"x<=n","key":-13,"loc":"172.00000000000003 -232.51654415130616"},{"category":"Process","text":"p2 = 1","key":-14,"loc":"172.00000000000003 -164.16651725769043"},{"category":"Process","text":"y = 1","key":-15,"loc":"172.00000000000003 -109.6331600189209"},{"category":"For","text":"y<=m","key":-16,"loc":"172.00000000000003 -55.2831331253052"},{"category":"Process","text":"p2 = p2*cbrt(x+y)","key":-17,"loc":"172.00000000000003 13.066893768310521"},{"category":"Process","text":"y = y+2","key":-18,"loc":"84.00000000000006 -55.2831331253052"},{"category":"Process","text":"x = x+1","key":-19,"loc":"83.00000000000006 -232.51654415130616"}],"linkDataArray":[{"from":-1,"to":-3,"fromPort":"B","toPort":"T","points":[171.9999999999999,-444.7333213806151,171.9999999999999,-434.7333213806151,171.99999999999994,-434.7333213806151,171.99999999999994,-434.7333213806153,172.00000000000003,-434.7333213806153,172.00000000000003,-424.7333213806153]},{"from":-3,"to":-11,"fromPort":"B","toPort":"T","points":[172.00000000000003,-378.66660690307623,172.00000000000003,-368.66660690307623,172.00000000000003,-368.66660690307623,172.00000000000003,-368.66660690307623,172.00000000000003,-368.66660690307623,172.00000000000003,-358.66660690307623]},{"from":-11,"to":-12,"fromPort":"B","toPort":"T","points":[172.00000000000003,-324.1332496643067,172.00000000000003,-314.1332496643067,172.00000000000003,-314.1332496643067,172.00000000000003,-314.1332496643067,172.00000000000003,-314.1332496643067,172.00000000000003,-304.1332496643067]},{"from":-12,"to":-13,"fromPort":"B","toPort":"T","points":[172.00000000000003,-269.5998924255371,172.00000000000003,-259.5998924255371,172.00000000000003,-259.5998924255371,172.00000000000003,-259.5998924255371,172.00000000000003,-259.5998924255371,172.00000000000003,-249.59989242553712]},{"from":-13,"to":-14,"fromPort":"B","toPort":"T","visible":true,"points":[172.00000000000003,-215.4331958770752,172.00000000000003,-205.4331958770752,172.00000000000003,-198.4331958770752,172.00000000000003,-198.4331958770752,172.00000000000003,-191.4331958770752,172.00000000000003,-181.4331958770752],"text":"Si"},{"from":-14,"to":-15,"fromPort":"B","toPort":"T","points":[172.00000000000003,-146.89983863830568,172.00000000000003,-136.89983863830568,172.00000000000003,-136.89983863830568,172.00000000000003,-136.89983863830568,172.00000000000003,-136.89983863830568,172.00000000000003,-126.89983863830568]},{"from":-15,"to":-16,"fromPort":"B","toPort":"T","points":[172.00000000000003,-92.36648139953616,172.00000000000003,-82.36648139953616,172.00000000000003,-82.36648139953616,172.00000000000003,-82.36648139953616,172.00000000000003,-82.36648139953616,172.00000000000003,-72.36648139953616]},{"from":-16,"to":-17,"fromPort":"B","toPort":"T","visible":true,"points":[172.00000000000003,-38.19978485107424,172.00000000000003,-28.19978485107424,172.00000000000003,-21.19978485107424,172.00000000000003,-21.19978485107424,172.00000000000003,-14.199784851074245,172.00000000000003,-4.199784851074245],"text":"Si"},{"from":-17,"to":-18,"fromPort":"L","toPort":"B","points":[107.92400360107425,13.066893768310521,97.92400360107425,13.066893768310521,84.00000000000009,13.066893768310521,84.00000000000009,-7.474780368804954,84.00000000000009,-28.01645450592043,84.00000000000009,-38.01645450592043]},{"from":-18,"to":-16,"fromPort":"R","toPort":"L","points":[115.58946990966803,-55.2831331253052,125.58946990966803,-55.2831331253052,126.90789794921879,-55.2831331253052,126.90789794921879,-55.2831331253052,128.22632598876956,-55.2831331253052,138.22632598876956,-55.2831331253052]},{"from":-16,"to":-7,"fromPort":"R","toPort":"T","visible":true,"points":[205.7736740112305,-55.2831331253052,215.7736740112305,-54.6415665626526,257,-54.6415665626526,257,44,172.00000000000003,44,172.00000000000003,55.3335723876953,172.00000000000003,65.3335723876953],"text":"No"},{"from":-7,"to":-19,"fromPort":"L","toPort":"L","points":[127.17987823486331,82.60025100708006,117.17987823486331,82.60025100708006,15,82.60025100708006,15,-232.51654415130616,41.52780914306646,-232.51654415130616,51.52780914306646,-232.51654415130616]},{"from":-19,"to":-13,"fromPort":"R","toPort":"L","points":[114.47219085693365,-232.51654415130616,124.47219085693365,-232.51654415130616,127.34980392456059,-232.51654415130616,127.34980392456059,-232.51654415130616,130.22741699218753,-232.51654415130616,140.22741699218753,-232.51654415130616]},{"from":-13,"to":-10,"fromPort":"R","toPort":"T","visible":true,"points":[203.77258300781253,-232.51654415130616,213.77258300781253,-232.51654415130616,323,-232.51654415130616,323,-125.06383759180706,323,-17.611131032307945,323,-7.611131032307945],"text":"No"},{"from":-10,"to":-9,"fromPort":"B","toPort":"T","points":[323,22.68001434326172,323,32.68001434326172,323,36,323,36,323,111,172.00000000000003,111,172.00000000000003,124.86692962646481,172.00000000000003,134.8669296264648]}]} })

El código respectivo, implementado como un método de la clase "DProd", es el siguiente:

var DProd = class { constructor(número1, número2) { this.n = número1; this.m = número2; } get dobleProductoria() { const {n, m} = this; if (n === undefined) throw new Error("No ha definido el primer límite."); if (m === undefined) throw new Error("No ha definido el segundo límite."); if (n%1!==0 || m%1!==0) throw new Error("Los límites deben ser enteros"); if (n<0 || m<0) throw new Error("Los límites deben ser positivos"); let p1 = 1; for (let x=1; x<=n; x++) { let p2 = 1; for (let y=1; y<=m; y+=2) p2 *= Math.cbrt(x+y); p1 *= p2; } return p1; } }

Como se puede ver, se valida que los límites de las productorias hayan sido establecidos y sean enteros y positivos. Llamando al método con algunos valores de prueba, se obtiene:

(new DProd(2, 3)).dobleProductoria
(new DProd(5, 7)).dobleProductoria
(new DProd(7, 7)).dobleProductoria
(new DProd()).dobleProductoria
(new DProd(3)).dobleProductoria
(new DProd(2.5, 6.7)).dobleProductoria
(new DProd(-7, -9)).dobleProductoria