Está en la página 1de 115

UNIVERSIDAD VERACRUZANA

FACULTAD DE INGENIERÍA MECÁNICA ELÉCTRICA

“MANUAL DE PROGRAMAS APLICADOS A MÉTODOS NUMÉRICOS”

TRABAJO PRÁCTICO EDUCATIVO

PARA ACREDITAR LA EXPERIENCIA EDUCATIV A DE:


TRABAJO RECEPCIONAL

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

DIRECTOR DE TRABAJO PRÁCTICO EDUCATIVO:


ISC. KARLOS REYES ORTEGA

POZA RICA DE HGO; VER. 2011


ÍNDICE
INTRODUCCIÓN 1
CAPITULO I
JUSTIFICACIÓN 3

TIPO Y NATURALEZA DEL TRABAJO 3

CARACTERÍSTICAS Y FUNCIONES ESCENCIALES 3


CAPITULO II
PROCESOS DEL TRABAJO

6
1.- ECUACIONES LINEALES

1.1.- Definición y clasificación 6

1.2.- Gauss Simple 6

1.2.1.- Ejemplo propuesto 9

1.2.2.- Diagrama de Flujo 11

1.2.3.- Pseudocódigo 13

1.2.4.- Programas en C 13

1.2.5.- Demostración del Programa 15

1.3.- Gauss Seidel 16

1.3.1.- Ejemplo propuesto 17

1.3.2.- Diagrama de Flujo 19

1.3.3.- Pseudocódigo 20

1.3.4.- Programas en C 21

1.3.5.- Demostración del Programa 23

1.4.- Gauss Jordan 25

1.4.1.- Ejemplo propuesto 25

1.4.2.- Diagrama de Flujo 28

1.4.3.- Pseudocódigo 30

1.4.4.- Programas en C 32
1.4.5.- Demostración del Programa 33

2.- ECUACIONES NO LINEALES 34

2.1.- Definición y tipos de ecuaciones no lineales 34

2.2.- Bisección 35

2.2.1.- Ejemplo propuesto 36

2.2.2.- Diagrama de Flujo 39

2.2.3.- Pseudocódigo 40

2.2.4.- Programas en C 41

2.2.5.- Demostración del Programa 42

2.3.- Falsa Posición 43

2.3.1.- Ejemplo propuesto 45

2.3.2.- Diagrama de Flujo 47

2.3.3.- Pseudocódigo 48

2.3.4.- Programas en C 49

2.3.5.- Demostración del Programa 51

2.4.- Newton-Raphson 52

2.4.1.- Ejemplo propuesto 53

2.4.2.- Diagrama de Flujo 55

2.4.3.- Pseudocódigo 56

2.4.4.- Programas en C 56

2.4.5.- Demostración del Programa 57

3.- ECUACIONES DIFERENCIALES ORDINARIAS 58

3.1.- Concepto y clasificación 58

3.2.- Euler 59

3.2.1.- Ejemplo propuesto 60

3.2.2.- Diagrama de Flujo 64

3.2.3.- Pseudocódigo 65
3.2.4.- Programas en C 66

3.2.5.- Demostración del Programa 67

3.3.-Runge-Kutta 68

3.3.1.- Ejemplo propuesto 69

3.3.2.- Diagrama de Flujo 71

3.3.3.- Pseudocódigo 72

3.3.4.- Programas en C 74

3.3.5.- Demostración del Programa 75

4.- INTEGRACIÓN 76

4.1.- Concepto y clasificación 76

4.2.- Simpson 1/3 76

4.2.1.- Ejemplo propuesto 77

4.2.2.- Diagrama de Flujo 80

4.2.3.- Pseudocódigo 81

4.2.4.- Programas en C 82

4.2.5.- Demostración del Programa 83


COSTOS 84

CAPITULO III

APORTACIONES Y CONTRIBUCIONES AL DESARROLLO 86

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

Dada la importancia que tienen los métodos numéricos en ingeniería, el alumno


necesita entender y comprender la experiencia educativa no solo desde un enfoque
teórico sino también práctico, entendido esto como la generación de los programas
para aplicar los métodos aprendidos durante la experiencia educativa, brindándoles
así una herramienta que podrán utilizar en el ámbito laboral y les permitirá ahorrar
tiempo y esfuerzo, debido a que mediante la aplicación de los métodos numéricos
es posible manejar sistemas de ecuaciones grandes los cuales de otra forma serian
difíciles de resolver de forma analítica.
Sin embargo, ésta materia actualmente no cuenta con un manual para el desarrollo
de los programas que apliquen los diferentes métodos vistos en clase; por tal
motivo, éste trabajo pretende ser una guía al momento de cursar esta experiencia y
ahorrar tiempo al alumno en la investigación del programa, desarrollo y aplicación
de los mismos.

TIPO Y NATURALEZA DEL TRABAJO

El tipo de trabajo es práctico educativo donde la información será seleccionada y


estructurada con el fin de contribuir en el aprendizaje de los estudiantes y como
soporte académico para los docentes que imparten la experiencia educativa de
métodos numéricos dentro de la Universidad Veracruzana, así mismo permitirá
mejorar las bases para la aplicación de los métodos numéricos mediante programas
los cuales sirven como herramienta para la solución de problemas en ingeniería.

CARACTERÍSTICAS Y FUNCIONES ESCENCIALES

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.

1.2.- Gauss Simple


Esta técnica básica puede extenderse a sistemas grandes de ecuaciones
desarrollando un esquema sistemático o algorítmico para eliminar incógnitas y
sustituir hacia atrás.
La eliminación de Gauss es el más básico de dichos esquemas.
Aquí se presentan las técnicas sistemáticas para la eliminación hacia adelante y la
sustitución hacia atrás que la eliminación gaussiana comprende. Dado que éstas
técnicas son muy adecuadas para utilizarse en computadoras, se requieren algunas
modificaciones para obtener un algoritmo confiable. En particular, el programa debe
evitar la división entre cero. Al siguiente método se le llama eliminación gaussiana
simple, ya que no evita este problema.

6
El método está ideado para resolver un sistema general de n ecuaciones:

a11x1+a12x2+a13x3+….+a1nxn=b1 (Ec. 1.1a)


a21x1+a22x2+a23x3+….+a2nxn=b2 (Ec. 1.1b)
. .
. .
an1x1+an2x2+an3x3+….+annxn=bn (Ec. 1.1c)

Como en el caso de dos ecuaciones, la técnica para resolver ecuaciones consiste


en dos fases: la eliminación de las incógnitas y su solución mediante sustitución
hacia atrás.

La eliminación hacia adelante de incógnitas. La primera fase consiste en reducir el


conjunto de ecuaciones a un sistema triangular superior (figura 1.1). El paso inicial
será eliminar la primera incógnita, x1, desde la segunda hasta la n-ésima ecuación.
Para ello se multiplica la ecuación (Ec. 1.1) por para obtener

