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 EDUCATIVA DE: TRABAJO RECEPCIONAL P R E S E N T A: Juan Arturo Badillo Rios José Luis Ortiz de la luz DIRECTOR DE TRABAJO PRÁCTICO EDUCATIVO: ISC. KARLOS REYES ORTEGA POZA RICA DE HGO; VER. 2011

Badillo riosyortizdelaluz

Embed Size (px)

Citation preview

Page 1: Badillo riosyortizdelaluz

UNIVERSIDAD VERACRUZANA

F A C U L T A D D E I N G E N I E R Í A M E C Á N I C A E L É C T R I C A

“ M A N U A L D E P R O G R A M A S A P L I C A D O S A M É T O D O S N U M É R I C O S ”

TRABAJO PRÁCTICO EDU CATIVO

P A R A A C R E D I T A R L A E X P E R I E N C I A E D U C A T I V A D E :

T R A B A J O R E C E P C I O N A L

P R E S E N T A :

Juan Arturo Badi l lo Rios

José Luis Orti z d e la lu z

D I R E C T O R D E T R A B A J O P R Á C T I C O E D U C A T I V O :

I S C . K A R L O S R E Y E S O R T E G A

PO Z A R I C A D E H G O ; V E R . 2 0 1 1

Page 2: Badillo riosyortizdelaluz

ÍNDICE

INTRODUCCIÓN

CAPITULO I

1

JUSTIFICACIÓN 3

TIPO Y NATURALEZA DEL TRABAJO 3

CARACTERÍSTICAS Y FUNCIONES ESCENCIALES

CAPITULO II

PROCESOS DEL TRABAJO

3

1.- ECUACIONES LINEALES

6

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

Page 3: Badillo riosyortizdelaluz

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

Page 4: Badillo riosyortizdelaluz

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

CAPITULO III

84

APORTACIONES Y CONTRIBUCIONES AL DESARROLLO 86

BIBLIOGRAFÍA 87

ANEXOS

88

Page 5: Badillo riosyortizdelaluz

1

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.

Page 6: Badillo riosyortizdelaluz

2

CAPITULO I

Page 7: Badillo riosyortizdelaluz

3

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.

Page 8: Badillo riosyortizdelaluz

CAPITULO II

Page 9: Badillo riosyortizdelaluz

PROCESO DEL

TRABAJO

Page 10: Badillo riosyortizdelaluz

6

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.

Page 11: Badillo riosyortizdelaluz

7

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

O

Donde el superíndice prima indica que los elementos han cambiado sus valores originales

Page 12: Badillo riosyortizdelaluz

8

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

Sustitución hacia atrás

Eliminación hacia adelante

Page 13: Badillo riosyortizdelaluz

9

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)

Page 14: Badillo riosyortizdelaluz

10

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

Page 15: Badillo riosyortizdelaluz

11

1.2.2.- Diagrama de flujo

Diagrama de Flujo Gauss Simple eliminación hacia adelante

Page 16: Badillo riosyortizdelaluz

12

Diagrama de Flujo Gauss Simple sustitución hacia atrás

Page 17: Badillo riosyortizdelaluz

13

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

Page 18: Badillo riosyortizdelaluz

14

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

Page 19: Badillo riosyortizdelaluz

15

1.2.5.- Demostración del programa

Page 20: Badillo riosyortizdelaluz

16

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.

Page 21: Badillo riosyortizdelaluz

17

