Convergencia de iteraciones en métodos numéricos
Convergencia de iteraciones en métodos numéricos
APLICACIONES A LA FISICA Y
LA INGENIERIA CON C
Impresión Noviembre 2022 :
dell:REPO/[Link]
BY
LUIS CARDON
SALTA
9 de Noviembre 2022
PUBLIQUE O PEREZCA
2
Contents
1 Búsqueda de raı́ces 1
1.1 Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1.1 Ejemplo: un problema de Mecánica . . . . . . . . . . . . . . . . . . . 2
1.2 Raı́ces. Fundamentos matemáticos . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Fı́sica de la caı́da libre con fricción. OMITIR. EN ELABORACION. . . . . . 6
1.3.1 REVISAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.4 Métodos numéricos para la búsqueda de raı́ces . . . . . . . . . . . . . . . . 10
1.5 Método de la bisección . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.5.1 Ventajas y desventajas . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.6 Convergencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.6.1 Convergencia del método de la bisección . . . . . . . . . . . . . . . . 13
1.7 Error . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.7.1 Exactitud y precisión. . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.7.2 Ejemplo: raı́z de f (x) = x6 − x − 1 . . . . . . . . . . . . . . . . . . . 17
1.8 Resolución computacional. C . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.8.1 Ejemplo: cálculo del coeficiente de arrastre. . . . . . . . . . . . . . . 26
1.9 Resolución computacional con Python . . . . . . . . . . . . . . . . . . . . . 30
1.9.1 Funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
1.9.2 Definción de funciones y módulos . . . . . . . . . . . . . . . . . . . . 31
1.9.3 Gráfico de funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
1.9.4 Trabajando desde la terminal interactiva . . . . . . . . . . . . . . . . 38
1.9.5 El método de la Bisección en Python . . . . . . . . . . . . . . . . . . 39
1.10 El método de Newton-Raphson . . . . . . . . . . . . . . . . . . . . . . . . . 44
1.10.1 Algoritmo de Newton . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
1.10.2 Ventajas y desventajas . . . . . . . . . . . . . . . . . . . . . . . . . . 45
1.10.3 Resolución computacional . . . . . . . . . . . . . . . . . . . . . . . . 46
1.11 Los métodos de la secante . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
i
ii
15 sobras 293
15.1 Procedimiento de Adams y Rogers . . . . . . . . . . . . . . . . . . . . . . . 293
15.2 Una biblioteca de funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
19 Aplicaciones 329
19.1 Conducción unidimensional en una varilla delgada . . . . . . . . . . . . . . . 329
19.1.1 Caso de generación nula . . . . . . . . . . . . . . . . . . . . . . . . . 330
19.1.2 Caso de generación uniforme . . . . . . . . . . . . . . . . . . . . . . . 330
19.2 Derivación de la ecuación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
19.3 Resolución computacional . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
19.3.1 Caso S = 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
19.3.2 Caso S 6= 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340
19.3.3 Fuente no homogénea . . . . . . . . . . . . . . . . . . . . . . . . . . . 342
19.4 Propiedades no homogéneas. HACIENDO. TERMINAR . . . . . . . . . . . 342
19.4.1 Discretización A . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343
19.4.2 Discretización B . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
19.5 Flujo unidimensional en conductos . . . . . . . . . . . . . . . . . . . . . . . 345
19.5.1 Perfil de velocidad en un canal . . . . . . . . . . . . . . . . . . . . . . 346
Búsqueda de raı́ces
1.1 Introducción
Las raı́ces o ceros de una función f (x) son los valores de x tales que satisfacen la ecuación
y = f (x) = 0 (1.1)
Designemos por α a la raı́z, es decir el valor de x que tal que f (x = α) = 0. Las raı́ces
o ceros de la función no son importante por el valor cero mismo. Si el mismo problema se
presenta como z = f (x) + x = x, que podemos describir con la ecuación g(x) = x, ahora
la búsqueda de ceros se transforma en la búsqueda de los valores de x que satisfagan la
igualdad, es decir en la resolución de la ecuación. Estos valores tienen la misma importancia
conceptual que los ceros o raı́ces del problema original. De manera que resolver los ceros o
las raı́ces de una función es equivalente a resolver la ecuación. Las ecuaciones de interés se
presentan aisladas o formando sistemas y describen problemas de interés en múltiples ramas
de la ciencia. En las secciones siguientes describiremos algunos de estos problema, los más
simples y nos introduciremos en los métodos para su resolución numérica, necesarios cuando
la resolución analı́tica es difı́cil o aún imposible.
Cuando podemos invertir explı́citamente la función f , es decir cuando podemos despejar x
explı́citamente en función de y de manera de tener otra función g = f −1 tal que x = f −1 (y)
o x = g(y), la raı́z se obtienen inmediatamente como α = g(0). Decimos que hemos resuelto
la ecuación en forma exacta o analı́tica. Esto no siempre es posible y depende de si la
función en cuestión es algebraica o trascendental.
Las funciones algebraicas son aquellas que se expresan mediante una suma finita de expre-
siones algebraicas, en las que aparecen solo los operadores suma, resta, producto, cociente
y potencia de números fraccionarios. Con mayor o menor dificultad pueden invertirse en
forma analı́tica. El ejemplo siguiente muestra una función fácil de invertir
x2 − 4 (x − 2)(x + 2)
y= = = x − 2 entonces x = y − 2 (1.2)
x+2 x + 2)
Las función trascendentales, en cambio, son aquellas que trascienden las reglas del
álgebra, requieren algo diferente para su cálculo e interpretación. En ellas aparecen fun-
ciones exponenciales, logarı́tmicas, trigonométricas, hiperbólicas u otras funciones especiales
de la fı́sica matemática, tales como la función error, gamma, etc., y no pueden ser repre-
sentadas por expresiones algebraicas. Estas funciones no pueden invertirse y por lo tanto
1
2
la obtención de sus ceros debe realizarse en forma numérica. Los siguientes son ejemplos
sencillos de esta clase de funciones
y = exp(−x) − x y = cos(x) y = x1/x y = log(x) (1.3)
La resolución explı́cita de problema planteado por f (x) = 0, que aparece con mucha frecuen-
cia en la resolución de problemas de matemática, ciencias e ingenierı́a, puede resultar muy
dificultosa para algunas funciones algebraicas e imposible para funciones trascendentales.
Estos casos conducen al problema de búsqueda de raı́ces que debe hacerse en forma
numérica.
El problema tiene antecedentes tempranos en la historia de la ciencia, aunque en sus primeras
manifestaciones, aun traducidos a términos modernos, tal vez no los reconocerı́amos como
problemas de búsqueda de raı́ces. Uno de estos problemas fue la obtención de la raı́z cuadrada
de un número a, problema que puede expresarse como la resolución de la ecuación f (x) =
x2 − a = 0. Este problema apareció ya en tiempos babilónicos ([Link]
org/wiki/Methods_of_computing_square_roots), y llegó a nuestros dı́as tratado por Isaac
Newton (1642-1726) y por Joseph Raphson (c1646-c1715). Con sus nombres reconocemos
hoy a uno de los métodos más eficaces para la búsqueda de raı́ces y que estudiaremos en la
sección 1.10 en la forma que le dió Thomas Simpson (1710-1760) ya basada en el cálculo.
f (k) = 0 (1.11)
3
Objetos no muy pequeños.
4
Esto implica que los valors de f (a) y f (b) deben tener distinto signo y la gráfica de la función
f (x) debe cortar el eje x un número impar de veces o por lo menos una vez.
El teorema del valor medio o teorema de Bolzano, establece que debe haber por lo
menos una raı́z, cero o solución,que designaremos α, en el intervalo abierto (a, b), tal que
f (α) = 0, es decir
Si f (a)f (b) < 0 ∃ α ∈ (a, b) : f (α) = 0 (1.13)
La raı́z es única en el intervalo [a, b] si la derivada, f ′ (x) ∈ [a, b] existe y preserva su signo.
Desde el punto de vista práctico, cuando hay más de una raı́z, el proceso de separación de
raı́ces implica determinar el signo de la derivada de la función en puntos de una partición
del intervalo [a, b] suficientemente fina.
Como ejemplo consideremos la función seno entre [π/2, 3π/2] mostrada en la Figura 1.1. Es
evidente allı́ (siendo f (3π/2) = −1 y f (π/2) = 1) que la condición f (a)f (b) < 0 garantiza la
existencia de al menos un cero, o un número impar de ellos, entre los extremos del intervalo.
En el intervalo señalado la función es siempre negativa, por lo que solo habrá una sola raı́z.
Para encontrar las raı́ces cuando no existe una solución explı́cita o cerrada para f (x) = 0
(por ejemplo, cuando la función es trascendental), debe recurrirse a métodos numéricos
A-cursos/cursoMNu/raı́[Link] - August 22, 2023 5
especı́ficos que por lo general caen en la categorı́a de métodos iterativos. Estos métodos
se caracterizan por ir aproximando la solución en una sucesión de pasos repetitivos.
Presentaremos aquı́ algunos de ellos. La búsqueda iterativa de raı́ces, si bien es conceptual-
mente muy simple, puede complicarse en muchos casos (raı́ces múltiples, etc.). Si se enfrenta
con estos problemas, el estudiante deberá recurrir a la bibliografı́a pertinente ([4], [5], [6],
[7], [13]) y deberá hacer uso de su ingenio para resolverlos.
6
donde F es la fuerza que causa la aceleración del objeto. En nuestro caso, un objeto en caı́da
libre, o aún en el caso más general de un objeto en vuelo libre sobre la superficie de la tierra,
está sometido a la fuerza de la gravedad y a la fuerza de arrastre o de resistencia que ejerce
el medio en que se mueve.
F = mg + f(v)v̂ (1.15)
ingenieros y pilotos se ocuparon del tema en las primeras decadas del siglo XIX. Se estudió
en forma experimental mediante el uso de péndulos, caı́da libre, y tuneles de viento.
Eiffel, desde un laboratorio montado en la famosa torre que lleva su nombre (1905-1911)
para estudiar el de la resistencia al movimiento que ejerce el aire.
No obstante, no se dispuso una teorı́a cientı́fica que explicara el fenómeno hasta que Prandlt
en 1904 propuso su teorı́a de la capa lı́mite, que comenzó con el desarrollo de la Mecánica
de Fluidos como ciencia moderna. En este ámbito, las fuerzas que el flujo de un fluido ejerce
al objeto (o la que el objeto ejerce al fluido, opuesta a la primera) se denomina fuerza de
arrastre, y su estudio es importante en un gran número de asuntos prácticos. Piense en
cualquier vehı́culo de transporte, desde una bicicleta, su automóvil, un camión o el tren o
incluso un cohete espacial en su vuelo ascencional o en su regreso a tierra, todos ellos, son
objetos que se mueven en un fluido, y mucha de la potencia que empleamos en esos vehı́culos
se usa para contrarrestar el efecto de la perdidad de energı́a ocasionada por el arrastre.
Figure 1.2: Para flujo laminar la separación se produce en algún punto en la parte frontal
de la esfera y la estela es grande. La sección transversal de la capa lı́mite separada aumenta
la sección transversal de la esfera, aumentando ası́ la diferencia de presión causada por el
objeto. Para flujo turbulento, la capa lı́mite permanece adherida a la esfera y la separación
se produce bastante atrás, y la estela es delgada. Su contribución a la fuerza de arrastre de
presión es menor comparada con la fricción. A medida que el número de Reynolds crece, la
separación se produce más atrás y el coeficiente de arrastre disminuye.
El arrastre tiene origen en dos fenómenos, por una lado en la diferencia de presión que se
produce entre barlovento (parte de un objeto de cara el viento) y sotavento (parte de un
objeto a espaldas del viento) de un cuerpo. Este efecto es predominante en los objetos
romos y es áltamente dependiente de la geometrı́a del cuerpo, sobre todo el área de sección
transversal normal a la dirección del flujo medio. Por otro lado, en la fuerza de fricción que
se produce por efecto de la viscosidad en la capa lı́mite superficial del cuerpo, y por ende,
dependiente de su área.
8
1.3.1 REVISAR
Consideremos las ecuaciones gobernantes del movimiento de un cuerpo romo, tal como una
esfera, por ejemplo, que por simplicidad se mueve en una dimensuón. La segunda ley de
Newton establece
d2 x
= mF (1.16)
dt2
Cualquiera sea la forma funcional de la fuerza, se puede como una serie de potencias. Por
ahora consideremos solo los términos de segundo orden
F = av + bv 2 (1.17)
En el caso de una esfera, para número de Reynolds moderado, tiene lugar un régimen de
capa lı́mite, que si bien se produce por efecto de la viscosidad, su contribución a la fuerza
de arrastre es menor. No obstante, en este régimen ocurre la denominada separación de la
capa lı́mite, que a los efectos de la presión, modifica la forma del cuerpo y en consecuencia
la fuerza de arrastre de forma.
Para este régimen, se puede suponer que la viscosidad, y en consecuencia el número de
Reynolds, no tiene efecto en el fenómeno. Existen dos formas de predecir de que depende la
fuerza de arrastre
FD = CρAv 2 (1.19)
• Para Re más altos, pero no tanto como para desencadenar el régimen turbulento.
Flujo reptante
Stokes, [14], demostró que para Re → 0, situación que se obtiene para objetos muy pequeños
o para fluidos muy viscosos, la fuerza de arrastre es proporcional a la velocidad
FD = 3πµDv (1.21)
es decir k = 3πµD y n = 1.
La situación tiene aplicación en el meteorologı́a, en el análisis de la velocidad de las gotas
de lluvia, en geologı́a, en el análisis de la dispersión de polvo y cenizas volcánicas, en los
problemas de sedimentación, en biologı́a en el estudio de organismos acuáticos y aéreos
pequeños, etc., todas ellas situaciones en las que se trata de partı́culas muy pequeñas.
5
Transformación de Galileo
10
Algunos métodos utilizan ambas ideas simultáneamente. En las secciones siguientes pre-
sentaremos los siguientes:
En la búsqueda numérica de la raı́z, el intervalo [a, b] debe elegirse de manera que contenga
sólo una raı́z. Si hubiera dos raı́ces, o cualquier otro número par de ellas, el algoritmo no
detectará ninguna raı́z en el intervalo. Si aún se aplica, el algoritmo encontrará una raı́z,
pero no sabremos cuantas de ellas hay en el intervalo y cual de ellas encuentra. Si hubiera
un número impar de raı́ces, el método de la bisección convergerá siempre a alguna de ellas,
pero no sabremos a cual. Por eso es importante haber visualizado el comportamiento de la
función antes de comenzar la busqueda de raı́ces.
El método de la bisección o búsqueda binaria es el método de encorchetado, bracketing,
más conocido. Consiste en dividir el entorno [a, b] por la mitad. La abscisa que corresponde
al promedio de a y b se denomina c y será nuestra primera aproximación a la raı́z,
a+b
c= (1.22)
2
El valor de c determina dos nuevos intervalos [a, c] y [c, b] y la raı́z α estará incluida en
alguno de ellos, como se muestra en la figura 1.3. La distancia o longitud entre los lı́mites
de cualquiera de estos intervalos, será siempre mayor que la distancia |c − α| entre la raı́z y
c.
|b − c|
|α − c| |α − c| < |b − c| < |b − a|
a c α b
Figure 1.3: Bisección del intervalo de búsqueda [a, b]
Podemos usar la longitud de los segmentos definidos por los intervalos [a, c] y [c, b], que son
respectivamente |c − a| y |b − c|, para acotar la diferencia entre la raı́z α y el valor c, |c − α|,
de la siguiente manera
|c − α| ≤ |b − c| = |c − a| (1.23)
siendo |b − c| o |c − a| una cota superior. Si esta cota es suficientemente pequeña, tomamos
el valor de c como una aproximación al valor de la raı́z y hacemos c ≈ α. La diferencia
entre el valor aproximado y el valor de la raı́z es el error de la solución numérica. En el
caso del método de la bisección no es posible conocer el error, pero como hemos visto si es
posible acotarlo, es decir es posible determina si es menor que una cantidad determinada
suficientemente pequeña.
Cuán pequeño es suficientemente pequeño depende de la precisión requerida para el resul-
tado. La precisión nos indica cuán cercano está el valor aproximado del verdadero valor de
la raı́z. El valor mı́nimo de la precisión aceptable se denomina tolerancia y se designa con
ε. Es un número pequeño, arbitrario, predeterminado, que da una medida de la pequeñez
que debe tener la cota del error para que nos quedemos satisfechos con la solución.
Entonces, exigiremos que la distancia |b − c| o |c − a| sea menor que cierta tolerancia ε, un
número pequeño, arbitrario.
En concreto, c será una aproximación de α en el intervalo [a, b] si
|c − α| ≤ |b − c| = |c − a| < ε (1.24)
Si en caso contrario, no se satisface el criterio |b − c| = |c − a| < ε, podemos tomar como
nuevo intervalo de búsqueda al segmento [a, c] o [c, b]. De entre los dos elegimos aquel que
12
contenga o encorchete la raı́z, es decir, para el cual se cumple la condición que f (a)f (c) < 0
o f (c)f (b) < 0. El procedimiento se repite obteniéndose una sucesion de valores {ci } =
{c0 , c1 , c2 , ..., cN } hasta que aguno de ellos satisface la tolerancia establecida. El algoritmo
se puede describir de la siguiente manera.
Algoritmo
6. Volver al paso 2.
El algoritmo producirá una serie de valores {ci } que como hemos visto aproximan la raı́z
cada vez con mayor precisión. Decimos que la sucesión o serie de valores convege a la raı́z.
1. Es muy simple, fácil de programa, sólo requiere calcular el promedio de dos números.
2. Al ser un método de encorchetado siempre converge.
3. Si hay más de una raı́z, siempre converge a una.
4. Se puede calcular rigurosamente una cota para el error.
5. La razón de convergencia es predecible.
6. A mayor número de iteraciones mayor presición.
1.6 Convergencia
Los métodos iterativos producen una sucesión o un serie de resultados que es de esperar
que se acerquen progresivamente a la solución buscada. Esto no siempre es ası́. Si la serie
tiende a un valor lı́mite decimos que la serie converge. En caso contrario decimos que
la serie diverge. El cómputo de los procesos iterativos divergentes termina en valores no
computables (overflow o NaN, Not a Number en C) y, de no tomar medidas preventivas, en
la terminación del programa.
Para algunos algoritmos, la convergencia está siempre garantizada, para otros, ésta depende
de ciertas condiciones que varı́an con el algoritmo. Una propiedad importante de los algorit-
mos iterativos de búsqueda de raı́ces es la rapidez de la convergencia, que puede determinarse
analı́ticamente.
Antes de pasar a los detalles de la convergencia en el método de la bisección, demos primero
una mirada práctica, experimental, del asunto. En la figura 1.4 se muestra gráficamente, para
el ejemplo estudiado, los valores aproximados de la raı́z en función del número de iteración.
La tabla de datos para el gráfico se produce en la lı́nea 41 del programa biseccion-1.c.
Se observa que las primeras aproximaciones a la raı́z difieren de ella por más o por menos.
f (x) = x6 − x − 1
1.26
dat : 1:2
1.24
1.22
1.2
1.18
1.16
1.14
1.12
0 2 4 6 8 10 12 14 16 18 20
Los métodos iterativos en general producen una secuencia que esperamos converja a la
solución, tenemos que
α = limn→∞ cn (1.26)
14
1.7 Error
Al obtener una solución aproximada de un problema es importante estimar el error que se
comete, que se puede expresar como error absoluto o error relativo. El error absoluto
es la diferencia entre el valor aproximado y el valor de la raı́z.
ea = |αk − α| (1.35)
A-cursos/cursoMNu/raı́[Link] - August 22, 2023 15
1
♦ bidat : 1:4 ♦
0.1 ♦
♦
♦
0.01 ♦
♦
♦
♦
0.001 ♦
error ♦
♦
0.0001 ♦
♦
♦
1e-05 ♦
♦
♦
♦
1e-06 ♦
♦
♦
1e-07 ♦
0 5 10 15 20 25
iteración
Figure 1.5: Evolución de error
forma analı́tica, y el valor aproximado que podemos calcular con nuestro algoritmo numérico.
En los métodos numéricos, la exactitud está medida por el error.
f (x) = x6 − x − 1 f (x) = x6 − x − 1
1.5 2
a a
1.4 c 1.8 c
1.3 b 1.6 b
1.2 1.4
1.1 1.2
1 1
2 4 6 8 10 12 14 16 18 20 2 4 6 8 10 12 14 16 18 20
Razón de convergencia
El análisis numérico puede determinar la velocidad con los distintos métodos proceden hacia
la convergencia. De ello surge una clasificación que los distingue en métodos de convergencia
lineal, cuadrática y superlineal.
Una secuencia {cn }∞
n ≥ 0 se dice que converge con orden p ≥ 1 a un punto α si se cumple
que
|α − cx+1 | ≥ K|α − cx+1 |n con n ≥ 0 y K > 0. (1.37)
otra forma de escribirlo es
|α − cx+1 |
limn7→∞ = =K (1.38)
|α − cx+1 |n
Si p = 1 se habla convergencia lineal y K, la razón de convergencia debe ser menor que
uno.
Si p > 1 se habla convergencia superlineal. Para p = 2 y p = 3 se habla convergencia
cuadrática y cúbica.
Para convergencia lineal se puede inducir que
Existen varios criterios de terminación para un algoritmo iterativo. Estos pueden tener
convergencia lenta, no obstante por lo general se preestablece un máximo de iteraciones,
alcanzado el cual el algoritmo se detiene. Si la terminación se hizo mediante este criterio
debiera analizarse si los resultados obtenidos son suficientemente convergidos.
A-cursos/cursoMNu/raı́[Link] - August 22, 2023 17
Un criterio más acorde con la idea de convergencia consiste en detener la iteración cuando la
diferencia entre dos resultados sucesivos resultan suficientemente pequeña, es decir |cn+1 −
cn )| < ǫ. Este criterio puede ser engañoso si la convergencia es muy lenta o cuando la raı́z
es cercana a cero. La forma relativa de este criterio es
|cn+1 − cn |
< ǫr (1.40)
|cn+1 |
Esta forma se prefiere cuando no se conoce los valores que tomarán las raı́ces o la función. Los
valores de tolerancia recomendable depende de los valores de la raı́z. Se pueden especificar en
forma absoluta o relativa. Si la raı́z esta cercana a cero, la forma relativa no es conveniente.
Si la raı́z es de orden 1, una tolerancia absoluta de ǫ = 10−6 será aceptable. Si la raı́z ocurre
para valores más altos, la tolerancia deberá ser menor, en cuyo caso conviene el uso de un
criterio relativo.
Teniendo en cuenta que las raı́ces hacen cero la función, aún también podrı́a usarse como
criterio de convegencia |f (xn+1 )| < ǫ. La también tolerancia puede elegirse en relación a la
precisión de la máquina, véase por ejemplo la sección Bisection Methods en el libro Numerical
Recipies, [13].
f(x)=x*x*x*x*x*x-x-1
set xrange[-10:10]
set yrange[-10000:10000]
plot f(x)
para un primer intento se puede omitir la especificación del rango. La figura 1.7, realizada
con gnuplot, muestra el comportamiento general de la función, y en la cercanı́a de la raı́z.
f (x) = x6 − x − 1 f (x) = x6 − x − 1
10000 1
f(x) f(x)
5000 0.5
0 0
-5000 -0.5
-10000 -1
-10 -5 0 5 10 1 1.04 1.08 1.12 1.16 1.2
Figure 1.7: La función f (x) = x6 − x − 1 en los intervalos de x, [−10, 10] y [1, 1.2]
18
5 float ff ( float R ) ;
6
7 int main ()
8 {
9 // biseccion -1. c
10 // o b t i e n e una raiz de la f u n c i o n
11 // f ( x ) = x ^6 - x -1
12 // en el i n t e r v a l o [ a : b ] = [ 1 : 2 ]
13
14 int i =0;
15 float x ,a ,b ,c , e p s i l o n =1e -6;
16
17 a =1;
18 b =1.2;
19
20 // C a l c u l a la ff f ( x ) vs . x
21 // para e x p l o r a r g r a f i c a m e n t e
22
32 c =( a + b ) /2.;
33 while ( fabs (b - c ) > e p s i l o n)
34 {
35 if ( ff ( b ) * ff ( c ) < 0. )
36 a=c;
37 else
38 b=c;
39
A-cursos/cursoMNu/raı́[Link] - August 22, 2023 19
40 c =( a + b ) /2.;
41
42 i = i +1;
43 printf ("%2 d %1.6 f %1.2 g \ n " ,i ,c , fabs (b - c ) ) ;
44 }
45
46 return 0;
47 }
48
49 float ff ( float x )
50 {
51 return pow (x ,6.) -x -1.;
52 }
./bi
1 1.150000 0.05
2 1.125000 0.025
3 1.137500 0.013
4 1.131250 0.0063
5 1.134375 0.0031
6 1.135938 0.0016
7 1.135156 0.00078
8 1.134766 0.00039
9 1.134570 0.0002
10 1.134668 9.8e-05
11 1.134717 4.9e-05
12 1.134741 2.4e-05
13 1.134729 1.2e-05
14 1.134723 6.1e-06
15 1.134726 3.1e-06
16 1.134725 1.4e-06
17 1.134724 7.2e-07
Figure 1.8: Salida del programa biseccion-1.c
8 int main ()
9 {
10 // biseccion -2. c
11
12 // o b t i e n e una raiz de la f u n c i o n
13 // f ( x ) = x ^6 - x -1
14 // en el i n t e r v a l o [a - b ]=[1 -2]
15
16 int i =0;
17 float a ,b , c ;
18 a =1.;
19 b =2.;
20 // C a l c u l a la ff f ( x ) vs . x
21 // para e x p l o r a r g r a f i c a m e n t e
22
23 // for ( x =0.; x <= b ; x = x +0.1)
24 // printf ("% f % f \ n " ,x , ff ( x ) ) ;
25 // return ;
26
27 c = b i s e c c i o n (a , b ) ;
28 printf (" Raiz =% f F ( raiz ) =% f \ n " ,c , ff ( c ) ) ;
29 return 0;
30 }
31
32 float ff ( float x )
33 {
34 return pow (x ,6.) -x -1.;
35 }
36 float b i s e c c i o n( float a , float b )
37 {
38 float c ;
39 int i =0 , imax =100;
40 float e p s i l o n =1.e -7;
41 // existe la raiz en el i n t e r v a l o
42 if ( ff ( a ) * ff ( b ) >0)
43 f p r i n t f( stderr , "# No hay raiz en el i n t e r v a l o \ n ") ;
44
45 c =( a + b ) /2.;
46 while ( fabs (b - c ) > e p s i l o n && i < imax )
47 {
48 if ( ff ( b ) * ff ( c ) < 0. )
49 a=c;
50 else
51 b=c;
52
53 c =( a + b ) /2.;
54 i = i +1;
55 // f p r i n t f( stderr , "%2 d %1.5 f %1.2 g \ n " ,i ,c , fabs (b - c ) ) ;
56 }
57 return c ;
58 }
59
A-cursos/cursoMNu/raı́[Link] - August 22, 2023 21
Un defecto de este programa es que el nombre de la función de trabajo, en este caso ff,
esta embebido en la función biseccion, lo que es poco conveniente. Para trabajar con
otra función, con otro nombre, habrı́a que modificar la función biseccion, cosa que por lo
general no querremos hacer. La función biseccion podrı́a estar en una librerı́a que no debe
modificarse. Se podrı́a cambiar la función misma ff lo que resultarı́a propenso a errores.
Para solucionar esta clase de problemas, las funciones de C admiten como argumento el
nombre de funciones. La alternativa III a continuación muestra, sin mucha explicación,
como se usa.
Una caracterı́stica de C algo más avanzada permite pasarle a una función el nombre de otra.
El prototipo de una función que recibe como argumento otra función es
aquı́ float (*f)(float) es un puntero a una función que retorna un flotante y que toma
como argumento otro flotante. En nuestro caso, el prototipo de la función biseccion será
c=biseccion(a, b , sin);
c=biseccion(a, b , cos);
c=biseccion(a, b , mifuncion);
if( (*f)(a)*(*f)(b);
....
}
5 float f1 ( float x ) ;
6
7 float b i s e c c i o n( float a , float b , float (* f ) ( float ) , int i m p r i m a t u r) ;
8
9 int main ()
10 {
11 // biseccion -3. c
12 // o b t i e n e una raiz de la f u n c i o n
13 // f ( x ) = x ^6 - x -1
14 // en el i n t e r v a l o [a - b ]=[1 -2]
15
16 int i =0 , i m p r i m a t u r;
17 float a ,b , c ;
18 a =1.;
19 b =2.;
20 // C a l c u l a la ff f ( x ) vs . x
21 // para e x p l o r a r g r a f i c a m e n t e
22
23 // for ( x =0.; x <= b ; x = x +0.1)
24 // printf ("% f % f \ n " ,x , ff ( x ) ) ;
25 // return ;
26
27 c = b i s e c c i o n (a ,b , f1 ,1) ;
28 printf (" Raiz =% f f ( raiz ) =% g \ n " ,c , f1 ( c ) ) ;
29 return 0;
30 }
31
32 float f1 ( float x )
33 {
34 return pow (x ,6.) -x -1.;
35 }
Ahora la función biseccion recibe como argumento el nombre de la función de trabajo. Por
supuesto esta debe estar declarada y definida dentro del alcance de la llamada.
La función biseccion se dispone en el archivo lib-biseccion.c para posibilitar su reuti-
lización y se muestra en el listado 1.4.
7
Esta función y otras para obtener raı́ces debieran guardarse en un único archivo que hace las veces de
librerı́a, o mejor dicho de biblioteca. Aquı́ se las ha mantendio en un archivo individual con el propósito de
facilitar la numeración automática desde 1 que hace el procesador de texto al imprimirlas.
A-cursos/cursoMNu/raı́[Link] - August 22, 2023 23
Burden y Faires, [7], sugiere que, para determinar qué subintervalo de [a, b] contiene la raı́z es
mejor utilizar la función signo. En C99 dispone la función copysign(float x, float y)
de la librerı́a tgmath, que compone un valor con el signo de y y el valor de x. La función
devolverá 1 o −1. Da el mismo resutado pero evita overflows en la multiplicación f (a)f (b).
Esta alternativa se ha implementado en la función biseccion6, en el archivo
lib-biseccion-6.c, listada en 1.5
Listing 1.5: lib-biseccion-6.c
1 # include < stdio .h >
2 # include < stdlib .h >
3 # include < math .h >
4 # include < tgmath .h >
5
24
$ ./bi
# i a b c fabs(b-c)
1 1.00000 1.50000 1.25000 0.25
2 1.00000 1.25000 1.12500 0.12
3 1.12500 1.25000 1.18750 0.062
4 1.12500 1.18750 1.15625 0.031
5 1.12500 1.15625 1.14062 0.016
6 1.12500 1.14062 1.13281 0.0078
7 1.13281 1.14062 1.13672 0.0039
8 1.13281 1.13672 1.13477 0.002
9 1.13281 1.13477 1.13379 0.00098
10 1.13379 1.13477 1.13428 0.00049
11 1.13428 1.13477 1.13452 0.00024
12 1.13452 1.13477 1.13464 0.00012
13 1.13464 1.13477 1.13470 6.1e-05
# Raiz=1.134705 f(raiz)=-0.000201099
$
Figure 1.9: Salida del programa biseccion-3.c
6 float b i s e c c i o n 6
7 ( float a , float b , float (* f ) ( float ) , int i m p r i m a t u r)
8 {
9 float c ;
10 int i =0 , imax =100;
11 float e p s i l o n =1.e -4;
12 // existe la raiz en el i n t e r v a l o
13 if ( i m p r i m a t u r ==1) f p r i n t f( stderr , "# i a b c
fabs (b - c ) \ n ") ;
14
15 if ( c o p y s i g n (1.0 ,(*f ) ( a ) ) * c o p y s i g n (1.0 ,(*f ) ( b ) ) >0)
16 { f p r i n t f( stderr , "# No hay raiz en el i n t e r v a l o\ n ") ;
17 return 0;}
18 c =( a + b ) /2.;
19 while ( fabs (b - c ) > e p s i l o n && i < imax )
20 {
21 if ( c o p y s i g n (1.0 ,(*f ) ( b ) ) * c o p y s i g n (1.0 ,(*f ) ( c ) ) <0)
22 a=c;
23 else
24 b=c;
25
26 c =( a + b ) /2.;
27 i = i +1;
28 if ( i m p r i m a t u r ==1) f p r i n t f( stderr , "%4 d %9.5 f %9.5 f %9.5 f %9.2 g \ n " ,i ,a ,b ,c ,
fabs (b - c ) ) ;
29 }
30 return c ;
31 }
A-cursos/cursoMNu/raı́[Link] - August 22, 2023 25
A efectos de mostrar que cada algoritmo se puede desarrollar de muchas maneras diferentes,
presentamos aquı́ en una una versión libre, ajustada a nuestra notación, la función zbrac
del libro Numerical Recipies de Press et al. Se recomienda al lector usar la implementación
original de los autores.
14 int i =0;
15 float a ,b ,c , e p s i l o n =1 e -5;
16 float f , fc ,r , dx ;
17
18 a =1.;
19 b =2.;
20
21 // C a l c u l a la ff f ( x ) vs . x
22 // para e x p l o r a r g r a f i c a m e n t e
23
30 fc = ff ( b ) ;
31 f = ff ( a ) ;
32
33 if ( fc *f >0)
34 printf (" No hay raiz en el i n t e r v a l o \ n ") ;
35
36 // Se ordena la d i r e c c i o n de b u s q u e d a
37 if (f <0)
38 { r=a;
39 dx =b - a ;}
40 else
41 { r=b;
42 dx =b - a ;}
43
44 // B i s e c c i o n
45 do
46 {
47 dx = dx /2.;
48 c = r + dx ;
26
49 fc = ff ( c ) ;
50 if ( fc <0) r = c ; // m a n t i e n e a c o t a d a la raiz
51 i ++;
52 f p r i n t f( stderr , "%2 d %1.5 f %1.2 g \ n " ,i ,r , fabs ( dx ) ) ;
53 }
54 while ( fabs ( dx ) > e p s i l o n || i < MAX ) ;
55
58 }
59
60 float ff ( float x )
61 {
62 return pow (x ,6.) -x -1.;
63 }
Esta implementación difiere de las anteriores en que primero se determina (lı́neas 37 − 42)
cual de los extremos del intervalo corresponde a la función con valor negativo y toma este
valor, que se denomina r en el programa, como punto de referencia. La longitud del intervalo
es dx, y el valor medio del intervalo se calcula sumando dx/2. al valor de la referencia dx.
El el algoritmo de bisección se desarrolla en las lı́neas 45 − 54. El listado siguiente muestra
los primeros 10 valores de la salida
$ head dat
1 1.00000 0.5
2 1.00000 0.25
3 1.12500 0.12
4 1.12500 0.062
5 1.12500 0.031
6 1.12500 0.016
7 1.13281 0.0078
8 1.13281 0.0039
9 1.13281 0.002
10 1.13379 0.00098
$
g(k) = 0 (1.42)
80
”[Link]”
70
60
50
40
f (c)
30
20
10
0
-10
0 1 2 3 4 5 6 7 8 9 10
c
Figure 1.10: La función f (k) vs. k.
m g t vt ǫ k
2
kg m /seg seg m/seg 1 kg/seg
5 10 9 10 1 × 10−6 4.99938
17 int i =0;
28
18 float a ,b , k ;
19 // C a l c u l a la ff f ( x ) vs . x
20 // para e x p l o r a r g r a f i c a m e n t e
21 // for ( k =0.; k <=10.; k = k +0.1)
22 // printf ("% f % f \ n " ,k , ff ( k ) ) ;
23 // return ;
24
25 // i n t e r v a l o de b u s q u e d a
26 a =0.;
27 b =6.;
28
29 k = b i s e c c i o n (a ,b , ff ,1) ;
30
31 printf (" Raiz =% f f ( raiz ) =% g \ n " ,k , ff ( k ) ) ;
32 return 0;
33 }
34 float ff ( float k )
35 {
36 float v ,t ,m , g ;
37
38 g =10.; // a c e l e r a c i o n de la garvedad , m / s
39 t =9.; // tiempo final , s
40 m =5.; // mass , kg
41 v =10.; // v e l o c i d a d final , m / s
42
El listado siguiente muestra los resultados de las últimas iteraciones antes de alcanzar la
convergencia de donde se obtiene que, dentro de la precisión deseada k ∼ 4.99938:
$ ./bi
$ i a b c fabs(b-c)
1 3.00000 6.00000 4.50000 1.5
2 4.50000 6.00000 5.25000 0.75
3 4.50000 5.25000 4.87500 0.38
4 4.87500 5.25000 5.06250 0.19
5 4.87500 5.06250 4.96875 0.094
6 4.96875 5.06250 5.01562 0.047
7 4.96875 5.01562 4.99219 0.023
8 4.99219 5.01562 5.00391 0.012
9 4.99219 5.00391 4.99805 0.0059
10 4.99805 5.00391 5.00098 0.0029
11 4.99805 5.00098 4.99951 0.0015
12 4.99805 4.99951 4.99878 0.00073
13 4.99878 4.99951 4.99915 0.00037
14 4.99915 4.99951 4.99933 0.00018
15 4.99933 4.99951 4.99942 9.2e-05
Raiz=4.999420 f(raiz)=-7.58616e-05
5.3
”[Link]”
5.2
5.1
c 4.9
4.8
4.7
4.6
4.5
0 5 10 15 20 25
iteracion
1.9.1 Funciones
El script [Link] mostrado en el listado 1.8 es un ejemplo muy pequeño y simple
de la estructura de un programa en Python.
4 # =================================
5 # D e f i n i c i o n de l a f u n c i o n
6 def fun1 (x):
7 return x∗∗3−5∗x−9
8
9 # =================================
10 # Programa p r i n c i p a l
11 # Entrada de d a t o s
12 a=1
13 b=2
14
15 # Impresion
16 rango = [Link] (a, b, 5)
17 print (rango )
18 print (fun1 (rango ))
✝ ✆
El script tiene tres partes, aunque sin ninguna discontinuidad entre ellas, salvo la barra
horizontal que hemos incluido como comentario para resaltar lo dicho. En la primera usual-
mente se importan los módulos con los que se quiere trabajar. Recordemos que los módulos
son archivos terminados en .py que contienen colecciones de código relacionado, funciones,
clases, variables, etc. Volveremos a ello en seguida. En la segunda usualmente se definen
varias funciones que luego usará el programa principal. En este script se han definido una
función de Python fun1 que en este caso implementa la función matemática
y = f (x) = x3 − 5x − 9 (1.44)
Para cada valor del argumento x calculará el valor de la función y. En seguida, después de
graficar esta función, obtendremos alguna de sus raı́ces.
A-cursos/cursoMNu/raı́[Link] - August 22, 2023 31
En la tercera parte del script, que hemos denominado el programa principal, se programa
la tarea que se requiere llevar a cabo. Se hace la entrada de datos y se ejecuta la tarea y si
es necesario se hace el posprocesamiento. En nuestro caso se ha establecido los datos dando
valores a las variables a y b, se hace uso de la función linspace del módulo numpy para crear
un rango de valores entre a y b, se imprime estos valores y se calcula e imprime la imágen
de estos valores a través de la función fun1
La ejecución del programa resulta en la siguiente salida 1.12
python [Link]
[1. 1.25 1.5 1.75 2. ]
[-13. -13.296875 -13.125 -12.390625 -11. ]
Figure 1.12: Salida del programa [Link]
9 k c o e f i c i e n t e de f r i c c i o n
10 t ti e m p o
11 v velocidad ini cial
12 m masa
13 g a c e l e r a c i o n de l a g r a v e d a d ”””
14
15 return (g∗m/k)∗(1−[Link](−k∗t/m))−v
16
17
El programa [Link] que se lista más adelante es igual al programa en sus efectos al
[Link] salvo que ya no definimos en él a la función fun1 ni ninguna otra.
5 # =================================
6 # Programa p r i n c i p a l
7 # Entrada de d a t o s
8 a=1
9 b=2
10
11 # Impresion
12 rango = [Link] (a, b, 5)
13 print (rango )
14 print (f.fun1 (rango ))
✝ ✆
La salida del programa es la siguiente ¡Ahora atención! La salida contiene la que pretendemos
A-cursos/cursoMNu/raı́[Link] - August 22, 2023 33
python [Link]
91
-0.6879132700050654
[1. 1.25 1.5 1.75 2. ]
[-13. -13.296875 -13.125 -12.390625 -11. ]
Figure 1.13: Salida de [Link]
17 # Programa p r i n c i p a l
18 # Se l l a m a a e j e c u c i o n l a s f u n c i o n e s d e f i n i d a s
19 # E s t e programa s e e j e c u t a r a como programa autonomo .
20 # Sus f u n c i o n e s ta m b i e n pueden s e r l l a m a d a s d e s d e o t r o
programa
21
Ahora, antes de proseguir, nos detengamos todavı́a en nuestro nuevo módulo [Link].
Es recomendable (Langtangen 2016, [? ]) verificar que las funciones programadas funcio-
nen correctamente. La forma más obvia de hacerlo es comparar sus resultados con los que
podemos calcular a mano o con una calculadora. Python provee varios medios para facili-
tar la prueba de un código. Uno de ellos es la denominada prueba afirmativa, edecuada
para hacer una comprobación de unidad ([Link]
#unit-tests-vs-integration-tests). Básicamente en esta prueba comparamos el resul-
tado de nuestro script con tres resultados correctos que hemos calculado por algún otro
medio. Por cada función definida podemos hacer una función de prueba. Para el caso de la
función fun1 en el programa [Link], la función test_fun1() hace la comparación
entre la salida de la función para un grupo de datos especificado con los resultados esperados
calculados a mano.
En la función test_fun1() se crea un arreglo, con tres valores de entrada, datos y se crea
otro arreglo con los resultados de aplicar la función a esos datos. En un tercer arreglo se
almacena los valores calculados manualmente, con calculadora, con symolab [Link]
[Link]/ u otro recurso online confiable, a partir de los datos. Luego se calcula el valor
absoluto de la diferencia entre unos y otros y de estas diferencias se toma el valor máximo
y se asigna a la variable exito. Esta es una variable boleana que puede tomar valor True o
False Si la variable exito resulte falsa, la sentencia assert exito interrumpirá la ejecución
del programa. En caso contrario no hará nada. El ejemplo mostrado, sólo demostrativo de
la estructura de la función de prueba es muy sencillo. Por lo general nuestras funciones serán
más complicadas y se podrán progamar de distintas maneras. No obstante, los resultados
deberı́a ser los mismos. Una función de prueba como la mostrada ayudarı́a a comprobar si
las modificaciones no alteran los resultados.
Con estos arreglos nuestro módulo funciones queda
4 # d e f i n i c i o n de f u n c i o n e s
5
12 # B l o c k de p r u e b a
13
25
37
38 # Programa p r i n c i p a l
39 # Si se llama a ejecucion e l s c r i p t
40 # s e e j e c u t a r a como programa autonomo .
41 # S i l a s f u n c i o n e s no pasan l a p r u e b a l a
42 # ejecucion se interrumpe
43 # S i s e i m p o r t a no e j e c u t a e l programa p r i n c i p a l
44 #
45 if name == " m a i n ":
46 test fun1 ()
47 test fun2 ()
48 print ("Prueba pasada con exito ")
49 print ("fun1 ", fun1(−10))
50 print ("fun2 ", fun2 (0))
51 print ("fun2 ", fun2 ([Link] (5)))
52 print ("fun2 ", fun2(−[Link] (5)))
✝ ✆
6 # Dato : i n t e r v a l o de c a l c u l o
7 a=1
8 b=10
9 # Crea un ra n g o de v a l o r e s de x y de y
10 x = np. linspace(a, b, 1000) # a b s c i s a s d i s c r e t a s
11 y = f.fun1 (x) # coordenadas d i s c r e t a s
12 # P l o t e o s i m p l e de l o s d a t o s
13 [Link] (x,y)
14 [Link] ()
✝ ✆
El archivo [Link] listado en 1.14 muestra una scrit mejorado para facilitar
y adornar el ploteo de funciones:
7 # I n t e r v a l o de c a l c u l o
8 a=−5
9 b=5
10 # Crea un ra n g o de v a l o r e s de x y de y
11 x = np. linspace(a, b, 50) # a b s c i s a s d i s c r e t a s
12 y = f.fun1 (x) # coordenadas d i s c r e t a s
13
14 # P l o t e o d e c o r a d o de l o s d a t o s
15 plt. xlabel ( ' x ' )
16 plt. ylabel ( ' y ' )
17 [Link] ( ' fun1 ' )
18 plt. axhline(y=0, c="blue ")
19 [Link] (x,y, '−ob ' , label ="f(x)=x∗∗3−5∗x−9")
20 plt. legend ()
21 plt. savefig( ' fig−fun1 .eps ' )
22 [Link] ()
A-cursos/cursoMNu/raı́[Link] - August 22, 2023 37
✝ ✆
El programa, además, crear un archivo con la figura 1.14 que se muestra a continuación.
fun1
100
f(x)=x**3-5*x-9
75
50
25
0
y
−25
−50
−75
−100
−4 −2 0 2 4
x
Por último, podemos crear una función para hacer este trabajo, es decir el ploteo cada vez
que necesitemos hacerlo. La función se incorporará al modulo [Link]. [Link]
se puede ejecutar de forma autónoma o se puede llamar como un módulo desde otro script.
La función se muestra en el listado 1.15. La ejecución autónoma produce la figura que se ve
en pantalla y el archivo [Link] que se ha incorporado aquı́ como figura 1.15.
29
fun1
1000
t=x^3 -5x-9
750
500
250
0
y
−250
−500
−750
−1000
Figure 1.15: Gráfica de la función fun1 creada con el programa [Link] y archivada
como [Link].
Notará que en módulo [Link] no hemos includo un bloque de prueba. Las pruebas
para una función como la presente son más complejas. Primero hay que determinar que se
quiere probar. El estudiante interesado puede acceder a la web para mayor información.
ipython
Python 3.9.12 (main, Apr 5 2022, 06:56:58)
Type ’copyright’, ’credits’ or ’license’ for more information
A-cursos/cursoMNu/raı́[Link] - August 22, 2023 39
La salida de este sentencia es la misma que la de anates, salvo que hemos cambiado los datos.
6 # Metodo de l a b i s e c c i o n
7 def biseccion (a,b,tol):
8 ””” Metodo de l a b i s e c c i o n ”””
9 paso = 1
10 condicion = True
11 while condicion :
12 c = (a + b)/2
13 print ( ' Iteracion %d, c = %0.6 f and f.fun1 (c) = %0.6 f '
% (paso , c, f.fun1 (c)))
14
17 else :
18 a = c
19
20 paso = paso + 1
21 condicion = abs(f.fun1 (c)) > tol
22
25 # Programa p r i n c i p a l
26 print ("#biseccion −[Link]:")
27 ”””
28 # Entrada de d a t o s
29 a = i n p u t ( ' I n t e r v a l o , e x tre m o a : ' )
30 b = i n p u t ( ' I n t e r v a l o , e x tre m o b : ' )
31 t o l = input ( ' Tolerancia : ')
32
33 # Convecion a f l o t a n t e s
34 a = float (a)
35 b = float (b)
36 tol = float ( tol )
37 ”””
38 a=1
39 b=5
40 tol =1.E−6
41
42
43 #Nota : R e d a c c i o n a l t e r n a t i v a
44 # a = f l o a t ( i n p u t ( ' I n t e r v a l o , e x tre m o a : ' ) )
45 # b = f l o a t ( i n p u t ( ' I n t e r v a l o , e x tre m o b : ' ) )
46 # t o l = f l o a t ( input ( ' Tolerancia : ') )
47
48
49 # Chequeo d e l i n t e r v a l o i n i c i a l
50 if f.fun1 (a) ∗ f.fun1 (b) > 0.0:
51 print ( ' El intervalo dado no contiene la raiz o contiene un
numero par de ellas . ' )
52 print ( ' Eliga un nuevo intervalo . ' )
53 else :
54 biseccion (a,b,tol)
✝ ✆
python [Link]
#[Link]:
Iteracion 1, c = 3.000000 and f.fun1(c) = 3.000000
Iteracion 2, c = 2.000000 and f.fun1(c) = -11.000000
Iteracion 3, c = 2.500000 and f.fun1(c) = -5.875000
Iteracion 4, c = 2.750000 and f.fun1(c) = -1.953125
Iteracion 5, c = 2.875000 and f.fun1(c) = 0.388672
Iteracion 6, c = 2.812500 and f.fun1(c) = -0.815186
Iteracion 7, c = 2.843750 and f.fun1(c) = -0.221588
Iteracion 8, c = 2.859375 and f.fun1(c) = 0.081448
Iteracion 9, c = 2.851562 and f.fun1(c) = -0.070592
Iteracion 10, c = 2.855469 and f.fun1(c) = 0.005297
Iteracion 11, c = 2.853516 and f.fun1(c) = -0.032680
Iteracion 12, c = 2.854492 and f.fun1(c) = -0.013700
Iteracion 13, c = 2.854980 and f.fun1(c) = -0.004204
Iteracion 14, c = 2.855225 and f.fun1(c) = 0.000546
Iteracion 15, c = 2.855103 and f.fun1(c) = -0.001829
Iteracion 16, c = 2.855164 and f.fun1(c) = -0.000641
Iteracion 17, c = 2.855194 and f.fun1(c) = -0.000048
Iteracion 18, c = 2.855209 and f.fun1(c) = 0.000249
Iteracion 19, c = 2.855202 and f.fun1(c) = 0.000101
Iteracion 20, c = 2.855198 and f.fun1(c) = 0.000027
Iteracion 21, c = 2.855196 and f.fun1(c) = -0.000011
Iteracion 22, c = 2.855197 and f.fun1(c) = 0.000008
Iteracion 23, c = 2.855196 and f.fun1(c) = -0.000001
Iteracion 24, c = 2.855197 and f.fun1(c) = 0.000003
Iteracion 25, c = 2.855197 and f.fun1(c) = 0.000001
Iteracion 26, c = 2.855197 and f.fun1(c) = -0.000000
La raiz es: 2.85519654
42
Este programa tiene el inconveniente que solo trabaja con la función fun1. Un pequeño
cambio en la entrada de datos de la función biseccion habilita la entrada del nombre de la
función como su argumento. La nueva versión del programa, ahora listado en 1.17 muestra
este cambio. También se ha usado el módulo [Link], se ha realizado una función
de prueba test_biseccion.py y se ha redactado como módulo, de manera que ahora este
script se puede ejecutar en forma autónoma o se puede llamar desde otro script.
6 # Metodo de l a b i s e c c i o n
7 def biseccion (ff ,a,b,tol):
8 ””” Metodo de l a b i s e c c i o n ”””
9 paso = 1
10 condicion = True
11 while condicion :
12 c = (a + b)/2
13 #p r i n t ( ' I t e r a c i o n %d , c = %0.6 f and f f ( c ) = %0.6 f ' % (
paso , c , f f ( c ) ) )
14
20 paso = paso + 1
21 #c o n d i c i o n = a b s ( a−c )> t o l #a b s ( f f ( c ) ) > t o l
22 condicion = abs(ff(c)) > tol
23
37
A-cursos/cursoMNu/raı́[Link] - August 22, 2023 43
40 test biseccion ()
41 print ( biseccion (f.fun1 ,1,5,1. E−10))
42 print ( biseccion (f.fun2 ,−5,−0.9,1.E−10))
✝ ✆
44
f (xn )
xn+1 = xn − (1.50)
f ′ (xn )
El algoritmo consiste en tomar un punto x0 como estimación inicial para la raı́z. Prefer-
entemente este valor debe ser próximo a la raı́z. Se denomina semilla o valor de prueba.
Se aplica la fórmula 1.50 para obtener un valor mejorado x1 . Ahora sucesivamente se utiliza
el último valor de x para reiniciar el proceso iterativo.
La figura 1.16 esquematiza el procedimiento.
A-cursos/cursoMNu/raı́[Link] - August 22, 2023 45
g0 (x)
g1 (x)
∗
x3 x2 x1 x0
Algoritmo
3. Calcular
f (x0 )
x1 = x0 − (1.51)
f ′ (x0 )
5. Hacer x0 = x1
6. Volver al paso 2.
Obsérvese que no hace falta guardar todos los valores intermedios xn . Solo hace falta tener
registro de dos de ellos a los efectos de poder establecer la convergencia. No obstante, con
frecuencia, en las funciones y procedimientos de librerı́as matemáticas, como por ejemplo las
de Numerical Recipies ([13]), se guardan los valores de xi , f (xi ) en un arreglo para los fines
de impresión posterior, ya que la tarea de enviar un resultado a pantalla puede consumir
demasiado tiempo.
3. Es necesario conocer y calcular la derivada f ′ (x) en forma explı́cita. Esto puede ser
costoso computacionalmente o incluso imposible.
5 float ff ( float x ) ;
6 float dff ( float x ) ;
7
8 int main ()
9 {
10 // newton -1. c
11
12 // o b t i e n e una raiz de la f u n c i o n
13 // f ( x ) = x ^6 -x -1
14 // en el i n t e r v a l o [a - b ]=[1 -2]
15
16 int i =1;
17 float x0 =0. , x1 , x2 , fx1 , e p s i l o n =1 e -6 , sol = 1 . 1 3 4 7 2 4 1 3 8 4 0 1 5 2 L ;
18
19 x1 =2.;
20 while ( fabs ( x1 - x0 ) > e p s i l o n)
21 {
22 i = i +1;
23 x0 = x1 ;
24 x1 = x0 - ff ( x0 ) / dff ( x0 ) ;
25 printf (" % d % f % f \ n " , i , x1 , sol ) ;
26 }
27 return 0;
28 }
29 float ff ( float x )
30 {
31 return pow (x ,6.) -x -1.;
A-cursos/cursoMNu/raı́[Link] - August 22, 2023 47
32 }
33 float dff ( float x )
34 {
35 return 6.* pow (x ,5.) -1;
36 }
f (x)
x0 x2 x3 x1
•
Algoritmo simple
Algoritmo
2. Calcular
x1 − x0
x2 = x1 − f (x1 ) (1.57)
f (x1 ) − f (x0 )
4. Hacer x0 = x2
5. Volver al paso 2.
En este procedimiento se mantuvo fijo el punto x1 , f (x1 ), como se muestra en la figura 1.18
marcado con un punto negro. El otro extremo del intervalo, originalmente en x0 , se actualizó
A-cursos/cursoMNu/raı́[Link] - August 22, 2023 49
por x2 , x3 , etc. Dadas las caracterı́sticas de la función, la raı́z estuvo siempre en el interior
del intervalo de búsqueda. Veremos en seguida que este procedimiento no es siempre el más
conveniente.
Convergencia
11 fx1 =(* f ) ( x1 ) ;
12 fx0 =(* f ) ( x0 ) ;
13
Observe que el método converge algo más lento que el método de Newton. Se hubiera
podido mantener fijo el otro extremo, el punto x0 , para luego de obtenida la aproximación
x2 , actualizar el intervalo de búsqueda reemplazando x1 por x2 . Este procedimiento se
esquematiza en la figura 1.19. Puede observarse que en este caso que, dadas las caracterı́sticas
de la función, el intervalo de búsqueda no siempre encierra la raı́z buscada. Aparece como una
propiedad deseable que la raı́z se encontrara siempre contenida en el intervalo de búsqueda.
Esto asegurarı́a una convergencia monótona a la raı́z. Para ello basta elegir adecuadamente,
en cada paso, el nuevo extremo del dominio de búsqueda. Podemos usar para ello el mismo
algoritmo que en el método de la bisección. La combinación del método de la tangente con
una selección del intervalo de búsqueda que mantenga encerrada a la raı́z se denomina el
método de la Regula Falsi.
f (x)
x0 x2 x4 x3 x1
•
•
Figure 1.19: Esquema del proceso de solución con el algoritmo de falsa posición.
(a − b)
c = b + fb (1.59)
(fa − fb )
que no es otra cosa que la misma ecuación 1.56
El algoritmo es el siguiente
Algoritmo
5. Volver al paso 2.
6 float f u n c i o n( float x ) ;
7 float r e g u l a f a l s i 1 ( float x , float B , float (* f ) ( float ) , int i m p r i m a t u r )
;
8
9 int main ()
10 {
11 // regulafalsi -1. c
12 // o b t i e n e una raiz de la f u n c i o n
13 // f ( x ) = x ^6 - x -1
14 // en el i n t e r v a l o [a - b ]=[1 -2]
15
16
17 float a ,b , c ;
18 a =1.;
19 b =2.;
20
21 // C a l c u l a la ff f ( x ) vs . x
22 // para e x p l o r a r g r a f i c a m e n t e
23
28 c = r e g u l a f a l s i 1 (a ,b , funcion ,1) ;
29 printf (" Raiz =% f f ( raiz ) =% g \ n " ,c , f u n c i o n( c ) ) ;
30 return 0;
31 }
32
33 float f u n c i o n( float x )
34 {
35 return pow (x ,6.) -x -1.;
36 }
15 {a=c;
16 fa =(* f ) ( a ) ;
17 } else
18 {b=c;
19 fb =(* f ) ( b ) ;
20 }
21 i = i +1;
22 if ( i m p r i m a t u r ==1) f p r i n t f( stderr , "%4 d %9.5 f %9.5 f %9.5 f %9.2 g \ n " ,i ,a ,b ,c ,
fabs (b - c ) ) ;
23 }
24 while ( fabs ((* f ) ( c ) ) > e p s i l o n && i < MAX ) ;
25 return c ;
26 }
A efectos de comparación presentamos aquı́ una versión ajustada a nuestra notación y algo
simplificada de la implementación de Press et al., [13]. Se recomienda al lector usar la
implementación de los autores.
Se parte del intervalo inicial de búsqueda es [x0 , x1 ]. tal que f (x0 )f (x1 ) < 0. Se hace
a = min(f (x0 ), f (x1 ) y b = max(f (x0 ), f (x1 )), con lo que se consigue que en el nuevo
intervalo de búsqueda [a, b], f (a) sea siempre el valor negativo y f (b) el positivo. En cada
iteración se cambiará a o b por c, de manera que se mantenga ...
El método de la Posición Falsa o Regula Falsi, se caracteriza por mantener la raı́z acorralada
entre los lı́mites del intervalo de búsqueda.
Para implementarlo es conveniente usar la siguiente notación. Las coordenadas que definen
el intervalo, que fueron denominadas x0 y x1 será designadas ahora por xa o xb según el valor
que tome la función f () sea alto o bajo (mayor que cero o menor que cero)). Si xi , con i
igual a 1 o 0, es tal que f (xi ) > 0 , designaremos xa = xi y f (xa ) = fa . El otro valor será
designado con el subı́ndice b.
Con esta notación, el algoritmo representado por la ecuación 1.54 se puede escribir como
(xa − xb )
x = xb + fb (1.61)
(fa − fb )
Algoritmo
4. Calcular
(xa − xb )
x = xb + fb (1.62)
(fa − fb )
7. Volver al paso 4.
1 //
2 fb=funcion(x1);
3 fa=funcion(x2);
4 if(fb<0)
5 {
6 xb=x1;
7 xa=x2;
8 }
9 else
10 {
11 xb=x2;
12 xa=x1;
13 swap=fb;
14 fb=fa;
15 fa=swap;
16 }
A-cursos/cursoMNu/raı́[Link] - August 22, 2023 55
Ventajas y desventajas
Ventajas
Desventajas
Convergencia
f (x) = x6 − x − 1 f (x) = x6 − x − 1
1.5 2
a a
1.4 c 1.8 c
1.3 b 1.6 b
1.2 1.4
1.1 1.2
1 1
2 4 6 8 10 12 14 16 18 20 2 4 6 8 10 12 14 16 18 20
6 float f u n c i o n( float x ) ;
56
9 int main ()
10 {
11 // regulafalsi -1. c
12 // o b t i e n e una raiz de la f u n c i o n
13 // f ( x ) = x ^6 - x -1
14 // en el i n t e r v a l o [a - b ]=[1 -2]
15
16
17 float a ,b , c ;
18 a =1.;
19 b =2.;
20
21 // C a l c u l a la ff f ( x ) vs . x
22 // para e x p l o r a r g r a f i c a m e n t e
23
24 // for ( x =0.; x <= b ; x = x +0.1)
25 // printf ("% f % f \ n " ,x , ff ( x ) ) ;
26 // return ;
27
28 c = r e g u l a f a l s i 1 (a ,b , funcion ,1) ;
29 printf (" Raiz =% f f ( raiz ) =% g \ n " ,c , f u n c i o n( c ) ) ;
30 return 0;
31 }
32
33 float f u n c i o n( float x )
34 {
35 return pow (x ,6.) -x -1.;
36 }
20 {a=c;
21 fa =(* f ) ( a ) ;
22 } else
23 {b=c;
24 fb =(* f ) ( b ) ;
25 }
26 i = i +1;
27 if ( i m p r i m a t u r ==1) f p r i n t f( stderr , "%4 d %9.5 f %9.5 f %9.5 f %9.2 g \ n " ,i ,a ,b ,c ,
fabs (b - c ) ) ;
28 }
29 while ( fabs ((* f ) ( c ) ) > e p s i l o n && i < MAX ) ;
30 return c ;
31 }
./bi
# i a b c fabs(b-c)
1 1.01613 2.00000 1.01613 0.98
2 1.03067 2.00000 1.03067 0.97
3 1.04372 2.00000 1.04372 0.96
4 1.05535 2.00000 1.05535 0.94
...
48 1.13464 2.00000 1.13464 0.87
49 1.13465 2.00000 1.13465 0.87
50 1.13466 2.00000 1.13466 0.87
Raiz=1.134660 f(raiz)=-0.000662124
Es interesante notar cuan rápido converge cuando se intercambian los lı́mites de la búsqueda.
58
1. x = g1 (x) = x2 + x − a
2. x = g2 (x) = x/a
3. x = g3 (x) = 1/2(x + x/a)
Los problemas de punto fijo se pueden resolver por métodos iterativos de aproximaciones
sucesivas. En general un método de aproximaciones sucesivas es aquel que permite encon-
trar las solución por aplicación repetida del siguiente algoritmo
xn+1 = g(xn ) (1.64)
Se comienza calculando g(x0 ), donde x0 es un valor arbitrario pero preferentemente cercano
a la solución. Este valor se denomina usualmente semilla o valor de prueba. Se obtiene
x1 = g(x0 ). Luego se reemplaza x0 por x1 y se repite el cálculo. Se genera una secuencia
{xn }∞
n que bajo ciertas condiciones es convergente y conduce a encontrar la solución, es decir
el punto fijo.
Se puede demostrar10 (véase [6], [8]) que para una función g(x), continua en el intervalo [a, b],
diferenciable en (a, b), dada una semilla x0 , la aplicación de un proceso iterativo de aproxi-
maciones sucesivas como el indicado por la ecuación 1.64, conducirá a una serie convergente
si se cumple que en la cercanı́a del punto fijo es
Maxa≤x≤b |g ′(x)| < 1 (1.65)
x0 x1 x2 x3 x3 x2 x1 x0
Figure 1.21: Algoritmo iterativo de aproximaciones sucesivas a) 0 < g ′(α) < 1, convergente.
b) g ′(α) > 1, divergente
a) b)
y=x y=x
y = g(x) y = g(x)
x0 x2x3 x1 x3 x0 x1
Figure 1.22: Algoritmo iterativo de aproximaciones sucesivas a) −1 < g ′ (α) < 0, convergente.
b) g ′(α) < −1, divergente
x1 = y0 (1.70)
donde n es un ı́ndice que indica el número de iteraciones. El algoritmo puede darse por
convergido cuando
|xn+1 − xn | < ε (1.72)
o cuando
|xn+1 − xn |
<ε (1.73)
|xn |
1.12.2 Algoritmo
El algoritmo puede escribirse de la siguiente manera
Algoritmo
1. Se propone un valor de prueba x0
x1 = g(x0 ) (1.74)
4. Se hace x0 = x1
5. Se vuelve al paso 2
1.14.1 Problema 1
Las ecuaciones paramétricas del vuelo de un proyectil son:
x = vx0 t (1.78)
1
y = vy0 t − gt2 (1.79)
2
B) Para el caso de resistencia lineal:
m k
x= vx0 (1 − e− m t ) (1.80)
k
mgt m mg k
y=− + (vy0 + )(1 − e− m t ) (1.81)
k k k
C) Para el caso de resistencia cuadrática:
1
x= (ln(1 − kvx0 t) (1.82)
kvx0
g 1 gt2 gt
y = (vy0 − ) ln(1 − kvx0 t) − − (1.83)
2kvx0 kvx0 4 2kvx0
Datos:
m = 1kg
g = 9.81ms−2
v0 = 9.81ms−1 , velocidad inicial
θ = 20o
k = 0.1m−1
Consigna:
• Utilice los dos canales disponibles en C, stderr y stdout, para imprimir la tabla y los
alcances por vı́as diferentes. Use el redireccionamiento de la shell para enviar la tabla
al archivo [Link] y el alcance al archivo [Link].
62
Resolución
7 int main ()
8 {
9 // biseccion - parcial -1 -2014 -1.c
10 // a l c a n c e de un p r o y e c t i l
11 // r e s i s t e n c i a c u a d r a t i c a
12 // Parker , 1997 , W a r b u r t o n et al . , 2010
13
14 int i =0;
15 float a ,b ,c ,R , e p s i l o n =1e -6;
16
17 a =1.;
18 b =20.;
19
20 // C a l c u l a la ff f ( c ) vs . c para g r a f i c a r
21 // for ( c =0.; c <= b ; c = c +0.1)
22 // printf ("% f % f \ n " ,c , ff ( c ) ) ;
23 // return ;
24
25 // existe la raiz en el i n t e r v a l o
26 if ( ff ( a ) * ff ( b ) >0)
27 printf (" No hay raiz en el i n t e r v a l o \ n ") ;
28
29 c =( a + b ) /2.;
30 while ( fabs (b - c ) > e p s i l o n)
31 {
32 if ( ff ( b ) * ff ( c ) < 0. )
33 a=c;
34 else
35 b=c;
36
37 c =( a + b ) /2.;
38 i = i +1;
39 printf ("%2 d , %1.5 f %1.2 g \ n " ,i ,c , fabs (b - c ) ) ;
40 }
41 return 0;
42
43 }
44
45 float ff ( float R )
46 {
47 float v , vx0 , vy0 ,g , k ;
48 v =9.81; // modulo de la v e l o c i d a d i n i c i a l
49 k =0.1; // c o e f i c i e n t e de a r r a s t r e
50 g =9.81; // a c e l e r a c i o n de la g r a v e d a d
51 theta =20.:
52 vx0 = v * cos ( theta * 3 . 1 4 1 5 / 1 8 0 . ) ;
A-cursos/cursoMNu/raı́[Link] - August 22, 2023 63
1.14.2 Problema 2
El alcance R de un proyectil cuando se considera resistencia del aire cuadrática, ha sido
aproximado por Parker (1977) y recientemente por Warburton et al. (2010), para el caso
especial en que vx0 >> vy0 , es decir trayectorias de ángulo bajo, por la siguiente ecuación
trascendental
g R g 2kR
vy0 + − e − 1 =0 (1.84)
2kvx0 vx0 4(kvx0 )2
Datos:
Use mismos coeficientes que en el problema anterior.
Resolución
3 float ff ( float R ) ;
4 int main ()
5 {
6 // biseccion - parcial -1 -2014 -2b . c
7
8 int i =0;
9 float a ,b ,c , R ;
10
11 a =1.;
12 b =20.;
13
14 // C a l c u l a la ff f ( c ) vs . c para g r a f i c a r
15 // for ( c =0.; c <= b ; c = c +0.1)
16 // printf ("% f % f \ n " ,c , ff ( c ) ) ;
17
18 // return ;
19 c = b i s e c c i o n 7(a ,b , ff ,1) ;
20 printf (" Raiz =% f f ( raiz ) =% g \ n " ,c , ff ( c ) ) ;
21 return 0;
22 }
23
24 float ff ( float R )
64
25 {
26 float v , vx0 , vy0 ,g ,k , theta ;
27 v =9.81;
28 k =0.1;
29 g =9.81;
30 theta =20;
31 vx0 = v * cos ( theta * 3 . 1 4 1 5 / 1 8 0 . ) ;
32 vy0 = v * sin ( theta * 3 . 1 4 1 5 / 1 8 0 . ) ;
33 return ( vy0 + g /(2.* k * vx0 ) ) *( R / vx0 ) -( g /(4.* k * k * vx0 * vx0 ) ) *( exp (2.* k * R )
-1.) ;
34 }
8 // existe la raiz en el i n t e r v a l o
9 if ( i m p r i m a t u r ==1) f p r i n t f( stderr , "# i a b c
fabs (b - c ) \ n ") ;
10
11 if ((* f ) ( a ) * (* f ) ( b ) >0)
12 { f p r i n t f( stderr , "# No hay raiz en el i n t e r v a l o\ n ") ;
13 return 0;}
14
15 fb =(* f ) ( b ) ;
16 fa =(* f ) ( a ) ;
17 c =( a + b ) /2.;
18 do
19 {
20 fc =(* f ) ( c ) ;
21
22 if ( fb * fc < 0. )
23 {a=c;
24 fa = fc ;
25 }
26 else
27 {b=c;
28 fb = fc ;}
29
30 c =( a + b ) /2.;
31 i = i +1;
32 if ( i m p r i m a t u r ==1) f p r i n t f( stderr , "%4 d %9.5 f %9.5 f %9.5 f %9.2 g \ n " ,i ,a ,b ,c ,
fabs (b - c ) ) ;
33 }
34 while ( fabs (b - c ) > e p s i l o n) ;
35 return c ;
36 }
A-cursos/cursoMNu/raı́[Link] - August 22, 2023 65
1.14.3 Problema 3
Obtenga la raı́z de sen(x) = 0 mediante el método de Newton Raphson y como problema de
punto fijo (aproximaciones sucesivas). Ayuda: El algoritmo de Newton Raphson es
f (xn )
xn+1 = xn − (1.85)
f ′ (xn )
1.14.4 Problema 4
Un objeto cae verticalmente en aire sujeto a la fuerza de la gravedad y a la fuerza viscosa.
La altura del objeto, h, en función del tiempo, t, está dada por
mg m2 g
h(t) = h0 − t + 2 (1 − e−kt/m ) (1.86)
k k
Datos g = 9.8m/s2 , m = 0.1kg, h0 = 100m, k = 1.5kgs/m.
Calcule cuánto tarda el cuerpo en caer al suelo con una exactitud de 0.01s.
Elija usted el método de resolución.
66
#include "lib-raices.h"
que reemplaza a los prototipos de la funciones individuales que incluı́amos antes, ya que el
archivo lib-raices.h hará la inclusión de todos los prototipos de todas las funciones. Eso
es suficiente para hacer accesibles al programa todas las funciones del archivo lib-raices.c
El programa debe compilarse ahora como
El archivo nombre.c, como siempre, debe estar en el directorio de trabajo asi como también
los dos nuevos archivos, lib-raices.c y lib-raices.h que componen nuestra biblioteca12.
El listado del archivo de encabezados lib-raices.h, listado 1.28, sirve como manual de uso
de las funciones de la biblioteca personal. Cada prototipo indica el retorno de la función y
los datos o argumentos que requiere y su tipo:
Listing 1.28: lib-raices.h
1 # include < stdio .h >
2 # include < stdlib .h >
3 # include < math .h >
4 # include < tgmath .h >
5
6 # define MAX 500
7
C dispone de herramientas para hacer de estos archivos una verdadera biblioteca (library
en inglés), de tipo estática o dinámica. Las bibliotecas estáticas o dinámicas precompilan
las funciones del archivo y las ponen a disposición para ser usadas en distintas etapas del
ensamblado de un programa o en la ejecución del mismo.
Las bibliotecas estáticas, cuyos archivos se distinguen con la extensión .a, consisten en un
archivo objeto que se ensambla con el objeto resultante del programa fuente en la etapa de
11
El término en inglés es library, que significa biblioteca. Por asociación sonora con el término español
librerı́a, con frecuente, y es probable que lo encuentre ası́ en este mismo libro, usamos este vocablo para
referirnos a una biblioteca.
12
Estos archivos, como se describe más abajo, nos son técnicamente bibliotecas de C, no obstante cumplen
la misma función y pueden transformarse en ellas.
A-cursos/cursoMNu/raı́[Link] - August 22, 2023 67
compilación para producir un único ejecutable o binario. Las funciones usadas de la librerı́a
pasan a formar parte del binario ası́ creado. Los ejecutables son algo más grandes que los
de los programas ensamblados con librerı́as dinámicas.
Los objetos de las bibliotecas dinámicas, cuyos archivos se distinguen con la extensión .so,
se unen al programa del usuario recién en la etapa de ejecución. Se denominan también
bibliotecas compartidas por que existe una única versión objeto de la misma, reutilizable
por diferentes programas a la vez. Las bibliotecas dinámicas se vinculan en dos etapas. En
una primera etapa, durante la compilación, el ensamblador hace diversas verificaciones, en
particular que las funciones que el programa usa estén en el programa o en la biblioteca. Los
objetos de funciones de librerı́a no se ensamblan al programa. En una segunda etapa, durante
la ejecución un cargador sube estos objetos a memoria y los hace disponibles al programa
ejecutable. Tienen la ventaja de que existe un único objeto que puede ser compartido por
diversos programas.
Existen varias otras librerı́as para C, C++, un listado puede encontrarse en la Wikipedia,
[2]. No debe perderse de vista que existen importantes librerı́as para álgebra numérica en
otros lenguajes, en particular Fortran. Una fuente importante de información puede hallarse
en la Wikipedia, [2]. Las librerı́as comerciales más conocidas son HLS, antes Hardwell,
[3], NAG, [10], IMSL, [1] que disponen versiones para los lenguajes de interés cientı́fico
principales: fortran, C, Java, Python, etc..
68
• Newton: gsl_root_fdfsolver_newton
• Secante: gsl_root_fdfsolver_secant
• Steffenson: gsl_root_fdfsolver_steffenson
• Brent: gsl_root_fsolver_brent
• Bisección: gsl_root_fsolver_bisection
El uso de esta librerı́a requiere conocimientos algo más avanzados de C que los utilizados
hasta aquı́. En particular el uso de estructuras y punteros
Para compilar se necesita el archivo de encabezados demo_fn.h que se puede bajar del sitio
web de GSL:
Listing 1.29: demofn.h
1 // d e m o _ f n. h
2 struct q u a d r a t i c _ p a r a m s
3 {
4 double a , b , c ;
5 };
6
11 return ( a * x + b ) * x + c ;
12 }
13
A-cursos/cursoMNu/raı́[Link] - August 22, 2023 69
31 double a = p - >a ;
32 double b = p - >b ;
33 double c = p - >c ;
34
35 *y = (a * x + b) * x + c;
36 * dy = 2.0 * a * x + b ;
37 }
6 # i n c l u d e " d e m o _ f n. h "
7 # i n c l u d e " d e m o _ f n. c "
8
9 int main ( void )
10 {
11 int status ;
12 int iter = 0 , m a x _ i t e r = 100;
13 const g s l _ r o o t _ f s o l v e r _ t y p e * T ;
14 gsl_root_fsolver *s;
15 double r = 0 , r _ e x p e c t e d = sqrt (5.0) ;
16 double x_lo = 0.0 , x_hi = 5.0;
17 gsl_function F;
18 struct q u a d r a t i c _ p a r a m s params = {1.0 , 0.0 , -5.0};
19
20 F . f u n c t i o n = & q u a d r a t i c;
21 F . params = & params ;
22
23 T = gsl_root_fsolver_brent ;
24 s = gsl_root_fsolver_alloc (T);
25 g s l _ r o o t _ f s o l v e r _ s e t (s , &F , x_lo , x_hi ) ;
26
34 do
35 {
36 iter ++;
37 status = g s l _ r o o t _ f s o l v e r _ i t e r a t e ( s ) ;
38 r = gsl_root_fsolver_root (s);
39 x_lo = g s l _ r o o t _ f s o l v e r _ x _ l o w e r ( s ) ;
40 x_hi = g s l _ r o o t _ f s o l v e r _ x _ u p p e r ( s ) ;
41 status = g s l _ r o o t _ t e s t _ i n t e r v a l ( x_lo , x_hi ,
42 0 , 0.001) ;
43
44 if ( status == G S L _ S U C C E S S )
45 printf (" C o n v e r g e d :\ n ") ;
46
6 # i n c l u d e " d e m o _ f n. h "
7 # i n c l u d e " d e m o _ f n. c "
8
26 g s l _ r o o t _ f d f s o l v e r _ s e t (s , & FDF , x ) ;
27
28 printf (" using % s method \ n " ,
29 gsl_root_fdfsolver_name (s));
30
31 printf ("% -5 s %10 s %10 s %10 s \ n " ,
32 " iter " , " root " , " err " , " err ( est ) ") ;
33 do
34 {
35 iter ++;
36 status = g s l _ r o o t _ f d f s o l v e r _ i t e r a t e ( s ) ;
37 x0 = x ;
38 x = gsl_root_fdfsolver_root (s);
39 status = g s l _ r o o t _ t e s t _ d e l t a (x , x0 , 0 , 1e -3) ;
40
41 if ( status == G S L _ S U C C E S S )
42 printf (" C o n v e r g e d :\ n ") ;
43
44 printf ("%5 d %10.7 f %+10.7 f %10.7 f \ n " ,
45 iter , x , x - r_expected , x - x0 ) ;
46 }
47 while ( status == G S L _ C O N T I N U E && iter < m a x _ i t e r) ;
48
49 gsl_root_fdfsolver_free (s);
50 return status ;
51 }
La librerı́a GSL utiliza para cálculos algebraicos las librerı́a cblas. Esta es una versión en
C de la librerı́a BLAS (Basic Linear Algebra Subprograms). Esta librerı́a, originalmente
en fortran pero ahora en varios otros lenguajes, especifica o estandariza operaciones básicas
de álgebra lineal como ser la multiplicación de vectores, matrices y vectores etc. Es un
estándar pero tiene versiones de referencia desarrolladas mantenidas por [Link]. Por
supuesto existen versiones comerciales de estas librerı́as optimizadas para computadoras
de alta perfomance. Numerosos sistemas de computación numérica mantienen las mismas
interfaces que hacen compatible el uso de sus funciones: entre ellas Armadillo, LAPACK,
LINPACK, GNU Octave, Mathematica, MATLAB, NumPy, R, y Julia.
Si las librerı́as gsl y cblas están bien instaladas en un sistema Linux, se puede puede
compilar con el siguiente comando
Bibliography
[1] IMSL Numerical Libraries. URL [Link]
[4] F. S. Acton. Numerical Methods That Works. Harper and Row, 1970.
[5] K. E. Atkinson. Elementary Numerical Analysis. John Wiley and Sons, 1993.
[6] Kendall E. Atkinson. An Introduction to Numerical Analysis. John Wiley and Sons,
second edition, 1989.
[7] R. L. Burden and J. Douglas Faires. Análisis Numérico. Thomson Learning, 1989.
[8] Mc. Cracken and Dorn. Métodos Numéricos y Programación en Fortran. Limusa, 1980.
[9] M. Galassi et al. Gnu Scientific Library Reference Manual, 2018. URL [Link]
[Link]/software/gsl/.
[14] G. G. Stokes. On the effect of internal friction of fluids on the motion of pendulums.
Transactions of the Cambridge Philosophical Society, 9, Part II:8–106, 1851.
[16] Paul Whiters. Some cool motion sensor stuff. URL [Link]
v=KyktvC7w7Js.