(Ec. 1.2)

Ahora, esta ecuación se resta de la ecuación (Ec. 1.2) para dar

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:

a11x1+a12x2+a13x3+….+a1nxn=b1 (Ec. 1.3a)


a´22x2+a´23x3+….+a´2nxn=b´2 (Ec. 1.3b)
a´32x2+a´33x3+….+a´3nxn=b´3 (Ec. 1.3c)
a´n2x2+a´n3x3+….+a´nnxn=b´n (Ec. 1.3d)
En los pasos anteriores, la ecuación (Ec. 1.1a) se llama la ecuación pivote, y se
denomina el coeficiente o elemento pivote. Observe que el proceso de multiplicación
del primer renglón por es equivalente a dividirla entre y multiplicarla por
. Algunas veces la operación de división es referida a la normalización. Se hace
esta distinción porque un elemento pivote cero llega a interferir con la normalización
al causar una división entre cero. Más adelante se regresará a este punto
importante, una vez que se complete la descripción de la eliminación de Gauss
simple.
Ahora se repite el procedimiento antes descrito para eliminar la segunda incógnita
en las ecuaciones (Ec. 1.3c) hasta (Ec. 1.3d). Para realizar esto, multiplique la
ecuación (Ec. 1.3b) por y reste el resultado de la ecuación (Ec. 1.3c). Se
realiza la eliminación en forma similar en las ecuaciones restantes para obtener.
a11x1+a12x2+a13x3+….+a1nxn=b1
a´22x2+a´23x3+….+a´2nxn=b´2
a´´33x3+….+a´´3nxn=b´´3
. .
. .
a´´n2x2+a´´n3x3+….+a´nnxn=b´n

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)

1.2.1.- Ejemplo propuesto


Para resolver el siguiente conjunto de ecuaciones. Emplee la eliminación de Gauss
(Ec.1.5)
(Ec.1.6)
(Ec.1.7)
Las operaciones se efectuarán usando seis cifras significativas.
La primera parte del procedimiento es la eliminación hacia adelante. Se multiplica la
ecuación (Ec. 1.5) por (0.1)/3 y se resta el resultado de la ecuación (Ec. 1.6) para
obtener

Después, se multiplica la ecuación (Ec. 1.5) por (0.3)/3 y se resta de la ecuación


(Ec.1.7) para eliminar . Luego de efectuar estas operaciones, el sistema de
ecuaciones es
(Ec.1.8)

(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)

Este resultado se sustituye en la ecuación (Ec.1.12):

7.003332 - 0.293333 (7.00003) = -19.5617


de la que se despeja

(Ec.1.15)

Por último, las ecuaciones (Ec.1.14) y (Ec.1.15) se sustituyen en la (Ec.1.8):

3 - 0.1 (-2.50000) - 0.2 (7.00003) = 7.85

de la que se despeja,

aunque hay un pequeño error de redondeo en la ecuación (Ec.1.14), los resultados


son muy cercanos a la solución exacta, . Esto se verifica al
sustituir los resultados en el sistema de ecuaciones original

10
1.2.2.- Diagrama de flujo

Diagrama de Flujo Gauss Simple eliminación hacia adelante

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

Pseudocódigo que realiza a) la eliminación hacia adelante y b) la sustitución hacia


atrás.

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:

Suponga que se limita a un conjunto de ecuaciones de 3 x 3. Si los elementos de la


diagonal no son todos cero, la primera ecuación se puede resolver para la
segunda para y la tercera para , para obtener
(Ec.1.16a)

(Ec.1.16b)

(Ec.1.16c)

Ahora, se puede empezar el proceso de solución al escoger valores iniciales para


las . Una forma simple para obtener los valores iniciales es suponer que todos son
cero. Estos ceros se sustituyen en la ecuación (Ec.1.16a), la cual se utiliza para
calcular un nuevo valor Después, se sustituye este nuevo valor de

junto con el valor previo cero de en la ecuación (Ec.1.16b) y se calcula el


nuevo valor de . Este proceso se repite con la ecuación (Ec.1.16c) para calcular
un nuevo valor de . Después se regresa a la primera ecuación y se repite todo el
procedimiento hasta que la solución converja suficientemente cerca de los valores
verdaderos. La convergencia se verifica usando el criterio de la siguiente ecuación
de error relativo porcentual.
16
(Ec.1.17)

Para toda las donde y son las iteraciones actuales y previas


respectivamente.

1.3.1.- Ejemplo propuesto


Planteamiento del problema. Use el método de Gauss-Seidel para obtener la
solución del sistema usado en el ejemplo:

Recuerde que la verdadera solución es .


Solución. Primero, despeje la incógnita sobre la diagonal para cada una de las
ecuaciones.

(Ec.1.18a)

(Ec.1.18b)

(Ec.1.18c)

Suponiendo que son cero, se utiliza la ecuación (Ec.1.18a) para calcular

Este valor, junto con el valor de = 0, se sustituye en la ecuación (Ec.1.18b) para


calcular

17
la primera iteración termina al sustituir los valores calculados para en la
ecuación (Ec.1.18c) para dar

en la segunda iteración, se repite el mismo proceso para calcular

El método es, por lo tanto, convergente hacia la verdadera solución. Es posible


aplicar iteraciones adicionales para mejorar los resultados. Sin embargo, es un
problema real no se podría saber con anticipación el resultado correcto. En
consecuencia, la ecuación (Ec.1.17) nos da un medio para estimar el error relativo
porcentual. Por ejemplo, para ,

Para los errores estimados son . Observe


que, como cuando se determinaron las raíces de una sola ecuación, las
formulaciones como la ecuación (Ec.1.17) de Error relativo porcentual, usualmente
ofrecen una valoración conservativa de la convergencia. Así, cuando estas se
satisfacen aseguran que el resultado se conozca con al menos, la tolerancia
especificada por .

18
1.3.2.- Diagrama de flujo

Diagrama de Flujo Gauss Seidel

19
1.3.3.- Pseudocódigo

SUBROUTINE Gseid (a, b, n, x, imax, es, lambda)


DO i = 1,n
dummy = ai.i
DO j = 1,n
ai,j = ai,j / dummy
END DO
bi = ai / dummy
END DO
DO i = 1, n
sum = bi
DO j = 1, n
IF i j THEN sum =sum – ai, j *xj
END DO
xi = sum
END DO
iter =1
DO
centinela = 1
DO i = 1, n
old = xi
sum = bi
DO j = 1, n
IF i j THEN sum =sum – ai, j *xj
END DO
xi = lambda * sum +( 1 - lambda) * old
IF centinela = 1 AND x1 0 . THEN
ea=ABS (( xi –old) / xi )*100.
IF ea es THEN centinela = 0
END IF
END DO
iter = iter + 1
IF centinela = 1 OR (iter I max) EXIT
END DO
END Gseid

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

