Está en la página 1de 18

for, while, break, continue


En este ejercicio se examinara un código para
encontrar las raíces de una ecuación no lineal y en el
proceso se introducira el método de Newton-
Raphson y las estructuras de control ”for”, ”while” y
”do...while” (sentecias de iteración: permiten repetir
una sentencia o un cojunto de ellas)
Método de Newton-
Raphson:

Problema numérico: encontrar la solución de la
ecuación f(x)=0 para alguna función (usualmente no
lineal) diferenciable.

El método de Newton-Raphson es muy eficiente,
pero puede requerir partir de una suposición bastante
buena de la solución.

Supongamos que x=p resuelve el problema. Esto
significa f(p)=0

No se conoce 'p', pero suponiendo que se conoce un
x cercano a p. Se expande f(p) en una serie de
Taylor alrededor de 'x':

Usando f(p)=0, se resuelve para 'p':


El resultado es solo un aproximado, dado que se
redujo terminos en la serie de Taylor. Si estos
terminos son pequeños, 'p' es una mejor
aproximación a la raiz que 'x', pero no se garantiza
que sea la solución exacta.
 Esta formula puede ser usada como las bases para
un algoritmo iterativo.
Cuando el método converge? cuando
decirle al programa que pare?

Un criterio es monitorear la mejora de |p-x| y parar
cuando esta es menor que una especificada
tolerancia.

Otra es monitorear el valor de | f(p) | y para cuando
es suficientemente pequeño.

Tenga en cuenta que aun cuando el cambio |p-x| es
menor que cierta tolerancia, no hay garantía que se
tiene la raíz a aquella presición. Sin embargo, para la
mayoría de las situaciones, este método es
suficiente.
Código C++: nr.cc
// Codigo primitivo para encontrar las raices de
// 4*x - cos(x)
// usando el metodo de Newton-Raphson
// Fisica computacional 23/09/2010
// Uso de
// nr
// Se pregunta al usuario por la tolerancia y el punto de partida.
#include <iostream>
#include <cmath>
using namespace std;
#define N 100 // Maximo numero de iteraciones
int main(){
double p,pnew;
double f,dfdx;
double tol;
int i;
cout << "Ingrese tolerancia: ";
cin >> tol;
cout << "Ingrese valor de partida x: ";
cin >> pnew;
// Bucle principal
for(i = 0; i < N; i = i + 1){
p = pnew;
// Evalua la funcion y su derivada
f = 4*p - cos(p);
dfdx = 4 + sin(p);
// El paso Newton-Raphson
pnew = p - f/dfdx;
// Conprueba si hay convergencia y abandona si se cumple
if(abs(p-pnew) < tol){
cout << "Root is " << pnew << " to within "
<< tol << "\n";
return 0;
}
}
// Se llega a este punto solo si interacion no converge
cerr << "Fallo convergencia luego de " << N << " iteraciones.\n";
return 1;
}
Explicación de nuevos
conceptos:
#define N 100 // Maximo numero de iteraciones


Esta es un forma comun para definir una constante
que podría ser cambiada algun día.

La sentencia #define debería colocarse en la parte
superior del código donde sea facil encontrar.

El símbolo ¨N¨ es tecnicamente llamado un ¨macro¨.

El compilador reemplaza cada instancia del macro
con su valor.
for(i = 0; i < N; i = i + 1){
...
}


Este es un bucle “for”. Especifica que la sentencia
entre las llaves debe ser ejecutada repetidamente
siempre y cuando i<N, empezando con i=0, e
incrementando i en 1 cuando la última sentencia
entre las llaves es alcanzada.

Se usa un bucle “for” aqui para imponer un número
máximo de iteraciones, y evitar que el código se
ejecute sin fin.
El bucle ¨for¨

El modelo genérico es:
for(sentencia-partida; expresion-logica; sentencia-incremento){
bloque-sentencias
}


Note que la expresión lógica es probada antes de
ingresar al bloque de sentencias.

Si sucede que N==0, la condición i<0 sería falsa y el
bloque de sentencias se omitiría.

Devido a que incrementar un contador en una
unidad es hecho frecuentemente, C++ tiene una
abreviación: i++ en lugar de i=i+1 (++i en este
contexto significa lo mismo)

Podriamos conseguir lo mismo con un blucle
“while”:
i = 0;
while(i < N){
...
i++;
}


