Iteración - 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, el bloque catch (las instrucciones 2) es ignorado. Finalmente, sin importar si se ha producido o no un error, el programa salta al bloque finally y se ejecutan 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 es:

function raizCuadrada(n, x1=1.1) {
if (n<0) throw "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;
};

Con el cual se obtienen los resultados esperados:

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

El código, con la estructura do-while y el comando return, es:

var raizCuadrada = function(n, x1=1.1) {
if (n<0) throw "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:

var raizCuadrada = (n, x1=1.1) => {
if (n<0) throw "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), en este caso, el error lanzado es el resultado calculado (x2), ese error (el resultado calculado) es atrapado por catch en la variable e y devuelto como el resultado de la función (lo que es correcto, porque "e" es el resultado calculado: el valor de "x2"). En JavaScript, el comando throw, como se puede ver en este ejemplo, no sólo puede lanzar (devolver) un mensaje 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, empleando las estructuras while y try-catch, es:

function legendre(x, n) {
if (n%1!==0) throw "El orden debe ser entero";
if (n<0) throw "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:

legendre(1.3, 2)
legendre(1.5, 3)
legendre(3.9, 7)
legendre(2.1, 0)
legendre(13.1, 1)
legendre(6.1, 4.5)
legendre(1.1, -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 el 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, empleando la estructura do-while y el comando break, es:

var exponente = y => {
  if (y === 0) return 1;
  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:

exponente(0)
exponente(2)
exponente(3.5)
exponente(4.7)
exponente(-9.2)

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 calculando el residuo de su división entre 2*π, entonces, con ese residuo, se obtiene el resultado correcto.

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 con la estructura for y el comando break, es:

function seno(a) {
  let x = Math.abs(a)*180/Math.PI;
  while (x > 270) x -= 360;
  x *= Math.PI/180;
  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 a < 0 ? -s2 : s2;
};

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

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

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 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.

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, es:

var dobleProductoria = function(n, m) {
if (n === undefined) throw "No ha definido el primer límite.";
if (m === undefined) throw "No ha definido el segundo límite.";
  if (n%1!==0 || m%1!==0) throw "Los números deben ser enteros";
  if (n<0 || m<0) throw "Los números 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 (que no sean valores indefinidos), sean enteros y positivos. Llamando al método con algunos valores de prueba, se obtiene:

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