El método de Gauss-Jordan es una variación de la eliminación de Gauss. La


principal diferencia consiste en que cuando una incógnita se elimina en el método
de Gauss-Jordan. Ésta es eliminada de todas las otras ecuaciones, no sólo de las
subsecuentes. Además, todos los renglones se normalizan al dividirlos entre su
elemento pivote. De esta forma, el paso de eliminación genera una matriz identidad
en vez de una triangular (figura 1.2). En consecuencia, no es necesario usar la
sustitución hacia atrás para obtener la solución. El método se ilustra mejor con un
ejemplo.

Figura 1.2
Representación gráfica del método de Gauss-Jordan.

1.4.1.- Ejemplo propuesto


Método de Gauss-Jordan
Para resolver el siguiente conjunto de ecuaciones. Con la técnica de Gauss-Jordan

Solución. Primero, exprese los coeficientes y el lado derecho como una matriz au-
mentada

3 -0.1 -0.2 7.85


0.1 7 -0.3 -19.3
0 -0.2 10 71.4

25
Luego normalice el primer renglón, dividiéndolo entre el elemento pivote, 3, para
obtener

1 -0.0333333 -0.066667 2.61667


0.1 7 -0.3 -19.3
0.3 -0.2 10 71.4

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.0333333 -0.066667 2.61667


0 7.00333 -0.293333 -19.5617
0 -0.190000 10.0200 70.6150

En seguida, se normaliza el segundo renglón dividiéndolo entre 7.00333:

1 -0.0333333 -0.066667 2.61667


0 1 -0.0418848 - 2.79320
0 -0.190000 10.0200 70.6150

Al reducir los términos x2 de las ecuaciones primera y tercera se obtiene

1 0 -0.0680629 2.52356
0 1 -0.0418848 -2.79320
0 0 10.01200 70.0843

El tercer renglón se normaliza después al dividirlo entre 10.0120:

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

De esta forma, como se muestra en la figura 1.2 la matriz de coeficientes se ha


transformado en la matriz identidad, y la solución se obtiene en el vector del lado
derecho. Observe que no se requiere la sustitución hacia atrás para llegar a la
solución.

27
1.4.2.- Diagrama de Flujo

N,M,I,A,J

Diagrama de Flujo Gauss Jordan

28
SUBROUTINE
GAUSS (N,M,A)

I,PIVOTE,A,J,K,N,
M,CERO

Diagrama de Flujo principal Gauss Jordan subrutina

29
1.4.3.- Pseudocódigo

SUB Gauss (a, b, n, x, tol, er)


DIMENSION s (n)
er = 0
DO i =l, n
si = ABS (ai,1 )
DO j = 2, n
IF ABS (Ai,j) si THEN si = abs (a i , j)
END DO
END DO
SUB Eliminate (a, s, n, b, tol, er)
IF er -1 THEN
CALL Substitute (a , n , b, x)
END IF
END Gauss

CALL Eliminate (a, s, n, b, tol, er)


DO k = 1, n – 1
CALL Pivot (a, b, s, n, k)
IF ABS (ak, k/ sk) tol THEN
er = -1
EXIT DO
END IF
DO i = k +1, n
factor = a i, k/ a k, k
DO j= k + 1, n
ai,j = a i, j - factor*ak,j
END DO
bi = bi – factor * bk
END DO
END DO
IF ABS (ak,k / sk) tol THEN er = -1
END Eliminate

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

donde la b y la a son constantes. A las ecuaciones algebraicas y trascendentales que


no se pueden expresar de esta forma se les llama ecuaciones no lineales. Por ejemplo,

son dos ecuaciones simultáneas no lineales con dos incógnitas, y , las cuales se
expresan en la forma de la ecuación como

Así, la solución serían los valores de y de y que hacen a las funciones y


iguales a cero. La mayoría de los métodos para determinar tales soluciones son
extensiones de los métodos abiertos para resolver ecuaciones simples.

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)

entonces hay al menos una raíz real entre y .

Los métodos de búsqueda incremental aprovechan esta característica localizando


un intervalo en el que la función cambie de signo. Entonces, la localización del
cambio de signo (y, en consecuencia, de la raíz) se logra con más exactitud al dividir
el intervalo en varios subintervalos. Se investiga cada uno de estos subintervalos
para encontrar el cambio de signo. El proceso se repite y la aproximación a la raíz
mejora cada vez más en la medida que los subintervalos se dividen en intervalos
cada vez más pequeños.

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.

2.2.1.- Ejemplo propuesto


Planteamiento del problema. Emplee el método de bisección para resolver el
siguiente problema.

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

Dicha aproximación representa un error relativo porcentual verdadero de


(note que el valor verdadero de la raíz es 14.7802). A continuación calculamos el
producto de los valores en la función en un límite inferior y en el punto medio:

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.

Entonces, se crea un nuevo intervalo redefiniendo el límite inferior como 14 y


determinando una nueva aproximación corregida de la raíz

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

la cual representa un error porcentual verdadero , = 1.5%. Este proceso se repite


para obtener una mejor aproximación. Por ejemplo,

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í:

que representa un error relativo porcentual , = 1 .9%. Este método se repite


hasta que el resultado sea suficientemente exacto para satisfacer sus necesidades.
En el ejemplo anterior, se observa que el error verdadero no disminuye con cada
iteración. Sin embargo, el intervalo donde se localiza la raíz se divide a la mitad en
cada paso del proceso. Como se estudiará en la siguiente sección, el ancho del
intervalo proporciona una estimación exacta del límite superior del error en el
método de bisección.

38
2.2.2.- Diagrama de Flujo

Diagrama de Flujo Bisección

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

Aun cuando la bisección es una técnica perfectamente válida para determinar


raíces, su método de aproximación por "fuerza bruta" es relativamente ineficiente.
La falsa posición es una alternativa basada en una visualización gráfica.

Un inconveniente del método de bisección es que al dividir el intervalo de , a


en mitades iguales, no se toman en consideración las magnitudes de y
de . Por ejemplo, si de está mucho más cercana a cero que de , es
lógico que la raíz se encuentre más cerca de que de (figura 2.4). Un método
alternativo que aprovecha esta visualización gráfica consiste en unir y
con una línea recta. La intersección de esta línea con el eje de las x representa una
mejor aproximación de la raíz. El hecho de que se reemplace la curva por una línea
recta da una "falsa posición" de la raíz; de aquí el nombre de método de la falsa
posición, o en latín, regula falsi. También se le conoce como método de
interpolación lineal.
Usando triángulos semejantes (fig.2.4) la intersección de la línea recta con el eje de
las se estima mediante
(Ec. 2.2)

en el cual se despeja
(Ec. 2.3)