Tenga en cuenta que aquí tenemos que tomar la
precaución de colocar las declaraciones de
inicialización e incremento en el lugar correcto. Y se
necesitan tres sentencias para hacer el trabajo de
uno. Por ello, el bucle “for” es preferible.
El bucle ¨while¨

La forma genérica es:
while(expresion-logica){
bloque-sentencias
}


El bucle while repite las sentencias dentro del
bloque de instrucciones mientras la expresión lógica
es verdadera.

Corresponde al programador asegurar que hay un
escape del bucle, para que no se ejecute en forma
indefinida. Otra razón para ser cautelosos acerca de
utilizar un bucle while donde un bucle “for” es
suficiente.
El bucle ¨do...while¨

La estructura do...while es mucho menos usada, la sintaxis
general es:

do{
bloque-sentencias;
} while(expresion-logica);


Esta estructura de bucle es muy similar a la estructura de
bucle while, excepto que la expresión lógica se comprueba
sólo después de ejecutar el bloque de instrucciones al menos
una vez. (Con el bucle while el bloque de instrucciones no
se ejecuta en absoluto si la expresión lógica es falsa.) Luego,
en ambos casos, el bloque se ejecuta repetidamente mientras
la expresión lógica sigue siendo cierta.
if(abs(p-pnew) < tol){
...
}


Esta prueba se llama condición de parada para el
método. Nos detenemos cuando el valor absoluto del
cambio en la raíz estimada es menor que la
tolerancia especificada. Se toma el valor absoluto
del cambio, ya que podría ser positivo o negativo.
return 0;


Esta sentencia fuerza una salida del programa
principal. El valor 0 es el código de salida. Es una
práctica común utilizar un código de salida de 0
para un normal desarrollo y un código distinto de
cero para una condición anormal. Tenga en cuenta
que en la parte inferior del código le damos un
código de salida de 1 para indicar que el método no
converge. Puede comprobar el código de salida de
su programa en el shell bash utilizando el comando
Unix “echo $?” inmediatamente luego que el
programa finaliza.

Otra manera comun de salir del programa principal es
llamando la funcion “exit”:
exit(0);


donde el número en parentesis es el código de salida
deseado.

La sentencia “break” proporciona otra manera de salir del
bucle:
for(i = 0; i < N; i = i + 1){
...
if(abs(p-pnew) < tol)break;
}


La sentencia break inmediatamente cierra el bloque de
sentencias controlado por un bucle for, while o do...while, y
procede con la siguiente sentencia despues de la llave de
cierre.
Sentencia “break”

El problema lógico en este caso es que se alcanze el mismo
punto en el código si el proceso no converge. Así que se
tiene que comprobar el valor de i para asegurarse de que no
fue así. Por ejemplo, se podría terminar de esta manera:

for(i = 0; i < N; i = i + 1){


...
if(abs(p-pnew) < tol)break;
}
if(i >= N){
cerr << "Falla convergencia luego de " << N <<
" iteraciones.\n";
return 1;
}
cout << "Raíz es " << pnew << " dentro de "
<< tol << "\n";
return 0;
Sentencia “continue”

Ofrece otra manera de saltar un bucle. Mientras “break” salta el resto
del bloque de instrucciones y cierra el bucle, “continue” salta la
declaración del resto del bloque de instrucciones y procede a la
siguiente iteración. Ejemplo de su uso en el mismo código:
for(i = 0; i < N; i = i + 1){
...
if(abs(p-pnew) > tol)continue;
cout << "Raíz es " << pnew << " dentro de "
<< tol << "\n";
return 0;
}
cerr << "Falla convergencia luego de " << N << "
iteraciones.\n";
return 1;


Tenga en cuenta que la desigualdad se invierte, el bucle continúa
mientras el cambio en la raíz es mayor que la tolerancia y i <N

La sentencia continue es más apropiada cuando el nivel de
anidamiento de bloques de instrucciones es torpe o cuando la
continuación es una alternativa poco probable, que no es el caso aquí.
“cerr”
cerr << "Falla convergencia luego de " << N <<
" iteraciones.\n";


El objeto “cerr” de iostream funciona como “cout”, pero
envía la salida al dispositivo stderr en lugar de a stdout. Por
defecto, el dispositivo stdout, como el dispositivo stderr, es
la consola.

Ejemplo: Permite (re)direccionar los mensajes de error a un
archivo.

También podría gustarte