Documentos de Académico
Documentos de Profesional
Documentos de Cultura
P R E S E N T A:
J u an A rtu r o B ad i l l o R i o s
J os é L u i s Orti z d e l a lu z
6
1.- ECUACIONES LINEALES
1.2.3.- Pseudocódigo 13
1.2.4.- Programas en C 13
1.3.3.- Pseudocódigo 20
1.3.4.- Programas en C 21
1.4.3.- Pseudocódigo 30
1.4.4.- Programas en C 32
1.4.5.- Demostración del Programa 33
2.2.- Bisección 35
2.2.3.- Pseudocódigo 40
2.2.4.- Programas en C 41
2.3.3.- Pseudocódigo 48
2.3.4.- Programas en C 49
2.4.- Newton-Raphson 52
2.4.3.- Pseudocódigo 56
2.4.4.- Programas en C 56
3.2.- Euler 59
3.2.3.- Pseudocódigo 65
3.2.4.- Programas en C 66
3.3.-Runge-Kutta 68
3.3.3.- Pseudocódigo 72
3.3.4.- Programas en C 74
4.- INTEGRACIÓN 76
4.2.3.- Pseudocódigo 81
4.2.4.- Programas en C 82
CAPITULO III
BIBLIOGRAFÍA 87
ANEXOS 88
INTRODUCCIÓN
Los métodos numéricos son técnicas mediante las cuales es posible resolver
problemas mediante el uso de operaciones aritméticas. Este manual tiene como
meta dejar plasmados los métodos más importantes que abarca la experiencia
educativa de métodos numéricos para la solución de sistemas de ecuaciones
lineales, no lineales y a su vez de derivadas e integrales. Cabe destacar que el
objetivo fundamental de este trabajo es ofrecer una guía práctica para que los
estudiantes puedan seguir paso a paso la elaboración de los programas desde el
desarrollo de los algoritmos a través de los diagramas de flujo hasta la realización
del código fuente pasando por las etapas de compilación y ejecución exitosa del
programa.
1
CAPITULO I
2
JUSTIFICACIÓN
El manual incluirá específicamente los temas de mayor interés para los estudiantes
de la Facultad de Ingeniería Mecánica Eléctrica, los cuales servirán como apoyo al
cursar la experiencia educativa de métodos numéricos.
La función principal de este trabajo, será proporcionar al alumno las bases para
conocer y aplicar los fundamentos de los métodos numéricos para la solución de
problemas de ingeniería, implementando diversos algoritmos a través de un
lenguaje de programación como el Lenguaje C y de esta manera obtener por
consecuencia programas que permitan mejorar el entendimiento de los métodos
numéricos.
3
CAPITULO II
PROCESO
DEL
TRABAJO
1.- ECUACIONES LINEALES
1.1.- Definición y clasificación
En este capítulo estudiaremos las técnicas de solución de sistemas de ecuaciones
lineales cuadrados Ax = b.
Un sistema de ecuaciones lineales, también conocido como sistema lineal de
ecuaciones o simplemente sistema lineal, es un conjunto de ecuaciones lineales
sobre un cuerpo o un anillo conmutativo.
El problema consiste en encontrar los valores desconocidos de las variables x1, x2 y
x3 que satisfacen las tres ecuaciones.
Para establecer la velocidad de cálculo y el "trabajo computacional" en los métodos
directos, se analiza el número de operaciones de éstos y con base en ello se
determinan sus necesidades de memoria. Como consecuencia de lo anterior, se da
particular atención a los sistemas especiales: simétricos, bandeados y dispersos,
entre otros. Así, estudiaremos los métodos que aprovechan estas características
para lograr reducir con esto el número de operaciones y los requerimientos de
máquina.
Posteriormente se exponen y se desarrollan tres métodos numéricos aplicados a las
ecuaciones lineales como son: Gauss Simple, Gauss Seidel y Gauss Jordan.
Dado que el mundo real puede verse como un grupo de objetos o partes trabajando
en conjunto o bien conectadas de alguna manera formando un todo, brindar al
alumno una mejor comprensión de la extraordinaria cantidad de situaciones que
pueden representarse con los sistemas o grupos de ecuaciones donde cada una de
ellas corresponde a alguna de sus partes, por ejemplo: en circuitos, estructuras.
6
El método está ideado para resolver un sistema general de n ecuaciones:
(Ec. 1.2)
Donde el superíndice prima indica que los elementos han cambiado sus valores
originales
7
Eliminación
hacia adelante
Sustitución
hacia atrás
Figura 1.1
Las dos fases de la eliminación de Gauss: eliminación hacia adelante y sustitución
hacia atrás. Los superíndices prima indican el número de veces que se han
modificado los coeficientes y constantes.
El procedimiento se repite después con las ecuaciones restantes. Por ejemplo, la
ecuación (Ec. 1.1) se puede multiplicar por y el resultado se resta de la
tercera ecuación. Se repite el procedimiento con las ecuaciones restantes y da
como resultado el siguiente sistema modificado:
8
Donde el superíndice biprima indica que los elementos se han modificado dos
veces.
El procedimiento puede continuar usando las ecuaciones pivote restantes. La última
manipulación en esta secuencia es el uso de la ésima ecuación para eliminar
el término de la -ésima ecuación. Aquí el sistema se habrá transformado en un
sistema triangular superior
(Ec. 1.4a)
(Ec. 1.4b)
(Ec. 1.4c)
. .
.
. .
(Ec. 1.4d)
(Ec.1.9)
(Ec.1.10)
9
Para completar la eliminación hacia adelante, debe eliminarse de la ecuación
(Ec.1.10). Para llevar a cabo esto, se multiplica la ecuación (Ec.1.9) por -
0.190000/7.00333 y se resta el resultado de la ecuación (Ec.1.10). Esto elimina
de la tercera ecuación y reduce el sistema a una forma triangular superior:
(Ec.1.11)
(Ec.1.12)
(Ec.1.13)
Ahora se pueden resolver estas ecuaciones por sustitución hacia atrás. En primer
lugar, de la ecuación (Ec.1.13) se despeja x3
(Ec.1.14)
(Ec.1.15)
de la que se despeja,
10
1.2.2.- Diagrama de flujo
11
Diagrama de Flujo Gauss Simple sustitución hacia atrás
12
1.2.3.- Pseudocódigo
a) DO k = 1, n – 1
DO i = k + 1, n
factor =
DO j = k + 1 to n
ai,j = ai,j – factor . ak,j
END DO
bi = bi - factor •
END DO
END DO
b) xn = bn / an,n
DO i=n-1, 1,-1
sum = O
DO j = i + 1, n
sum = sum + ai,j . xj
END DO
xi = (bi - sum) / ai, i
END DO
1.2.4.- Programas en C
Gauss Simple
#include <math.h>
#include <stdio.h> /*para printf(),scanf()*/
#include <conio.h> /*para getch(),clrscr()*/
//#include <stdlib.h>/*para exit()*/
//#include <dos.h>
#define NUMEL 20
#define INTERVALOS 0
float A[25][25], B[25], S[25],X[25];
MAIN
printf("\n METODO DE GAUSS SIMPLE");
printf("\n Numero de Ecuaciones = ");
scanf("%d",&n);
printf("\n Inserte cada uno de los coeficientes\n");
for(i=1;i<=n;i++)
{ printf("\n Fila %d \n",i);
for(j=1;j<=n;j++)
{ printf(" Ingrese A(%d,%d) = ",i,j);
scanf("%f",&A[i][j]);
}
}
printf("\n Inserte cada uno de los terminos independientes\n");
for(i=1;i<=n;i++){
{ printf(" Ingrese B(%d) = ",i);
scanf("%f",&B[i]);
}
}
13
printf("\n Tolerancia para el calculo = ");
scanf("%f",&tol);
Gauss( n,tol, &er );
printf("\n\n RAICES DEL SISTEMA\n ");
for(i=1;i<=n;i++){
printf("\n X(%d) = %6.4f",i,X[i]);
}
printf("\n\n Fin del programa");
getch();
}
void Gauss( int n, float tol, int *er){
int i,j;
// IMPRESION DE LOS COEFICIENTES RECIBIDOS
/* printf("\n IMPRESION DE COEFICIENTES\n");
for(i=1;i<=n;i++)
{ printf("\n Fila %d \n",i);
for(j=1;j<=n;j++)
{ printf(" A(%d,%d) = %f",i,j, A[i][j]);
}
printf("\n");
}
getch();
*/
*er = 0;
for (i=1;i<=n;i++){
S[i] = abs(A[i][1]);
for(j=2;j<=n;j++)
if( abs(A[i][j]>S[i]))
S[i] = A[i][j];
}
14
1.2.5.- Demostración del programa
15
1.3.- Gauss Seidel
El método de Gauss-Seidel emplea valores iniciales y después itera para obtener
las mejores aproximaciones a la solución. El método de Gauss-Seidel es
particularmente adecuado cuando se tiene gran número de ecuaciones. Los
métodos de eliminación pueden estar sujetos a errores de redondeo. Debido a que
el error en el método de Gauss-Seidel es determinado por el número de iteraciones,
no es un tema que preocupe. Aunque existen ciertos ejercicios donde la técnica de
Gauss-Seidel no convergerá al resultado correcto, estudiaremos otras ventajas que
se tienen dicho método.
Una matriz bandeada es una matriz cuadrada en donde la diagonal principal son
valores diferentes a cero (valor=1) y los que se encuentran fuera de la diagonal son
ceros. Los sistemas bandeados se encuentran con frecuencia en la práctica
científica y de la ingeniería. Por ejemplo, tales sistemas aparecen en la solución de
ecuaciones diferenciales.
Aunque la eliminación de Gauss o la convencional se emplean para resolver
sistemas de ecuaciones bandeados, resultan ser ineficientes, debido a que si el
pivoteo no es necesario, ninguno de los elementos fuera de la banda cambiará su
valor original igual a cero. Así, será necesario utilizar tiempo y espacio en el
almacenamiento y en el manejo de estos ceros inútiles. Si se sabe de antemano
que el pivoteo no es necesario, se pueden desarrollar algoritmos muy eficientes en
los que no intervengan los ceros fuera de la banda. Como en muchos problemas
con sistemas bandeados, no se requiere el pivoteo; los algoritmos alternos, que se
describirán a continuación, son los métodos seleccionados para tal fin.
El método de Gauss-Seidel es el método iterativo más comúnmente usado.
Suponga que se da un sistema de n ecuaciones:
(Ec.1.16b)
(Ec.1.16c)
(Ec.1.18a)
(Ec.1.18b)
(Ec.1.18c)
17
la primera iteración termina al sustituir los valores calculados para en la
ecuación (Ec.1.18c) para dar
18
1.3.2.- Diagrama de flujo
19
1.3.3.- Pseudocódigo
20
1.3.4. - Programas en C
GAUSS SEIDEL
#include <stdio.h>
#include <math.h>
#include <iostream.h>
#include <conio.h>
#define L 10
#define P L
MAIN
cout<<"\n\n METODO DE GAUSS SEIDEL ";
cout<<"\n\n Numero de incognitas Posibles en el sistema: ";
scanf("%d",&n);
Gauss_Seidel(n);
titulo(n);
resultados();
cout<<"\n\nLos resultado son ";
for(x=0;x<n;x++)
{
RESULTADOS[x]=X[x];
cout<<"\nX["<<x<<"]= "<<RESULTADOS[x];
}
getch();
}
void resultados()
{
int q=0,i=1,t=3,s=n,r=0;
int sw=0,w=0,ite=0,h=0;
while((sw==0)&&(w<20))
{
h=0;
while(h<n)
{
if(tabla[r]==tabla[r+s])
{
cont++;
}
if(cont==n)
sw=1;
r++;
s++;
h++;
}
ite++;
w++;
}
w=ite-1;
for(int j=0;j<w;j++)
{
t=t+2;
if((i%10==0))
{
textcolor(LIGHTRED+BLINK);
gotoxy(5,t-2);
cprintf("\n\n ---Presione una tecla para ingresar ala tabla!!! ");
getch();
textcolor(GREEN);
clrscr();
t=5;
titulo(n);
}
gotoxy(15,t);cout<<i<<"ø";
int y=20,z=0;
for(int r=0;r<n;r++)
21
{
gotoxy(y+z,t);cout<<tabla[q];
q++;
z=z+10;
}
i++;
}
}
void main()
{
22
1.3.5.- Demostración del programa
23
24
1.4.- Gauss Jordan
Figura 1.2
Representación gráfica del método de Gauss-Jordan.
Solución. Primero, exprese los coeficientes y el lado derecho como una matriz au-
mentada
25
Luego normalice el primer renglón, dividiéndolo entre el elemento pivote, 3, para
obtener
El término se elimina del segundo renglón restando 0.1 veces al primer renglón del
segundo. En forma similar, restando 0.3 veces el primer renglón del tercero, se
eliminará el término del tercer renglón:
1 0 -0.0680629 2.52356
0 1 -0.0418848 -2.79320
0 0 10.01200 70.0843
1 0 -0.0680629 2.52356
0 1 -0.0418848 -2.79320
0 0 1 7.00003
26
Por último los términos se pueden eliminar de la primera y segunda ecuación para
obtener
1 0 0 3.00000
0 1 0 -2.50001
0 0 1 7.00003
27
1.4.2.- Diagrama de Flujo
N,M,I,A,J
28
SUBROUTINE
GAUSS (N,M,A)
I,PIVOTE,A,J,K,N,
M,CERO
29
1.4.3.- Pseudocódigo
30
SUB Pivot (a, b, s, n, k)
p=k
big = ABS(ak,k/sk)
DO i i= k + 1, n
dummy = ABS(aii,k/sii)
IF dummy > big THEN
big = dummy
p=ii
END IF
END DO
IF p k THEN
DO jj = k, n
dummy = ap, jj
ap, jj = ak, jj
ak, jj = dummy
END DO
dummy = bp
bp = bk
bk = dummy
dummy = sp
sp = sk
sk = dummy
END IF
END pivot
SUB Substitute (a, n, b, x)
xn = bn / an,n
DO i = n – 1, 1, -1
sum = 0
DO j = i + 1, n
sum = sum + ai,j * xj
END DO
xi = (bi – sum) / ai,i
END DO
END Substitute
31
1.4.4.- Programas en C
GAUSS JORDAN
#include <math.h>
#include <stdio.h> /*para printf(),scanf()*/
#include <conio.h> /*para getch(),clrscr()*/
//#include <stdlib.h>/*para exit()*/
//#include <dos.h>
#define NUMEL 20
#define INTERVALOS 0
float A[25][25], B[25], S[25],X[25];
MAIN
printf("\n METODO DE GAUSS JORDAN");
printf("\n\n Ingrese el numero de incognitas \n\n Numero de Ecuaciones = ");
scanf("%d",&n);
printf("\n Inserte cada uno de los coeficientes\n");
for(i=1;i<=n;i++)
{ printf("\n Fila %d \n",i);
for(j=1;j<=n+1;j++)
{ printf(" Ingrese a(%d,%d) = ",i,j);
scanf("%f",&a[i][j]);
}
}
m=n+1;
do
{ if(a[1][1]==0)
{k=m-1;
for(i=2;i<=k;i++)
{if(a[i][1]!=0)
{for(j=1;j<=m;j++)
{ apoyo=a[i][j];
a[i][j]=a[1][j];
a[1][j]=apoyo;
}
}
}
}
else
{for(j=2;j<=m;j++)
{for(i=2;i<=n;i++)
{b[i-1][j-1]=a[i][j]-a[1][j]*a[i][1]/a[1][1];}
}
for(j=2;j<=m;j++)
{b[n][j-1]=a[1][j]/a[1][1];}
m=m-1;
for(j=1;j<=m;j++)
{for(i=1;i<=n;i++)
{a[i][j]=b[i][j];}
}
}
}
while(m>1);
printf("\n\n RAICES DEL SISTEMA\n ");
for(i=1;i<=n;i++)
{printf("\n X(%d) = %1.4f",i,a[i][1]);}
printf("\n\n Fin del programa");
getch();
}
}
32
1.4.5.- Demostración del programa
33
2.- ECUACIONES NO LINEALES
2.1.- Definición y tipos de ecuaciones no lineales
En este capítulo estudiaremos diversos métodos para resolver ecuaciones no lineales
en una incógnita , aprovechando los conceptos básicos del cálculo y las
posibilidades gráficas y de cómputo de la tecnología moderna. Sistemáticamente a la
interpretación gráfica de los métodos, a fin de mostrar visualmente su funcionamiento y
de enriquecer las imágenes asociadas con ellos; de igual manera, se generan tablas
en la aplicación de cada técnica para analizar el comportamiento numérico y
eventualmente detener el proceso.
Se ha organizado el material como métodos de uno y dos puntos, de los segundos el
de posición falsa. Esto, junto con el concepto de orden de convergencia, nos permitirá
tener los elementos suficientes para seleccionar la técnica más adecuada para una
situación dada. Finalizamos el capítulo con las técnicas para resolver ecuaciones
polinomiales. El propósito de este capítulo es que el estudiante cuente con los
elementos básicos, computacionales y de criterio, apropiados para resolver el
problema algebraico clásico de encontrar las raíces reales y complejas de la ecuación
, en donde las técnicas algebraicas de "despejar" la incógnita no sean
aplicables, como es el caso de , o bien resulten imprácticas.
Por último, es importante señalar lo difícil que resulta pensar en un tópico de
matemáticas o ingeniería que no involucre ecuaciones de esta naturaleza.
La solución de este sistema consta de un conjunto de valores que simultáneamente
hacen que todas las ecuaciones sean iguales a cero.
Presentamos los métodos, para el caso en que las ecuaciones simultáneas son
lineales, es decir, que se puedan expresar en la forma general
son dos ecuaciones simultáneas no lineales con dos incógnitas, y , las cuales se
expresan en la forma de la ecuación como
34
2.2.- Bisección
Al aplicar las técnicas gráficas se observa que cambia de signo a ambos lados
de la raíz. En general, si es real y continúa en el intervalo que va desde hasta
y y tienen signos opuestos, es decir,
(Ec.2.1)
Figura 2.1
35
El método de bisección, conocido también como de corte binario, de partición de
intervalos o de Bolzano, es un tipo de búsqueda incremental en el que el intervalo
se divide siempre a la mitad. Si la función cambia de signo sobre un intervalo, se
evalúa el valor de la función en el punto medio. La posición de la raíz se determina
situándola sobre el punto medio del subintervalo, dentro del cual ocurre un cambio
de signo. El proceso se repite hasta obtener una mejor aproximación. En la figura
2.1 se presenta un algoritmo sencillo para los cálculos de la bisección. En la figura
2.3 se muestra una representación gráfica del método. Los siguientes ejemplos se
harán a través de cálculos reales involucrados en el método.
Figura 2.2
El método gráfico para determinar las raíces de una ecuación
Solución. El primer paso del método de bisección consiste en asignar dos valores
iniciales a la incógnita (en este problema, c) que den valores de con diferentes
signos. En la figura 2.2 se observa que la función cambia de signo entre los valores
12 y 16. Por lo tanto, la estimación inicial de la raíz se encontrará en el punto
medio del intervalo
36
que es mayor a cero y, por lo tanto, no ocurre cambio de signo entre el límite
inferior y el punto medio. En consecuencia, la raíz debe estar localizada entre 14 y
16.
Figura 2.3
Una representación gráfica del método de bisección. La gráfica presenta las
primeras tres iteraciones del ejemplo 2.2.1
37
Por lo tanto, la raíz está entre 14 y 15. El límite superior se redefine como 15 y la
raíz estimada para la tercera iteración se calcula así:
38
2.2.2.- Diagrama de Flujo
39
2.2.3.- Pseudocódigo
FUNCTION Bisect(xl, xu, es, imax, xr, iter, ea)
iter = 0
fl = f(xl)
DO
xrold = xr
xr = (xl + xu) / 2
fr = f( xr )
iter = iter + 1
IF xr 0 THEN
ea = ABS((xr – xrold) / xr) * 100
END IF
test = fl * fr
IF test 0 THEN
xu = xr
ELSE IF test 0 THEN
xl = xr
fl= fr
ELSE
ea = 0
END IF
IF ea es OR iter imax EXIT
END DO
Bisect = xr
END Bisect
40
2.2.4.- Programas en C
BISECCIÓN
#include <math.h>
#include <stdio.h> /*para printf(),scanf()*/
#include <conio.h> /*para getch(),clrscr()*/
//#include <stdlib.h>/*para exit()*/
//#include <dos.h>
#define NUMEL 20
#define INTERVALOS 0
float A[25][25], B[25], S[25],X[25];
MAIN
printf("\n METODO DE BISECCION\n");
printf( " Teclea valor minimo = ");
scanf("%f",&xmin);
printf("\n");
printf( " Teclea valor maximo = ");
scanf("%f",&xmax);
printf("\n");
printf( " Teclea valor de error esperado = ");
scanf("%f",&error);
printf("\n");
printf( " Teclea iteraciones maximas = ");
scanf("%f",&iteraciones);
printf("\n");
c1 = Bisect(xmin, xmax, error, iteraciones);
printf( " Resultado = %f", c1);
getch();
}
}
float Bisect( float x1,float xu, float es, int imax){
int iter;
float f1, fr, test;
float xold, xr, ea=0;
iter = 0;
f1 = F(x1, 10, 40, 68.1);
do{
xold = xr;
xr = (x1+xu)/2;
iter = iter +1;
if( xr != 0 ){
ea = abs((xr-xold)/xr)*100;
}
fr = F(xr, 10, 40, 68.1);
test = f1*fr;
if( test < 0 ){ // Se determina si hay una raiz entre x1 y xr, cambio de signo
xu = xr;
}
else if ( test > 0 ) {
x1 = xr;
f1 = fr;
}
else // Se encontro una raiz
ea = 0;
// imprimimos los resultados
printf( " No X1 Xu Xr ea et\n");
printf( " %d %6.3f %6.3f %6.3f %6.3f %6.3f \n", iter, x1, xu, xr, ea ) ;
}while( (ea >= es) || (iter<imax));
return xr;
}
41
2.2.5.- Demostración del programa
42
2.3.- Falsa Posición
en el cual se despeja
(Ec. 2.3)
43
Figura 2.4
Representación gráfica del método de la falsa posición con los triángulos
semejantes sombreados se obtiene la fórmula para el método.
Dividiendo entre
(Ec. 2.3a)
Ésta es una de las formas del método de la falsa posición. Observe que permite el
cálculo de la raíz como una función de los valores iniciales inferior y
superior . Ésta puede ponerse en una forma alternativa al separar los términos:
44
Agrupando términos se obtiene
La cual es la misma ecuación (Ec. 2.3). Se utiliza esta forma porque implica una
evaluación de la función y una multiplicación menos que la ecuación (Ec. 2.3a).
= 12
= 14.9113 f
45
el cual tiene errores relativos y verdadero y aproximado de 0.09 y 0.79 por ciento.
Es posible realizar iteraciones adicionales para hacer una mejor aproximación de
las raíces.
Se obtiene una idea más completa de la eficiencia de los métodos de bisección y
de falsa posición al observar la figura 3.5 donde se muestra el error relativo
porcentual verdadero de los ejemplos 3.3 y 3.3.1. Observe cómo el error decrece
mucho más rápidamente en el método de la falsa posición que en el de la
bisección, debido a un esquema más eficiente en el método de la falsa posición
para la localización de raíces.
Recuerde que en el método de bisección el intervalo entre y se va
haciendo más pequeño durante los cálculos. Por lo tanto, el intervalo, como se
define para la primera iteración, proporciona una medida del error en este método.
Éste no es el caso con el método de la falsa posición, ya que uno de los valores
iniciales puede permanecer fijo durante los cálculos, mientras que el otro converge
hacia la raíz. Como en el caso del ejemplo, el extremo inferior permanece en 12,
mientras que converge a la raíz. En tales casos, el intervalo no se acorta, sino
que se aproxima a un valor constante.
Figura 2.5
Comparación de los errores relativos de los métodos de bisección y de falsa
posición
46
2.3.2.- Diagrama de Flujo
47
2.3.3.- Pseudocódigo
48
2.3.4.- Programas en C
#include <math.h>
#include <stdio.h> /*para printf(),scanf()*/
#include <conio.h> /*para getch(),clrscr()*/
//#include <stdlib.h>/*para exit()*/
//#include <dos.h>
#define NUMEL 20
#define INTERVALOS 0
float A[25][25], B[25], S[25],X[25];
MAIN
49
float FalsePos( float x1,float xu, float es, int imax){
int iter=0, i1, iu;
float f1, fr, fu, test;
float xrold, xr, ea=0;
f1 = F(x1, 10, 40, 68.1);
fu = F(xu, 10, 40, 68.1);
do{
xrold = xr;
xr = xu-fu*(x1-xu)/(f1-fu);
fr = F(xr,10,40,68.1);
iter = iter +1;
if ( xr != 0 ) {
ea = abs( (xr - xrold)/xr )* 100;
}
test = f1 * fr;
if( test < 0 ) {
xu = xr;
fu = F(xu, 10, 40, 68.1);
iu = 0;
i1 = i1 + 1;
if ( i1 >= 2 )f1 = f1 / 2;
}
else if ( test > 0 ){
x1 = xr;
f1 = F(x1, 10, 40, 68.1);
i1 = 0;
iu = iu +1;
if( iu >= 2) fu = fu / 2;
}
else ea=0;
}while( (ea >= es) || (iter<imax));
return xr;
}
50
2.3.5.- Demostración del programa
51
2.4.- Newton-Raphson
Tal vez, de las fórmulas para localizar raíces, la fórmula de Newton-Raphson
(figura 2.6) sea la más ampliamente utilizada. Si el valor inicial para la raíz es ,
entonces se puede trazar una tangente desde el punto [ , ] de la curva. Por lo
común, el punto donde esta tangente cruza al eje x representa una aproximación
mejorada de la raíz.
Figura 2.6
Representación gráfica del método de Newton Raphson. Se extrapola una tangente
a la función en [esto es, ] hasta el eje x para obtener una estimación de la
raíz en .
f
f´ (Ec.2.4)
52
2.4.1.- Ejemplo propuesto
Planteamiento del problema. Utilice el método de Newton-Raphson para calcular
la raíz de empleando como valor inicial y se considere
como raíz real la iteración en donde exista una similitud de al menos 6 cifras
significativas con la iteración anterior.
Solución. La primera derivada de la función es
que se sustituye, junto con la función original en la ecuación (2.5), para tener
53
Empezando con un valor inicial , se obtuvieron los siguientes resultados:
0 0 100 '
1 0.500000000 11.8
2 0.566311003 0.147
3 0.567143165 0.0000220
4 0.567143290 <
54
2.4.2.- Diagrama de Flujo
INICIO
NGRAD,N,M,I,A,A
PROX,NRAIZ,X,N
MI,B,C,Y,REL
No convergen en
NMI iteraciones
55
2.4.3.- Pseudocódigo
function newtonIterationFunction(x) {
return x - (cos(x) - x^3) / (-sin(x) - 3*x^2)
}
var x := 0,5
for i from 0 to 99 {
print "Iteraciones: " i
print "Valor aproximado: " x
xold := x
x := newtonIterationFunction(x)
if x = xold {
print "Solución encontrada!"
break
}
}
2.4.4.- Programas en C
NEWTON RAPHSON
#include <conio.h>
#include <stdio.h>
#include <math.h>
MAIN
printf("\t\tMETODO DE NEWTON RAPHSON");
printf("\n\nintruce valor inicial");
printf("\n\nX=");
scanf("%f",&x1);
printf("\nIteraciones=");
scanf("%d",&I);
do
{
y=exp(-x1)-x1;
y2=-1*exp(-x1)-1;
xr=x1 - (y/y2);
a=((xr-x1)/xr)*100;
e=fabs(a);
x1=xr;
i++;
c++;
}
while(i<I);
printf("\n\n\n\nLa raiz aproximada es x%d = %.12f ",c,xr);
printf("\n\nError = %.3f",e);
getch();
}
56
2.4.3.- Demostración del programa
57
3.- ECUACIONES DIFERENCIALES ORDINARIAS
3.1.- Concepto y clasificación
En este capítulo se estudiarán, las técnicas numéricas de solución de ecuaciones
diferenciales con condiciones iniciales o de frontera, denominados problemas de valor
inicial o de frontera, respectivamente. Una ecuación diferencial ordinaria
(comúnmente abreviada "EDO") es una relación que contiene funciones de una sola
variable independiente, y una o más de sus derivadas con respecto a esa variable.
Para esto, se inicia formulando tales problemas, y luego, a partir de las ideas de
extrapolación, se plantean métodos como el de Euler. Más adelante, en un proceso
de ponderación de pendientes, se obtienen métodos con diferentes órdenes de
exactitud donde no se requiere de derivaciones complicadas de funciones, pagándose
como precio de ello un mayor número de cálculos. Tales métodos son conocidos
como métodos de Runge-Kutta. Basándose en el proceso de integración implicado en
la solución de las ecuaciones diferenciales y en la aproximación de funciones se
plantean familias de métodos denominados de predicción-corrección.
Dado que las ecuaciones diferenciales ordinarias permiten modelar procesos diná-
micos tales como: vaciado de recipientes, reactores químicos, movimientos
amortiguados, desarrollos poblacionales e incluso situaciones estáticas como la
deflexión de vigas y problemas geométricos. Estas técnicas analíticas son necesarias
para ciertas ecuaciones muy particulares.
Esta gran utilidad de las ecuaciones diferenciales es fácil de explicar; recuérdese que
si se tiene la función su derivada puede interpretarse como la
velocidad de cambio de y con respecto a . En cualquier proceso natural, las variables
incluidas y sus velocidades de cambio se relacionan entre sí mediante los principios
científicos que gobiernan el proceso. El resultado de expresar en símbolos
matemáticos estas relaciones, a menudo es una ecuación diferencial.
58
3.2.- Euler
Este tema se refiere a la solución de ecuaciones diferenciales ordinarias de la forma
De acuerdo con esta ecuación, la pendiente estimada se usa para extrapolar desde
un valor anterior a un nuevo valor en una distancia (figura 3.1). Esta fórmula
se aplica paso a paso para calcular un valor posterior y, por lo tanto, para trazar la
trayectoria de la solución.
En otras palabras, se toma la pendiente al inicio del intervalo como una aproximación
de la pendiente promedio sobre todo el intervalo.
Figura 3.1
Ilustración gráfica del método de un paso.
59
La primera derivada ofrece una estimación directa de la pendiente en (figura 3.2):
Figura 3.2
Método de Euler.
60
Solución. Se utiliza la ecuación (Ec.3.2) para implementar el método de
Euler:
Por lo tanto,
La solución verdadera en es
Así, el error es
61
Tabla 3.2.1
Error relativo
porcentual
Figura 3.3
Comparación de la solución verdadera con una solución numérica usando el método
de Euler, para la integral de y' = -2X3 + 1 2X2 - 20x + 8.5 desde x = O hasta x = 4 con
un tamaño de paso de 0.5. La condición inicial en x = O es y = 1.
62
Observe que aunque el cálculo capta la tendencia general de la solución verdadera, el
error resulta considerable. Como se explica en la siguiente sección, es posible reducir
tal error usando un tamaño de paso menor.
El ejemplo anterior usa un polinomio simple como ecuación diferencial con el objetivo
de facilitar el siguiente análisis de error. De esta forma,
En efecto, un caso más general (y más común) implica EDO, donde aparece una
función que depende tanto de como de ,
Conforme avancemos en esta parte del texto, nuestros ejemplos comprenderán EDO
que dependen de variables independientes y dependientes.
63
3.2.2.- Diagrama de flujo
64
3.2.3.- Pseudocódigo
‘ nt rva o nt grac ón
xi = 0
xf = 4
‘var ab s n c a s
x = xi
y=1
‘ stab c tamaño paso t rm na
‘ núm ro pasos cá c o
dx = 0.5
nc= (xf – xi) /dx
‘con c on s sa a
PRINT x,y
´ciclo para implementar el método de Euler
‘ sp g r s ta os
DO i = 1, nc
dydx = -2x3 +12x2 – 20x + 8.5
y = y + dydx . dx
x= x + dx
PRINT x, y
END DO
65
3.2.4.- Programas en C
EULER
#include <iostream.h>
#include <iomanip.h>
#include <conio.h>
#include <math.h>
#include <stdlib.h>
#include <dos.h>
MAIN
return (-2*pow(x,3))+(12*pow(x,2))-(20*x)+8.5;
case EULER: Lee(x0,xf,y0,h);
Euler(x0,xf,y0,h);
getch();
break;
case SALIR: gotoxy(34,20);
cout<<"Fin de "<<__FILE__;
gotoxy(34,21);
cout<<"Espere un momento...";
sleep(1);
exit(0);
break;
default: gotoxy(34,15);
cout<<"Opcion no permitida";
getch();
break;
}
}while(op!=SALIR);
return 0;
}
cout<<" METODO DE EULER ";
gotoxy(10,4);
cout<<"Xo = "<<setw(10)<<setprecision(5)<<x0;
gotoxy(10,5);
cout<<"Xf = "<<setw(10)<<setprecision(5)<<xf;
gotoxy(10,6);
cout<<"Yo = "<<setw(10)<<setprecision(5)<<y0;
gotoxy(10,7);
cout<<"h = "<<setw(10)<<setprecision(5)<<h;
gotoxy(10,9);
cout<<" x y";
gotoxy(9,10);
cout<<"----------------------";
cout<<endl;
cout<<setw(10) <<setprecision(5) << setiosflags(ios::fixed) << x;
cout<<setw(20) <<setprecision(5) << setiosflags(ios::fixed) << y << endl;
while(x<xf){
y+=h*f(x,y);
x+=h;
cout<<setw(10) <<setprecision(5) << setiosflags(ios::fixed) << x
<<setw(20) <<setprecision(5) << setiosflags(ios::fixed) << y <<
endl;
}
}
void Heun(float x0,float xf,float y0,float h)
{
66
3.2.5. - Demostración del programa
67
3.3.-Runge-Kutta
El método de Runge-Kutta (RK) logra la exactitud del procedimiento de la serie
Taylor sin necesitar el cálculo de derivadas de orden superior. Existen muchas
variantes, pero todas tienen la forma generalizada de la siguiente ecuación.
(Ec.3.3)
(Ec.3.4)
(Ec.3.4a)
(Ec.3.4b)
(Ec.3.4c)
.
.
.
(Ec.3.4d)
donde las y son constantes. Observe que las son relaciones de recurrencia.
Es decir, aparecen en la ecuación , la cual aparece en la ecuación , etcétera.
Como cada es una evaluación funcional, esta recurrencia vuelve eficiente al método
de RK para cálculos en computadora.
68
MÉTODO DE RUNGE KUTTA DE SEGUNDO ORDEN
La segunda versión de segundo orden de la ecuación (Ec.3.3) es
(Ec.3.5)
donde
(Ec.3.5a)
(Ec.3.5b)
0.0 1 1.00000 0
0.5 .0000
3.21875 3.277344 1.8
1.0 0
3.00000 3.101563 3.4..
1.5 2.21875 2.347656 5.8
2.0 2.00000 2.140625 7.0
2.5 2.71875 2.855469 5.0
3.0 4.00000 4.117188 2.9
3.5 . 4.71875 4.800781 1.7
4.0 3.00000 3.031250 1.0
69
En el primer intervalo también es igual a 8.5 y
70
3.3.2.-Diagrama de flujo
71
3.3.3.- Pseudocódigo
x = xi
m= 0
xpm = x
DO I = 1, n
ypi,m = yi
END DO
DO
xend = x + xout
IF (xend xf) THEN xend = xf
h= dx
CALL Integrador (x, y, n, h, xend)
m=m+1
xpm = x
DO i = 1, n
ypi,m = yi
END DO
IF (x xf) EXIT
LOOP
DISPLAY RESULTS
END
72
b) Rutina para tomar un paso de salida
SUB integrator (x, y, n, h, xend)
DO
IF (xend – x < h) THEN h = xend – x
CALL RK4 (x, y, n, h)
IF (x xend) EXIT
END DO
END SUB
c) Método RK de cuarto orden para un sistema de EDO
SUB RK4(x, y, n, h)
CALL Derivs (x, y, k1)
DO i = 1, n
ymi = yi + k1i * h / 2
END DO
CALL Derivs (x + h / 2, ym, k2)
DO i = 1, n
ymi = yi + k2i * h / 2
END DO
CALL Derivs (x + h / 2, ym, k3)
DO i = 1, n
yei = yi + k3i * h
END DO
CALL Derivs (x + h, ye, k4)
DO i = 1, n
slopei = (k1i + 2* (k2i+k3i)+k4i)/6
yi = yi + slopei * h
END DO
x=x+h
END SUB
d) Rutina para determinar derivadas
SUB Derivs (x, y, dy)
dy1 = …
dy2 = ….
END SUB
73
3.3.4.- Programas en C
RUNGE KUTTA
#include <iostream.h>
#include <iomanip.h>
#include <conio.h>
#include <math.h>
#include <stdlib.h>
#include <dos.h>
MAIN
return 4*exp(0.8*x)-(0.5*y);
case RK2: Lee(x0,xf,y0,h);
Heun(x0,xf,y0,h);
getch();
break;
case SALIR: gotoxy(34,20);
cout<<"Fin de "<<__FILE__;
gotoxy(34,21);
cout<<"Espere un momento...";
sleep(1);
exit(0);
break;
default: gotoxy(34,15);
cout<<"Opcion no permitida";
getch();
break;
}
}while(op!=SALIR);
return 0;
}
cout<<"METODO DE HEUN (RK Orden 2)"<<endl;
gotoxy(10,4);
cout<<"Xo = "<< setw(10) << setprecision(5) <<x0;
gotoxy(10,5);
cout<<"Xf = "<< setw(10) << setprecision(5) <<xf;
gotoxy(10,6);
cout<<"Yo = "<< setw(10) << setprecision(5) <<y0;
gotoxy(10,7);
cout<<"h = "<< setw(10) << setprecision(5) <<h;
gotoxy(10,9);
cout<<"x y";
gotoxy(9,10);
cout<<"----------------------";
cout<<endl;
cout<<setw(10) << setprecision(5) << setiosflags(ios::fixed) << x;
cout<<setw(20) << setprecision(5) << setiosflags(ios::fixed) << y <<endl;
while(x<xf){
k1=h*f(x,y);
k2=h*f(x+h,y+k1);
y+=(k1/2.0+k2/2.0);
x+=h;
cout<<setw(10) << setprecision(5) << setiosflags(ios::fixed) << x
<<setw(20) << setprecision(5) << setiosflags(ios::fixed) << y
<<endl;
}
}
void rk4(float x0,float xf,float y0,float h)
{
74
3.3.5.- Demostración del programa
75
4.- INTEGRACIÓN
4.1.- Concepto y clasificación
En este capítulo se abordará el tema clásico de integración definida. Para ello se
utilizarán procesos finitos, en los que a diferencia de los métodos analíticos, donde
el concepto de límite es central y por tanto los procesos infinitos se manejan
conjuntos de puntos discretos y haremos pasar por ellos o entre ellos un polinomio,
para después integrar o derivar dicho polinomio. Con esta técnica podremos
integrar y derivar funciones dadas tabularmente o bien funciones analíticas muy
complejas e, incluso, integrar aq é as c a nt gra “no st ”, como s n caso
de
s n cos
s n tc
Figura 4.1a
a) Descripción gráfica de la regla de Simpson 1/3, que consiste en tomar el
área bajo una parábola que une tres puntos.
76
Figura 4.1b
b) Descripción gráfica de la regla de Simpson 3/8 que consiste en tomar el área
bajo una ecuación cubica que une cuatro puntos.
f f
f f f (Ec.4.1)
77
donde, en este caso, . Esta ecuación se conoce como regla de
Simpson 1/3, y es la segunda fórmula de integración cerrada de Newton-Cotes. La
especificación "1/3" se origina del hecho de que está dividida entre 3 en la
ecuación (Ec.4.1). Una alternativa para obtenerla se integra el polinomio de Newton-
Gregory para llegar a la misma fórmula.
f f f
a b (Ec.4.2)
Ancho Altura promedio
donde a b y el punto a la mitad entre a y b , que está dado por
(b+a)/2. Observe que, de acuerdo con la ecuación (Ec.4.2), el punto medio está
ponderado por dos tercios; y los dos puntos extremos, por un sexto.
t f
o como
b a
t f (Ec.4.3)
78
Aplicación simple de la regla de Simpson 1/3
Planteamiento del problema. Con la ecuación (Ec.4.2) integre
que es aproximadamente 5 veces más precisa que una sola aplicación de la regla
del trapecio
El error estimado es [(Ec.4.2.2)]
79
4.2.2.- Diagrama de flujo
INICIO
n_s, n_p, h, b,
a, x_j, j, k, i
scanf("%d",&n);
if(n<1){
_error(INTERVALOS);
exit(1);
}
else
printf("\n Valor de a =>");
scanf("%f",&a);
printf("\n Valor de b =>");
scanf("%f",&b);
}
82
4.2.5.- Demostración del programa
83
COSTOS
84
CAPITULO III
APORTACIONES Y CONTRIBUCIONES AL DESARROLLO
Una de las razones por la que se elaboró este manual, es para que el estudiante
tenga como apoyo en la experiencia de métodos numéricos, programas para
aplicar los métodos, brindándoles así una herramienta que podrán utilizar y les
permitirá ahorrar tiempo y esfuerzo.
Con este trabajo práctico educativo se pretende que al estudiante le sea de mucha
utilidad y disponga de una herramienta más, principalmente a los estudiantes de
ingeniería que cursen la experiencia educativa de métodos numéricos con el fin de
que logre una mayor comprensión de los temas mencionados, utilizando como
estrategia de aprendizaje el uso de programas que ayuden a agilizar el
procedimiento de los métodos expuestos en este tema.
86
BIBLIOGRAFÍA
MÉTODOS NUMÉRICOS
LUTHE OLVERA SCHUTZ
87
ANEXOS
Anexo A
DIAGRAMAS DE FLUJO
TERMINAL:
DEFINICIÓN DE VARIABLES:
PROCESO:
DECISIÓN:
ENTRADA:
SALIDA:
88
Anexo B
CICLOS
Ciclos: Son procesos repetitivos los cuales se ejecutan una o más instrucciones
varias veces.
Valor Final: Con este valor indicamos la última vez que el ciclo debe ejecutarse.
89
Anexo C
PRINCIPIOS DE C
En este anexo se ofrece una breve historia del desarrollo del lenguaje C y se
consideran también sus características.
ORÍGENES DEL C
CARACTERÍSTICAS DE C
Algunas de las características más importantes que definen el lenguaje y que han
permitido que sea tan popular, como lenguaje de programación son:
Tamaño pequeño.
Uso extensivo de llamadas a funciones.
Comandos breves (poco tecleo).
Lenguaje estructurado.
Programación de bajo nivel (nivel bit)
Implementación de apuntadores - uso extensivo de apuntadores para la memoria,
arreglos, estructuras y funciones
Las diversas razones por la cual se ha convertido en un lenguaje de uso
profesional son:
El uso de constructores de alto nivel.
El poder manejar actividades de bajo-nivel.
El generar programas eficientes.
La posibilidad de poder ser compilado en una variedad de computadoras, con
90
pocos cambios (portabilidad).
Un punto en contra es que tiene una detección pobre de errores, lo cual en
ocasiones es problemático para los principiantes.
Estructura de un programa en C
Un programa de C tiene básicamente la siguiente forma:
Comandos del preprocesador.
Definiciones de tipos.
Prototipos de funciones - declara el tipo de función y las variables pasadas a la
misma.
Variables
Funciones
Para un programa se debe tener una función main().
Una función tiene la forma:
tipo nombre_de_la_funcion (parámetros)
{
variables locales
sentencias de C
Si la definición del tipo es omitida, C asume que la función regresa un tipo entero.
Nota: Lo anterior puede ser una fuente de problemas en un programa.
A continuación se muestra un primer programa:
/* Programa ejemplo */
main()
{
NOTAS:
C requiere un punto y coma al final de cada sentencia.
printf es una función estándar de C, la cual es llamada en la función main().
\n significa salto de línea. Salida formateada.
exit() es también una función estándar que hace que el programa termine. En el
sentido estricto no es necesario ya que es la última línea de main() y de cualquier
forma terminará el programa.
En caso de que se hubiera llamado a la función printf de la siguiente forma:
printf(".\n.1\n..2\n...3\n");
La salida tendría la siguiente forma:
.1
..2
...3
91
VARIABLES
Float 4
double 8
Los tipos de datos básicos tiene varios modificadores que les preceden. Se usa un
modificador para alterar el significado de un tipo base para que encaje con las
diversas necesidades o situaciones. Los modificadores son: signed, unsigned, long
y short.
En los sistemas UNIX todos los tipos int son long int, a menos que se especifique
explícitamente short int.
Nota: no hay un tipo booleano en C -- se deberá usar char, int o aún mejor
unsigned char.
signed, unsigned, long y short pueden ser usados con los tipos char e int. Aunque
es permitido el uso de signed en enteros, es redundante porque la declaración de
entero por defecto asume un número con signo.
Para declarar una variable en C, se debe seguir el siguiente formato:
tipo lista_variables;
tipo es un tipo válido de C y lista_variables puede consistir en uno o más
identificadores separados por una coma. Un identificador debe comenzar con una
letra o un guión bajo.
Ejemplo:
int i, j, k;
float x,y,z;
char ch;
92
DEFINICIÓN DE VARIABLES GLOBALES
Una variable global se declara fuera de todas las funciones, incluyendo a la función
main(). Una variable global puede ser utilizada en cualquier parte del programa.
Por ejemplo:
short numero, suma;
int numerogr, sumagr;
char letra;
main()
{
...
}
main()
{
...
}
main()
{
suma = 0.0;
sumagr= 0;
letra = 'A';
...
}
La asignación múltiple se puede llevar a cabo, si todos los tipos de las variables
son iguales.
Se pueden redefinir los tipos de C usando typedef. Como un ejemplo de un simple
uso se considera como se crean dos nuevos tipos real y letra. Estos nuevos tipos
pueden ser usados de igual forma como los tipos predefinidos de C.
typedef float real;
typedef char letra;
Observar que se antepone & a los nombres de las variables, excepto a la cadena
de caracteres.
CONSTANTES
Notas:
Se puede usar constantes o después del tipo.
94
Es usual inicializar una constante con un valor, ya que no puede ser cambiada de
alguna otra forma.
OPERADORES ARITMÉTICOS
main()
{
x=( ( ++z ) - ( y-- ) ) % 100;
}
Que es equivalente a:
int x,y,z;
main()
{
z++;
x = ( z-y ) % 100;
y--;
}
OPERADORES DE COMPARACIÓN
El operador para probar la igualdad es ==, por lo que se deberá tener cuidado de
no escribir accidentalmente sólo =, ya que:
if ( i = j ) ...
Es una sentencia legal de C (sintácticamente hablando aunque el compilador avisa
cuando se emplea), la cual copia el valor de ``j'' en ``i'', lo cual será interpretado
como VERDADERO, si j es diferente de cero.
Diferente es !=, otros operadores son: < menor que, > mayor que, <= menor que o
igual a y >= (mayor que o igual a).
OPERADORES LÓGICOS
ORDEN DE PRECEDENCIA
como
a=
(b=
( 10 / 5 )
+ 2 );
ESTRUCTURAS CONDICIONALES
En este capítulo se revisan los distintos métodos con los que C controla el flujo
lógico de un programa.
Como se revisó en el capítulo anterior, los operadores relaciones binarios que se
usan son:
==, !=, <, <=, > y >=
además los operadores lógicos binarios:
||, &&
y el operador lógico unario de negación !, que sólo toma un argumento.
Los operadores anteriores son usados con las siguientes estructuras que se
muestran.
97
LA SENTENCIA IF
if (condición)
sentencia;
...o
if (condición)
sentencia1;
else
sentencia2;
...o
if (condicion1)
sentencia1;
else if (condicion2)
sentencia2;
...
else
sentencian;
El flujo lógico de esta estructura es de arriba hacia abajo. La primera sentencia se
ejecutará y se saldrá de la estructura if si la primera condición es verdadera. Si la
primera condición fue falsa, y existe otra condición, se evalúa, y si la condición es
verdadera, entonces se ejecuta la sentencia asociada. Si existen más condiciones
dentro de la estructura if, se van evaluando éstas, siempre y cuando las
condiciones que le precedan sean falsas.
La sentencia que está asociada a la palabra reservada else, se ejecuta si todas las
condiciones de la estructura if fueron falsas.
Por ejemplo:
main()
{
int x, y, w;
........
if (x>0)
{
z=w;
.......
}
else
{
z=y;
.......
}
}
98
EL OPERADOR “?”
El uso del operador “?” para reemplazar las sentencias if ... else no se restringe
sólo a asignaciones, como en el ejemplo anterior. Se pueden ejecutar una o más
llamadas de función usando el operador ? poniéndolas en las expresiones que
forman los operandos, como en el ejemplo siguiente:
f1(int n)
{
printf("%d ",n);
}
f2()
{
printf("introducido\n");
}
main()
{
int t;
printf(": ");
scanf("%d",&t);
99
LA SENTENCIA SWITCH
switch (variable) {
case constante1:
secuencia de sentencias
break;
case constante2:
secuencia de sentencias
break;
case constante3:
secuencia de sentencias
break;
...
default:
secuencia de sentencias
}
Donde la computadora ejecuta la sentencia default si no coincide ninguna
constante con la variable, esta última es opcional. Cuando se encuentra una
coincidencia, la computadora ejecuta las sentencias asociadas con el case hasta
encontrar la sentencia break con lo que sale de la estructura switch.
Las limitaciones que tiene la sentencia switch ... case respecto a la estructura if
son:
Sólo se tiene posibilidad de revisar una sola variable.
Con switch sólo se puede comprobar por igualdad, mientras que con if puede ser
con cualquier operador relacional.
No se puede probar más de una constante por case.
La forma como se puede simular el último punto, es no teniendo sentencias
asociados a un case, es decir, teniendo una sentencia nula donde sólo se pone el
caso, con lo que se permite que el flujo del programa caiga al omitir las sentencias,
como se muestra a continuación:
switch (letra)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
numvocales++;
break;
100
case ' ':
numesp++;
break;
default:
numotras++;
break;
}
ITERACIÓN
LA SENTENCIA FOR
main()
{
for( X=3; X>0; X--)
{
printf("X=%d\n",X);
}
}
101
Todos las siguientes sentencias for son válidas en C. Las aplicaciones prácticas de
tales sentencias no son importantes aquí, ya que tan sólo se intenta ilustrar
algunas características que pueden ser de utilidad:
for ( x=0; ( (x>3) && (x<9) ); x++ )
LA SENTENCIA WHILE
donde sentencia puede ser una sentencia vacía, una sentencia única o un bloque
de sentencias que se repetirán. Cuando el flujo del programa llega a esta
instrucción, primero se revisa si la condición es verdad para ejecutar la(s)
sentencia(s), y después el ciclo while se repetirá mientras la condición sea
verdadera. Cuando llega a ser falsa, el control del programa pasa a la línea que
sigue al ciclo.
En el siguiente ejemplo se muestra una rutina de entrada desde el teclado, la cual
se cicla mientras no se pulse A:
main()
{
char carac;
carac = '\0';
while( carac != 'A') carac = getchar();
}
102
A continuación mostramos otro ejemplo:
main()
{
int x=3;
while( x>0 )
{
printf("x = %d\n", x);
x--;
}
}
Como se observa, dentro del ciclo tenemos más de una sentencia, por lo que se
requiere usar la llave abierta y la llave cerrada { ... } para que el grupo de
sentencias sean tratadas como una unidad.
Como el ciclo while pueda aceptar también expresiones, y no solamente
condiciones lo siguiente es válido:
while ( x-- );
while ( x = x + 1 );
while ( x += 5 );
carac = '\0';
while ( (carac = getchar()) != 'A' )
putchar(carac);
}
LA SENTENCIA DO-WHILE
Al contrario de los ciclos for y while que comprueban la condición en lo alto del
bucle, el bucle do ... while la examina en la parte baja del mismo. Esta
característica provoca que un ciclo do ... while siempre se ejecute al menos una
103
vez. La forma general del ciclo es:
do {
sentencia;
} while (condición);
Aunque no son necesarias las llaves cuando sólo está presente una sentencia, se
usan normalmente por legibilidad y para evitar confusión (respecto al lector, y no
del compilador) con la sentencia while.
En el siguiente programa se usa un ciclo do ... while para leer números desde el
teclado hasta que uno de ellos es menor que o igual a 100:
main()
{
int num;
do
{
scanf("%d", &num);
} while ( num>100 );
}
Otro uso común de la estructura do... while es una rutina de selección en un menú,
ya que siempre se requiere que se ejecute al menos una vez.
main()
{
int opc;
printf("1. Derivadas\n");
printf("2. Limites\n");
printf("3. Integrales\n");
do
{
printf(" Teclear una opcion: ");
scanf("%d", &opc);
switch(opc)
{
case 1:
printf("\tOpcion 1 seleccionada\n\n");
break;
case 2:
printf("\tOpcion 2 seleccionada\n\n");
break;
case 3:
printf("\tOpcion 3 seleccionada\n\n");
break;
default:
printf("\tOpcion no disponible\n\n");
break;
}
104
} while( opc != 1 && opc != 2 && opc != 3);
}
Se muestra un ejemplo donde se reescribe usando do... while uno de los ejemplos
ya mostrados.
main()
{
int x=3;
do
{
printf("x = %d\n", x--);
}
while( x>0 ) ;
}
Este programa muestra en pantalla los números del 0 al 10, cuando alcanza el
valor 10 se cumple la condición de la sentencia if, se ejecuta la sentencia break y
sale del ciclo.
La sentencia continue funciona de manera similar a la sentencia break. Sin
embargo, en vez de forzar la salida, continue fuerza la siguiente iteración, por lo
que salta el código que falta para llegar a probar la condición. Por ejemplo, el
siguiente programa visualizará sólo los números pares:
main()
{
int x;
if ( valor>100)
{
printf("Valor no valido\n");
continue;
/* Pasar al principio del ciclo nuevamente */
}
Los arreglos son una colección de variables del mismo tipo que se referencian
utilizando un nombre común. Un arreglo consta de posiciones de memoria
contigua. La dirección más baja corresponde al primer elemento y la más alta al
último. Un arreglo puede tener una o varias dimensiones. Para acceder a un
elemento en particular de un arreglo se usa un índice.
El formato para declarar un arreglo unidimensional es:
tipo nombre_arr [ tamaño ]
Por ejemplo, para declarar un arreglo de enteros llamado listanum con diez
elementos se hace de la siguiente forma:
int listanum[10];
En C, todos los arreglos usan cero como índice para el primer elemento. Por tanto,
el ejemplo anterior declara un arreglo de enteros con diez elementos desde
listanum[0] hasta listanum[9].
La forma como pueden ser accesados los elementos de un arreglo, es de la
siguiente forma:
106
listanum[2] = 15; /* Asigna 15 al 3er elemento del arreglo listanum*/
num = listanum[2]; /* Asigna el contenido del 3er elemento a la variable num */
Observar que para declarar cada dimensión lleva sus propios paréntesis
cuadrados.
Para acceder los elementos se procede de forma similar al ejemplo del arreglo
unidimensional, esto es,
tabladenums[2][3] = 15; /* Asigna 15 al elemento de la 3ª fila y la 4ª columna*/
num = tabladenums[25][16];
107
CADENAS
Para asignar la entrada estándar a una cadena se puede usar la función scanf con
la opción %s (observar que no se requiere usar el operador &), de igual forma para
mostrarlo en la salida estándar.
Por ejemplo:
main()
{
char nombre[15], apellidos[30];
Funciones
Una función es un conjunto de declaraciones, definiciones, expresiones y
sentencias que realizan una tarea específica.
108
El formato general de una función en C es:
main()
{
int a=7, b=10;
float resultado;
FUNCIONES VOID
Las funciones void dan una forma de emular, lo que en otros lenguajes se conocen
como procedimientos (por ejemplo, en PASCAL). Se usan cuando no requiere
regresar un valor. Se muestra un ejemplo que imprime los cuadrados de ciertos
números.
void cuadrados()
{
int contador;
main()
{
109
cuadrados();
}
FUNCIONES Y ARREGLOS
main()
{
char nombre[]="Facultad";
imp_rev(nombre);
}
main()
{
float numeros[]={2.3, 8.0, 15.0, 20.2, 44.01, -3.0, -2.9};
PROTOTIPOS DE FUNCIONES
Antes de usar una función C debe tener conocimiento acerca del tipo de dato que
regresará y el tipo de los parámetros que la función espera.
El estándar ANSI de C introdujo una nueva (mejor) forma de hacer lo anterior
respecto a las versiones previas de C.
La importancia de usar prototipos de funciones es la siguiente:
Se hace el código más estructurado y por lo tanto, más fácil de leer.
Se permite al compilador de C revisar la sintaxis de las funciones llamadas.
Lo anterior es hecho, dependiendo del alcance de la función. Básicamente si una
función ha sido definida antes de que sea usada (o llamada), entonces se puede
usar la función sin problemas.
Si no es así, entonces la función se debe declarar. La declaración simplemente
maneja el tipo de dato que la función regresa y el tipo de parámetros usados por la
función.
Es una práctica usual y conveniente escribir el prototipo de todas las funciones al
principio del programa, sin embargo esto no es estrictamente necesario.
Para declarar un prototipo de una función se indicará el tipo de dato que regresará
la función, el nombre de la función y entre paréntesis la lista del tipo de los
parámetros de acuerdo al orden que aparecen en la definición de la función. Por
ejemplo:
int longcad(char []);
Lo anterior declara una función llamada longcad que regresa un valor entero y
acepta una cadena como parámetro.
111