Ésta es la fórmula de la falsa posición. El valor de calculado con la ecuación


(Ec. 2.3), reemplazará, después, a cualquiera de los dos valores iniciales, o , y
da un valor de la función con el mismo signo de . De esta manera, los valores
o siempre encierran la verdadera raíz. El proceso se repite hasta que la
aproximación a la raíz sea adecuada. El algoritmo es idéntico al de la bisección
(figura 2.1), excepto en que la ecuación (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.

Desarrollo del método de la falsa posición


Multiplicando en cruz la ecuación (2.2) obtenemos

Agrupando términos y reordenando:

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:

Sumando y restando en el lado derecho:

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

2.3.1.- Ejemplo propuesto


Con el método de la falsa posición determine la raíz de la misma ecuación
analizada en el ejemplo 2.3 [ecuación (Ec. 2.3a)].
Solución. Se empieza el cálculo con los valores iniciales =12 y = 16.
Primera iteración:
= 12 = 6.0699
=16 = -2.2688

que tiene un error relativo verdadero de 0.89 por ciento.


Segunda iteración:
o = -1.5426
Por lo tanto, la raíz se encuentra en el primer subintervalo y xr se vuelve ahora el
límite superior para la siguiente iteración, = 14.9113:

= 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

Diagrama de Flujo Falsa Posición

47
2.3.3.- Pseudocódigo

FUNCTION ModFalsepos (xl, xu, es, imax, xr, iter, ea)


iter = 0
fl = f(xl)
fu = f (xu)
DO
xrold = xr
xr = xu – fu * (xl – xu) / (fl – fu)
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
fu = f(xu)
iu= 0
il = il + 1
IF il 2 THEN fl = fl / 2
ELSE IF test O THEN
xl=xr
fl = f (xl)
il=0
iu = iu + 1
IF iu 2 THEN fu =fu / 2
ELSE
ea = 0
END IF
IF ea es OR iter imax THEN EXIT
END DO
modFalsepos = xr
END Modfalsepos

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

printf("\n METODO DE FALSA POSICION\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);
c1 = FalsePos( xmin, xmax, error, iteraciones);
printf( " Resultado = %f", c1);
getch();
}
}

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.

El método de Newton-Raphson se deduce a partir de esta interpretación


geométrica. De la figura 2.4, se tiene que la primera derivada en es equivalente a
la pendiente:

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)

que se reordena para obtener


f
(Ec.2.5)

La cual se conoce como fórmula de Newton-Raphson.

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 <

Así, el método converge rápidamente a la raíz verdadera. Observe que el error


relativo porcentual verdadero en cada iteración disminuye mucho más rápido que
con la iteración simple de punto fijo.

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

Diagrama de Flujo Newton Raphson

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.

Muchas de las leyes generales de la naturaleza se expresan en el lenguaje de las


ecuaciones diferenciales; abundan también las aplicaciones en ingeniería, economía,
en las mismas matemáticas y en muchos otros campos de la ciencia aplicada.

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

Recuerde que el método fue de la forma general


Nuevo valor = valor anterior + pendiente x tamaño de paso
o, en términos matemáticos,
(Ec.3.2)

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):

donde es la ecuación diferencial evaluada en y . La estimación se


sustituye la ecuación (Ec.3.1):
f (Ec.3.2)
Esta fórmula se conoce como método de Euler (o de Euler-Cauchy o de punto
pendiente). Se predice un nuevo valor de y, usando la pendiente (igual a la primera
deriva en el valor original de x) para extrapolar linealmente sobre el tamaño de paso h
(figura 3.2).

Figura 3.2
Método de Euler.

3.2.1.- Ejemplo propuesto


Planteamiento del problema. Con el método de Euler integre numéricamente la
ecuación

desde hasta con un tamaño de paso 0.5. La condición inicial en


es . Recuerde que la solución exacta está dada por la siguiente ecuación:

60
Solución. Se utiliza la ecuación (Ec.3.2) para implementar el método de

Euler:

donde y la pendiente estimada en es

Por lo tanto,

La solución verdadera en es

Así, el error es

Et = valor verdadero - valor aproximado


o , expresada como error relativo porcentual, t = -63.1%. En el segundo paso,

La solución verdadera en x = 1.0 es 3.0 y, entonces, el error relativo porcentual es -


95.8%. El cálculo se repite y los resultados se dan en la tabla 3.2.1 y en la figura 3.3.

Comparación de los valores verdadero y aproximado de la integral de y'= -2X3+ 1


2.x2 - 20x + 8.5, con la condición inicial de que y = 1 en x = 0. Los valores
aproximados se calcularon empleando el método de Euler con un tamaño de paso de
0.5. El error local se refiere al error en que se incurre sobre un solo paso. Éste se
calcula con una expansión de la serie de Taylor como en el ejemplo 3.3. El error
global es la discrepancia total debida a los pasos anteriores y presentes.

61
Tabla 3.2.1

Error relativo
porcentual

X Y verdadero Y euler Global Local


0.0 1 .00000 1 .00000

0.5 3.21875 5.25000 -63.1 -63.1


1.0 3.00000 5.87500 -95.8 -28.0
1.5 2.21875 5.12500 131.0 -1.41
2.0 2.00000 4.50000 -125.0 20.5
2.5 2.71875 4.75000 -74.7 17.3
3.0 4.00000 5.87500 46.9 4.0
3.5 4.71875 7.12500 -51.0 -11.3
4.0 3.00000 7.00000 -133.3 -53.0

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

Diagrama de Flujo Euler

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)

donde se conoce como la función incremento, la cual puede interpretarse


como una pendiente representativa en el intervalo. La función incremento se escribe
en forma general como

(Ec.3.4)

donde las son constantes y las son

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

Es posible tener varios tipos de métodos de Runge-Kutta empleando diferentes nú-


meros de términos en la función incremento especificada por n. Observe que el
método de Runge-Kutta (RK) de primer orden con n=1 es, de hecho, el método de
Euler. Una vez que se elige n, se evalúan las a, p y q igualando la ecuación (Ec.3.3) a
los términos en la expansión de la serie de Taylor. Así, al menos para las versiones
de orden inferior, el número de términos, n, por lo común representa el orden de la
aproximación. Por ejemplo, en la siguiente sección, los métodos RK de segundo
orden usan la función incremento con dos términos (n – 2).

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)

Como se describe a continuación, los valores de se evalúan al igualar


la ecuación (Ec.3.5) con la expansión de la serie de Taylor hasta el término de
segundo.

3.3.1.- Ejemplo propuesto


Comparación de varios esquemas RK de segundo orden
Planteamiento del problema. Utilice el método de Runge Kutta para integrar
numéricamente la siguiente ecuación:

Con la condición inicial de que y = 1 en x = 0. Los valores aproximados se calcularon