(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

Page 22: Badillo riosyortizdelaluz

18

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 .

Page 23: Badillo riosyortizdelaluz

19

1.3.2.- Diagrama de flujo

Diagrama de Flujo Gauss Seidel

Page 24: Badillo riosyortizdelaluz

20

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

Page 25: Badillo riosyortizdelaluz

21

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

Page 26: Badillo riosyortizdelaluz

22

{ gotoxy(y+z,t);cout<<tabla[q]; q++; z=z+10; } i++; } } void main() {

Page 27: Badillo riosyortizdelaluz

23

1.3.5.- Demostración del programa

Page 28: Badillo riosyortizdelaluz

24

Page 29: Badillo riosyortizdelaluz

25

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

Page 30: Badillo riosyortizdelaluz

26

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

Page 31: Badillo riosyortizdelaluz

27

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.

Page 32: Badillo riosyortizdelaluz

28

1.4.2.- Diagrama de Flujo

Diagrama de Flujo Gauss Jordan

N,M,I,A,J

Page 33: Badillo riosyortizdelaluz

29

Diagrama de Flujo principal Gauss Jordan subrutina

I,PIVOTE,A,J,K,N,

M,CERO

SUBROUTINE

GAUSS (N,M,A)

Page 34: Badillo riosyortizdelaluz

30

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

Page 35: Badillo riosyortizdelaluz

31

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 = i i

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

Page 36: Badillo riosyortizdelaluz

32

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

Page 37: Badillo riosyortizdelaluz

33

1.4.5.- Demostración del programa

Page 38: Badillo riosyortizdelaluz

34

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,

Y

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.

Page 39: Badillo riosyortizdelaluz

35

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

Page 40: Badillo riosyortizdelaluz

36

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:

Page 41: Badillo riosyortizdelaluz

37

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,

Page 42: Badillo riosyortizdelaluz

38

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.

Page 43: Badillo riosyortizdelaluz

39

2.2.2.- Diagrama de Flujo

Diagrama de Flujo Bisección

Page 44: Badillo riosyortizdelaluz

40

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

Page 45: Badillo riosyortizdelaluz

41

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

Page 46: Badillo riosyortizdelaluz

42

2.2.5.- Demostración del programa

Page 47: Badillo riosyortizdelaluz

43

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

Page 48: Badillo riosyortizdelaluz

44

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:

Page 49: Badillo riosyortizdelaluz

45

Agrupando términos se obtiene

O

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

Page 50: Badillo riosyortizdelaluz

46

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

Page 51: Badillo riosyortizdelaluz

47

2.3.2.- Diagrama de Flujo

Diagrama de Flujo Falsa Posición

Page 52: Badillo riosyortizdelaluz

48

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

Page 53: Badillo riosyortizdelaluz

49

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

Page 54: Badillo riosyortizdelaluz

50

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

Page 55: Badillo riosyortizdelaluz

51

2.3.5.- Demostración del programa

Page 56: Badillo riosyortizdelaluz

52

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

f´ (Ec.2.5)

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

Page 57: Badillo riosyortizdelaluz

53

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

Page 58: Badillo riosyortizdelaluz

54

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.

Page 59: Badillo riosyortizdelaluz

55

2.4.2.- Diagrama de Flujo

Diagrama de Flujo Newton Raphson

No convergen en

NMI iteraciones

NGRAD,N,M,I,A,APROX,NRAIZ,X,N

MI,B,C,Y,REL

INICIO

Page 60: Badillo riosyortizdelaluz

56

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

Page 61: Badillo riosyortizdelaluz

57

2.4.3.- Demostración del programa

Page 62: Badillo riosyortizdelaluz

58

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.

Page 63: Badillo riosyortizdelaluz

59

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.

Page 64: Badillo riosyortizdelaluz

60

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:

Page 65: Badillo riosyortizdelaluz

61

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.

Page 66: Badillo riosyortizdelaluz

62

Tabla 3.2.1

Error relativo porcentual

Figura 3.3

Comparación de la solución verdadera con una solución numérica usando el método de Euler, para la integral de y' = -2X3 + 1 2X2 - 20x + 8.5 desde x = O hasta x = 4 con un tamaño de paso de 0.5. La condición inicial en x = O es y = 1.

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

Page 67: Badillo riosyortizdelaluz

63

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.

Page 68: Badillo riosyortizdelaluz

64

3.2.2.- Diagrama de flujo

Diagrama de Flujo Euler

Page 69: Badillo riosyortizdelaluz

65

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

Page 70: Badillo riosyortizdelaluz

66

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

Page 71: Badillo riosyortizdelaluz

67

3.2.5. - Demostración del programa

Page 72: Badillo riosyortizdelaluz

68

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

Page 73: Badillo riosyortizdelaluz

69

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

.0000

0

1.00000 0

0.5 3.21875 3.277344 1.8

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

Page 74: Badillo riosyortizdelaluz

70

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

Page 75: Badillo riosyortizdelaluz

71

3.3.2.-Diagrama de flujo

Diagrama de Flujo Runge Kutta

Page 76: Badillo riosyortizdelaluz

72

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

Page 77: Badillo riosyortizdelaluz

73

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

Page 78: Badillo riosyortizdelaluz

74

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

Page 79: Badillo riosyortizdelaluz

75

3.3.5.- Demostración del programa

Page 80: Badillo riosyortizdelaluz

76

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.

Page 81: Badillo riosyortizdelaluz

77

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

f

Después de la integración y de las manipulaciones algebraicas, se obtiene la siguiente fórmula:

f f f (Ec.4.1)

Page 82: Badillo riosyortizdelaluz

78

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:

a b f f f

(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

t b a

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.

Page 83: Badillo riosyortizdelaluz

79

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.

Page 84: Badillo riosyortizdelaluz

80

4.2.2.- Diagrama de flujo

Diagrama de Flujo Simpson 1/3

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

INICIO

Page 85: Badillo riosyortizdelaluz

81

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

Page 86: Badillo riosyortizdelaluz

82

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

Page 87: Badillo riosyortizdelaluz

83

4.2.5.- Demostración del programa

Page 88: Badillo riosyortizdelaluz

84

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.

Page 89: Badillo riosyortizdelaluz

CAPITULO III

Page 90: Badillo riosyortizdelaluz

86

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.

Page 91: Badillo riosyortizdelaluz

87

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

Page 92: Badillo riosyortizdelaluz

88

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.

Page 93: Badillo riosyortizdelaluz

89

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.

Page 94: Badillo riosyortizdelaluz

90

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

Page 95: Badillo riosyortizdelaluz

91

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

Page 96: Badillo riosyortizdelaluz

92

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;

Page 97: Badillo riosyortizdelaluz

93

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;

Page 98: Badillo riosyortizdelaluz

94

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.

Page 99: Badillo riosyortizdelaluz

95

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

Page 100: Badillo riosyortizdelaluz

96

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

* / %

+ -

Page 101: Badillo riosyortizdelaluz

97

<< >>

< <= > >=

== !=

&

^

|

&&

||

?

= += -= *= /=

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.

Page 102: Badillo riosyortizdelaluz

98

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

Page 103: Badillo riosyortizdelaluz

99

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

Page 104: Badillo riosyortizdelaluz

100

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;

Page 105: Badillo riosyortizdelaluz

101

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

Page 106: Badillo riosyortizdelaluz

102

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.

Page 107: Badillo riosyortizdelaluz

103

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

Page 108: Badillo riosyortizdelaluz

104

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

Page 109: Badillo riosyortizdelaluz

105

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

Page 110: Badillo riosyortizdelaluz

106

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

Page 111: Badillo riosyortizdelaluz

107

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

Page 112: Badillo riosyortizdelaluz

108

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.

Page 113: Badillo riosyortizdelaluz

109

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

Page 114: Badillo riosyortizdelaluz

110

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

Page 115: Badillo riosyortizdelaluz

111

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.