con el método RK de segundo orden, con un tamaño de paso de 0.5.

RUNGE KUTTA DE SEGUNDO ORDEN

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

La pendiente promedio se calcula mediante

que se utiliza para predecir

Resolver la siguiente función con la condición inicial en


. Los valores aproximados se calcularon utilizando el método de runge kutta con un
tamaño de paso igual a 1.

0 2.0000000 2.0000000 0.00 2.0000000 0.00

1 6.1946314 6.7010819 8.18 6.3608655 2.68


2 14.8439219 16.3197819 9.94 15.3022367 3.09
3 33.6771718 37.1992489 10.46 34.7432761 3.17
4 75.3389626 83.3377674 10.62 77.7350962 3.18

70
3.3.2.-Diagrama de flujo

Diagrama de Flujo Runge Kutta

71
3.3.3.- Pseudocódigo

a) Programa pr nc pa o “man ja or”


Asigna valores para
n= número de ecuaciones
yi= valores iniciales de n variables dependientes
xi= valor inicial de la variable independiente
xf= valor final de la variable independiente
dx= cálculo del tamaño de paso
xout= intervalo de salida

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

Además, dicha técnica se puede aproximar a la obtención de integrales dobles y


triples.
Siendo la derivada la medida de cambio puntual o instantáneo y la integral la suma
o acumulación de tales cambios, resulta fundamental en cualquier actividad de in-
geniería o ciencias, conocer ambas técnicas, y no menos importante, darle sentido
físico a los resultados.

4.2.- Simpson 1/3


Una forma de obtener una estimación más exacta de una integral consiste en usar
polinomios de grado superior para unir los puntos. Por ejemplo, si hay otro punto a
la mitad entre y los tres puntos se pueden unir con una parábola (figura
4.1a). Si hay dos puntos igualmente espaciados entre f(a) y f b , los cuatro puntos
se pueden unir mediante un polinomio de tercer grado (figura 4.1b). Las fórmulas
que resultan de tomar las integrales bajo esos polinomios se conocen como reglas
de Simpson.
La regla de Simpson 1/3 resulta cuando un polinomio de interpolación de segundo
grado se sustituye en la siguiente ecuación:

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.

4.2.1.- Ejemplo propuesto


Si se designan a y b como x0 y x2 respectivamente y f2(x) se representa por un
polinomio de Lagrange de segundo grado, la integral se transforma en

f f

Después de la integración y de las manipulaciones algebraicas, se obtiene la


siguiente fórmula:

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.

La regla de Simpson 1/3 también se puede expresar usando el formato de la


siguiente ecuación:

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.

Se puede demostrar que la aplicación a un solo segmento de la regla de Simpson


1/3 tiene un error de truncamiento.

t f
o como

b a
t f (Ec.4.3)

donde está en algún lugar en el intervalo de y Así, la regla de Simpson 1/3


es más exacta que la regla del trapecio. No obstante, una comparación con la
ecuación (21.6) indica que es más exacta de lo esperado. En lugar de ser
proporcional a la tercera derivada, el error es proporcional a la cuarta derivada. Esto
es porque, como se muestra en el cuadro 21.3, el término del coeficiente de tercer
grado se hace cero durante la integración de la interpolación polinomial. En
consecuencia, la regla de Simpson 1/3 alcanza una precisión de tercer orden aun
cuando se base en sólo tres puntos.

78
Aplicación simple de la regla de Simpson 1/3
Planteamiento del problema. Con la ecuación (Ec.4.2) integre

desde hasta . Recuerde que la integral exacta es 1.640533


Solución.

Por lo tanto, la ecuación (Ec.4.2.2) se utiliza para calcular

Que representa un error exacto de

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)]

donde -2400 es el promedio de la cuarta derivada en el intervalo, , debido a que el


promedio de la cuarta derivada no es una estimación exacta de . Sin
embargo, como este caso tiene que ver con un polinomio de quinto grado, el
resultado concuerda.

79
4.2.2.- Diagrama de flujo

INICIO

n_s, n_p, h, b,
a, x_j, j, k, i

Diagrama de Flujo Simpson 1/3


80
4.2.3. - Pseudocódigo
a)
FUNCTION Simp13 (h, f0, fl, f2)
simp13 = 2* h * (f0+4*f1+f2) /6
END Simp13
b)
FUNCTION Simp38 (h, f0, fl, f2)
simp38 = 3*h* (f0+3*(f1+f2)+f3) /8
END Simp38
c)
FUNCION Simp13m (h, n, f)
sum = f(0)
DO i = 1, n- 2, 2
sum = sum + 4 * fi + 2 * fi+1
END DO
sum = sum + 4 * fn-1 + 2 * fn
simp13m = h * sum / 3
END Simp13m
d)
FUNCTION SimpInt (a, b, n, f)
h = (b – a) / n
IF n = 1 THEN
sum = trap (h, fn-1,fn)
ELSE
m=n
odd = n / 2 – INT(n / 2)
IF odd > 0 AND > 1 THEN
sum = sum + simp38(h, fn-3, fn-2, fn-1, fn)
m=n–3
END IF
IF m > 1 THEN
sum = sum + simp13m(h,m,f)
END IF
END IF
SimpInt =sum
END SimpInt
81
4.2.4.- Programas en C
#include <stdio.h> /*para printf(),scanf()*/
#include <conio.h> /*para getch(),clrscr()*/
#include <stdlib.h>/*para exit()*/
#include <dos.h>
#include <math.h>
#define NUMEL 20
#define INTERVALOS 0
float f(float);
void _error(int n);
MAIN
}
h=(b-a)/(2*n);
S0=S1=0;
for(i=1;i<=(2*n-1);++i){
x=a+((double)i)*h;
if(!(i%2))
S0+=f(x);
else
S1+=f(x);
}
*Area=(h*(f(a)+4*S1+2*S0+f(b))/3.0);

printf("\n El area es -> %5.6f",*Area);


getch();
}
void LeeDatos(int opc)
{
if(opc==SIMPSON1_3){
clrscr();
printf("\n Metodo de Integracion por 1/3 de Simpson");
printf("\n ========================================");
putchar('\n');
printf("\n Numero de intervalos (PAR) -> "); }

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

Para la elaboración de este manual de programas aplicados a métodos numéricos


se recopiló información de diferentes fuentes: libros e internet pero como
herramienta principal, el programa borland c++ versión 5.0 y el costo de operación
de este software fue gratuito ya que la facultad cuenta con esta herramienta y está
instalado en el centro de cómputo en nuestra facultad de ingeniería mecánica
eléctrica.

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 PARA INGENIEROS CON PROGRAMAS DE


APLICACIÓN
STEVEN C. CHAPRA
RAYMOND P. CANALE

MÉTODOS NUMÉRICOS
LUTHE OLVERA SCHUTZ

MÉTODOS NUMÉRICOS APLICADOS A LA INGENIERÍA


ANTONIO NIEVES

87
ANEXOS
Anexo A

DIAGRAMAS DE FLUJO

TERMINAL:

Indica el inicio y el fin de un Diagrama de Flujo.

DEFINICIÓN DE VARIABLES:

Define todas y cada una de las variables que serán


utilizadas en el programa representado en el diagrama
de flujo.

PROCESO:

Cualquier tipo de operación que pueda originar cambio


de valor, formato o posición de la información
almacenada en memoria, operaciones aritméticas, de
transferencia, etc.

DECISIÓN:

Indica operaciones lógicas o de comparación de datos,


normalmente dos, y en función del resultado de la misma
determina cual de los distintos caminos alternativos del
programa se debe seguir; normalmente tiene dos salidas
respuestas: sí o no, pero puede tener más según los
casos.

ENTRADA:

Indica la asignación de un valor de una variable tomando


este valor desde un dispositivo de entrada.

SALIDA:

Indica que el resultado será presentado ya sea por


pantalla o por impresora.

88
Anexo B

CICLOS

Ciclos: Son procesos repetitivos los cuales se ejecutan una o más instrucciones
varias veces.

Valor Inicial: Se encuentra asignado a una variable la cual es la que controla el


ciclo y debe ser de tipo entero, además tiene el valor de inicio del ciclo.

Valor Final: Con este valor indicamos la última vez que el ciclo debe ejecutarse.

Incremento: Representa la frecuencia en que debe aumentarse la variable.

Entrada: Marca el principio o reinicio de las instrucciones que se encuentran


dentro del ciclo.

Regreso: Indica donde termina el ciclo, en qué momento el proceso se repite.

Salida: Indica la finalización de la ejecución de un ciclo.

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

El proceso de desarrollo del lenguaje C se origina con la creación de un lenguaje


llamado BCPL, que fue desarrollado por Martin Richards. El BCPL tuvo influencia
en un lenguaje llamado B, el cual se usó en 1970 y fue inventado por Ken
Thompson y que permitió el desarrollo de C en 1971, el cual lo inventó e
implementó Dennis Ritchie. Para 1973 el sistema operativo UNIX estaba casi
totalmente escrito en C.
Durante muchos años el estándar para C fue la versión 5 del sistema operativo
UNIX, documentada en ``The C Programming Language'' escrito por Brian W.
Kernighan and Dennis M. Ritchie in 1978 comúnmente referido como K&R.
Posteriormente se hicieron varias implementaciones las cuales mostraban las
siguientes tendencias:
Nuevas características
Diferencias de máquinas
Diferencias de productos
Errores en los compiladores
Malas implementaciones
Esto originó que en el verano de 1983 se estableciera un comité para resolver
estas discrepancias, el cual empezó a trabajar en un estándar ANSI C, la cual fue
completada en 1988.

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()
{

printf( "Me gusta C\n" );


exit (0);

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

C tiene los siguientes tipos de datos simples:


Tabla: Tipos de C
Tipo Tamaño (bytes) Límite inferior Límite superior
Char 1 -- --
unsigned char 1
short int 2

unsigned short int 2


(long) int 4

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()
{
...
}

Es también posible pre inicializar variables globales usando el operador de


asignación =, por ejemplo:
float suma= 0.0;
int sumagr= 0;
char letra= 'A';

main()
{
...
}

Que es lo mismo que:


float suma;
int sumagr;
char letra;

main()
{
suma = 0.0;
sumagr= 0;
letra = 'A';

...
}

Dentro de C también se permite la asignación múltiple usando el operador =, por


ejemplo:
a = b = c = d = 3;

...que es lo mismo, pero más eficiente que:


a = 3;
b = 3;
c = 3;
93
d = 3;

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;

/* Declaración de variables usando el nuevo tipo */


real suma=0.0;
letra sig_letra;

LECTURA Y ESCRITURA DE VARIABLES

El lenguaje C usa salida formateada. La función printf tiene un carácter especial


para formatear (%) -- un carácter enseguida define un cierto tipo de formato para
una variable.
%c caracteres
%s cadena de caracteres
%d enteros
%f flotantes
Por ejemplo:
printf("%c %d %f",ch,i,x);

La sentencia de formato se encierra entre " ", y enseguida las variables.


Asegurarse que el orden de formateo y los tipos de datos de las variables
coincidan.
scanf() es la función para entrar valores a variables. Su formato es similar a printf.
Por ejemplo:
scanf("%c %d %f %s",&ch, &i, &x, cad);

Observar que se antepone & a los nombres de las variables, excepto a la cadena
de caracteres.

CONSTANTES

ANSI C permite declarar constantes. Cuando se declara una constante es un poco


parecido a declarar una variable, excepto que el valor no puede ser cambiado.
La palabra clave const se usa para declarar una constante, como se muestra a
continuación:
const a = 1;
int a = 2;

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.

La directiva del preprocesador #define es un método más flexible para definir


constantes en un programa.
Frecuentemente se ve la declaración const en los parámetros de la función. Lo
anterior simplemente indica que la función no cambiara el valor del parámetro. Por
ejemplo, la siguiente función usa este concepto:
char *strcpy(char *dest, const char *orig);
El segundo argumento orig es una cadena de C que no será alterada, cuando se
use la función de la biblioteca para copiar cadenas.

OPERADORES ARITMÉTICOS

Lo mismo que en otros lenguajes de programación, en C se tienen los operadores


aritméticos más usuales (+ suma, - resta, * multiplicación, / división y % módulo).
El operador de asignación es =, por ejemplo: i=4; ch='y';
Incremento ++ y decremento -- unario. Los cuales son más eficientes que las
respectivas asignaciones. Por ejemplo: x++ es más rápido que x=x+1.
Los operadores ++ y -- pueden ser prefijos o postfijos. Cuando son prefijos, el valor
es calculado antes de que la expresión sea evaluada, y cuando es postfijo el valor
es calculado después que la expresión es evaluada.
En el siguiente ejemplo, ++z es prefijo y -- es postfijo:
int x,y,z;

main()
{
x=( ( ++z ) - ( y-- ) ) % 100;
}

Que es equivalente a:
int x,y,z;

main()
{
z++;
x = ( z-y ) % 100;
y--;
}

El operador % (módulo o residuo) solamente trabaja con enteros, aunque existe


una función para flotantes.
El operador división / es para división entera y flotantes. Por lo tanto hay que tener
cuidado. El resultado de x = 3 / 2; es uno, aún si x es declarado como float. La
regla es: si ambos argumentos en una división son enteros, entonces el resultado
es entero. Si se desea obtener la división con la fracción, entonces escribirlo como:
x = 3.0 / 2; o x = 3 / 2.0 y aún mejor x = 3.0 / 2.0.
Por otra parte, existe una forma más corta para expresar cálculos en C. Por
ejemplo, si se tienen expresiones como: i = i + 3; o x = x * (y + 2); , pueden ser
95
reescritas como:

Lo cual es equivalente, pero menos eficiente que:

Por lo que podemos reescribir las expresiones anteriores como: i += 3; y x *= y + 2;


respectivamente.

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

Los operadores lógicos son usualmente usados con sentencias condicionales o


relacionales, los operadores básicos lógicos son:
&& Y lógico, || O lógico y! negación.

ORDEN DE PRECEDENCIA

Es necesario ser cuidadosos con el significado de expresiones tales como a + b *


c, dependiendo de lo que se desee hacer
(a + b) * c
o
a + (b * c)
Todos los operadores tienen una prioridad, los operadores de mayor prioridad son
evaluados antes que los que tienen menor prioridad. Los operadores que tienen la
misma prioridad son evaluados de izquierda a derecha, por lo que:
a-b-c
es evaluado como
(a - b) - c
Prioridad Operador(es)
Más alta ( ) [ ] ->
! ~ ++ -- - (tipo) * & sizeof
*/%
+-
96
<< >>
< <= > >=
== !=
&
^
|
&&
||
?
= += -= *= /=
Más baja ,

De acuerdo a lo anterior, la siguiente expresión:


a < 10 && 2 * b < c
Es interpretada como:
(a < 10) && ( (2 * b) < c )
y
a=
b=
10 / 5
+ 2;

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

Las tres formas como se puede emplear la sentencia if son:

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 operador ternario condicional “?” es más eficiente que la sentencia if. El


operador ? tiene el siguiente formato:
expresión1 ? expresión 2 : expresion3;
Que es equivalente a la siguiente expresión:
if (expresión1) then expresión2 else expresión3;
Por ejemplo, para asignar el máximo de a y b a la variable z, usando ?,
tendríamos:
z = (a>b) ? a : b;
que es lo mismo que:
if (a > b)
z = a;
else
z = b;

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);

/* imprime mensaje apropiado */


t ? f1(t) + f2() : printf("Se dio un cero\n");

99
LA SENTENCIA SWITCH

Aunque con la estructura if ... else if se pueden realizar comprobaciones múltiples,


en ocasiones no es muy elegante, ya que el código puede ser difícil de seguir y
puede confundir incluso al autor transcurrido un tiempo. Por lo anterior, C tiene
incorporada una sentencia de bifurcación múltiple llamada switch. Con esta
sentencia, la computadora comprueba una variable sucesivamente frente a una
lista de constantes enteras o de carácter. Después de encontrar una coincidencia,
la computadora ejecuta la sentencia o bloque de sentencias que se asocian con la
constante. La forma general de la sentencia switch es:

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

En este capítulo se revisan los mecanismos de C para repetir un conjunto de


instrucciones hasta que se cumple cierta condición.

LA SENTENCIA FOR

La sentencia for tiene el siguiente formato:

for ( expresión1; expresión2; expresión3)


sentencia;
o { bloque de sentencias }
En donde expresión1 se usa para realizar la inicialización de variables, usando una
o varias sentencias, si se usan varias sentencias deberá usarse el operador, para
separarlas. Por lo general, establece el valor de la variable de control del ciclo.
expresión2 se usa para la condición de terminación del ciclo y expresión3 es el
modificador a la variable de control del ciclo cada vez que la computadora lo repite,
pero también puede ser más que un incremento.
Por ejemplo:
int X;

main()
{
for( X=3; X>0; X--)
{
printf("X=%d\n",X);
}
}

genera la siguiente salida a pantalla ...


X=3
X=2
X=1

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++ )

for ( x=0, y=4; ( (x>3) && (x<9) ); x++, y+=2)

for ( x=0, y=4, z=4000; z; z/=10)

En el segundo ejemplo se muestra la forma como múltiples expresiones pueden


aparecer, siempre y cuando estén separadas por una coma ,
En el tercer ejemplo, el ciclo continuará iterando hasta que z se convierta en .

LA SENTENCIA WHILE

La sentencia while es otro ciclo o bucle disponible en C. Su formato es:

while ( expresión) sentencia;

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();
}

Antes de entrar al ciclo se inicializa la variable carac a nulo. Después pasa a la


sentencia while donde se comprueba si carac no es igual a 'A', como sea verdad
entonces se ejecuta la sentencia del bucle (carac = getchar();). La función getchar()
lee el siguiente carácter del flujo estándar (teclado) y lo devuelve, que en nuestro
ejemplo es el caracter que haya sido tecleado. Una vez que se ha pulsado una
tecla, se asigna a carac y se comprueba la condición nuevamente. Después de
pulsar A, la condición llega a ser falsa porque carac es igual a A, con lo que el ciclo
termina.
De lo anterior, se tiene que tanto el ciclo for, como el ciclo while comprueban la
condición en lo alto del ciclo, por lo que el código dentro del ciclo no se ejecuta
siempre.

102
A continuación mostramos otro ejemplo:
main()
{
int x=3;

while( x>0 )
{
printf("x = %d\n", x);
x--;
}
}

que genera la siguiente salida en pantalla:


x=3
x=2
x=1

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 );

Si se usan este tipo de expresiones, solamente cuando el resultado de x--, x=x+1 o


x+=5 sea cero, la condición fallará y se podrá salir del ciclo.
De acuerdo a lo anterior, podemos realizar una operación completa dentro de la
expresión. Por ejemplo:
main()
{
char carac;

carac = '\0';
while ( (carac = getchar()) != 'A' )
putchar(carac);
}

En este ejemplo se usan las funciones de la biblioteca estándar getchar() -- lee un


carácter del teclado y putchar() escribe un carácter dado en pantalla. El ciclo while
procederá a leer del teclado y lo mostrará hasta que el carácter A sea leído.

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 ) ;
}

USO DE BREAK Y CONTINUE

Como se comento uno de los usos de la sentencia break es terminar un case en la


sentencia switch. Otro uso es forzar la terminación inmediate de un ciclo, saltando
la prueba condicional del ciclo.
Cuando se encuentra la sentencia break en un bucle, la computadora termina
inmediatamente el ciclo y el control del programa pasa a la siguiente sentencia del
ciclo. Por ejemplo:
main()
{
int t;
for(t=0; t<100; t++)
{
printf("%d ", t);
if (t==10) break;
}
}

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;

for( x=0; x<100; x++)


{
if (x%2)
continue;
printf("%d ",x);
105
}
}

Finalmente se considera el siguiente ejemplo donde se leen valores enteros y se


procesan de acuerdo a las siguientes condiciones. Si el valor que sea leído es
negativo, se desea imprimir un mensaje de error y se abandona el ciclo. Si el valor
es mayor que 100, se ignora y se continúa leyendo, y si el valor es cero, se desea
terminar el ciclo.
main()
{
int valor;

while( scanf("%d", &valor) == 1 && valor != 0)


{
if ( valor<0 )
{
printf("Valor no valido\n");
break;
/* Salir del ciclo */
}

if ( valor>100)
{
printf("Valor no valido\n");
continue;
/* Pasar al principio del ciclo nuevamente */
}

printf("Se garantiza que el valor leido esta entre 1 y 100");


}
}

ARREGLOS UNIDIMENSIONALES Y MULTIDIMENSIONALES

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 */

El lenguaje C no realiza comprobación de contornos en los arreglos. En el caso de


que sobrepase el final durante una operación de asignación, entonces se
asignarán valores a otra variable o a un trozo del código, esto es, si se dimensiona
un arreglo de tamaño N, se puede referenciar el arreglo por encima de N sin
provocar ningún mensaje de error en tiempo de compilación o ejecución, incluso
aunque probablemente se provoque el fallo del programa. Como programador se
es responsable de asegurar que todos los arreglos sean lo suficientemente
grandes para guardar lo que pondrá en ellos el programa.
C permite arreglos con más de una dimensión, el formato general es:
tipo nombre_arr [ tam1 ][ tam2 ] ... [ tamN];
Por ejemplo un arreglo de enteros bidimensionales se escribirá como:
int tabladenums[50][50];

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];

A continuación se muestra un ejemplo que asigna al primer elemento de un arreglo


bidimensional cero, al siguiente 1, y así sucesivamente.
main()
{
int t,i,num[3][4];

for(t=0; t<3; ++t)


for(i=0; i<4; ++i)
num[t][i]=(t*4)+i*1;

for(t=0; t<3; ++t)


{
for(i=0; i<4; ++i)
printf("num[%d][%d]=%d ", t,i,num[t][i]);
printf("\n");
}

En C se permite la inicialización de arreglos, debiendo seguir el siguiente formato:


tipo nombre_arr[ tam1 ][ tam2 ] ... [ tamN] = {lista-valores};
Por ejemplo:
int i[10] = {1,2,3,4,5,6,7,8,9,10};
int num[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};

107
CADENAS

A diferencia de otros lenguajes de programación que emplean un tipo denominado


cadena string para manipular un conjunto de símbolos, en C, se debe simular
mediante un arreglo de caracteres, en donde la terminación de la cadena se debe
indicar con nulo. Un nulo se especifica como '\0'. Por lo anterior, cuando se declare
un arreglo de caracteres se debe considerar un carácter adicional a la cadena más
larga que se vaya a guardar. Por ejemplo, si se quiere declarar un arreglo cadena
que guarde una cadena de diez caracteres, se hará como:
char cadena[11];

Se pueden hacer también inicializaciones de arreglos de caracteres en donde


automáticamente C asigna el carácter nulo al final de la cadena, de la siguiente
forma:
char nombre_arr[ tam ]="cadena";
Por ejemplo, el siguiente fragmento inicializa cadena con ``hola'':
char cadena[5]="hola";

El código anterior es equivalente a:


char cadena[5]={'h','o','l','a','\0'};

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];

printf("Introduce tu nombre: ");


scanf("%s",nombre);
printf("Introduce tus apellidos: ");
scanf("%s",apellidos);
printf("Usted es %s %s\n",nombre,apellidos);
}

El lenguaje C no maneja cadenas de caracteres, como se hace con enteros o


flotantes, por lo que lo siguiente no es válido:
main()
{
char nombre[40], apellidos[40], completo[80];

nombre="José María"; /* Ilegal */


apellidos="Morelos y Pavón"; /* Ilegal */
completo="Gral."+nombre+apellidos; /* Ilegal */
}

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:

especificador_de_tipo nombre_de_función( lista_de_parámetros )


{
variables locales
código de la función
}
El especificador_de_tipo indica el tipo del valor que la función devolverá mediante
el uso de return. El valor puede ser de cualquier tipo válido. Si no se específica un
valor, entonces la computadora asume por defecto que la función devolverá un
resultado entero. No se tienen siempre que incluir parámetros en una función. la
lista de parámetros puede estar vacía.
Las funciones terminan y regresan automáticamente al procedimiento que las
llamó cuando se encuentra la última llave}, o bien, se puede forzar el regreso antes
usando la sentencia return. Además del uso señalado la función return se usa para
devolver un valor.
Se examina a continuación un ejemplo que encuentra el promedio de dos enteros:
float encontprom(int num1, int num2)
{
float promedio;

promedio = (num1 + num2) / 2.0;


return(promedio);
}

main()
{
int a=7, b=10;
float resultado;

resultado = encontprom(a, b);


printf("Promedio=%f\n",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;

for( contador=1; contador<10; contador++)


printf("%d\n",contador*contador);
}

main()
{
109
cuadrados();
}

En la función cuadrados no está definido ningún parámetro, y por otra parte


tampoco se emplea la sentencia return para regresar de la función.

FUNCIONES Y ARREGLOS

Cuando se usan un arreglo como un argumento a la función, se pasa sólo la


dirección del arreglo y no la copia del arreglo entero. Para fines prácticos podemos
considerar el nombre del arreglo sin ningún índice como la dirección del arreglo.
Considerar el siguiente ejemplo en donde se pasa un arreglo a la función imp_rev,
observar que no es necesario especificar la dimensión del arreglo cuando es un
parámetro de la función.
void imp_rev(char s[])
{
int t;

for( t=strlen(s)-1; t>=0; t--)


printf("%c",s[t]);
}

main()
{
char nombre[]="Facultad";

imp_rev(nombre);
}

Observar que en la función imp_rev se usa la función strlen para calcular la


longitud de la cadena sin incluir el terminador nulo. Por otra parte, la función
imp_rev no usa la sentencia return ni para terminar de usar la función, ni para
regresar algún valor.
Se muestra otro ejemplo,
float enconprom(int tam, float lista[])
{
int i;
float suma = 0.0;

for ( i=0; i<tam; i++)


suma += lista[i];
return(suma/tam);
}

main()
{
float numeros[]={2.3, 8.0, 15.0, 20.2, 44.01, -3.0, -2.9};

printf("El promedio de la lista es %f\n", enconprom(7,numeros) );


}
110
Para el caso de que se tenga que pasar un arreglo con más de una dimensión, no
se indica la primera dimensión pero, el resto de las dimensiones deben señalarse.
Se muestra a continuación un ejemplo:
void imprtabla(int tamx,int tamy, float tabla[][5])
{
int x,y;

for ( x=0; x<tamx; x++ )


{
for ( y=0; y<tamy; y++ )
printf("t[%d][%d]=%f",x,y,tabla[x][y]);
printf("\n");
}
}

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

También podría gustarte