09.05.2013 Views

Programación en Pascal

Programación en Pascal

Programación en Pascal

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>Programación</strong> <strong>en</strong> <strong>Pascal</strong><br />

(Geometría Computacional, 3 er curso de I.T. Topografía)<br />

Un programa <strong>en</strong> <strong>Pascal</strong><br />

El primer programa <strong>en</strong> <strong>Pascal</strong> que vamos a realizar es escribir <strong>en</strong> pantalla la frase "Hola<br />

Mundo". Veremos como pasar un simple algoritmo <strong>en</strong> seudocódigo a un programa <strong>en</strong> <strong>Pascal</strong>.<br />

algoritmo Dihola<br />

inicio<br />

ESCRIBIR "Hola Mundo"<br />

fin<br />

Tipos y estructuras de datos<br />

program Dihola;<br />

begin<br />

writeln ('Hola Mundo');<br />

<strong>en</strong>d.<br />

Un tipo de dato repres<strong>en</strong>ta un conjunto de valores. Si una variable, constante o expresión son<br />

de un tipo determinado, esto significa que sólo pued<strong>en</strong> tomar valores de ese conjunto.<br />

En <strong>Pascal</strong> exist<strong>en</strong> una serie de tipos básicos o primitivos proporcionados por el l<strong>en</strong>guaje:<br />

boolean, char, integer y real. El usuario también puede definir sus propios tipos <strong>en</strong> una sección<br />

TYPE.<br />

Declaraciones de tipo<br />

Sirv<strong>en</strong> para declarar nuevos tipos, dándoles un nombre. Ej:<br />

TYPE<br />

VAR<br />

TANIMAL = string [30];<br />

animal : TANIMAL;<br />

S<strong>en</strong>t<strong>en</strong>cias condicionales<br />

El flujo del programa no siempre es continuo sino que puede dep<strong>en</strong>der de ciertas condiciones,<br />

hablamos de las s<strong>en</strong>t<strong>en</strong>cias condicionales. En seudocódigo estas s<strong>en</strong>t<strong>en</strong>cias se escribían con<br />

SI-ENTONCES-SINO.<br />

Supongamos que queremos calcular el punto de intersección <strong>en</strong>tre dos rectas.<br />

La ecuación de la primera recta es: y=m1x+c1 y la segunda y=m2x+c2. Podemos resolver el<br />

problema mediante un simple sistema de dos ecuaciones con dos incognitas de la sigui<strong>en</strong>te<br />

manera:<br />

1


s<strong>en</strong>t<strong>en</strong>cia<br />

condicional<br />

{y=m1x+c1; -> x=(c1-c2)/(m2-m1)<br />

y=m2x+c2; -> y=m1x+c1<br />

}<br />

program Intersec_Rectas;<br />

var x,y,m1,m2,c1,c2:real;<br />

begin<br />

writeln ('Datos de la primera recta');<br />

write ('m1= '); readln(m1);<br />

write ('c1= '); readln(c1);<br />

writeln ('Datos de la segunda recta');<br />

write ('m2= '); readln(m2);<br />

write ('c2= '); readln(c2);<br />

lectura de<br />

datos<br />

if abs(m2-m1) < 0.00001 (*rectas paralelas*)<br />

th<strong>en</strong> writeln ('Rectas Paralelas, no intersectan')<br />

else begin<br />

x:=(c1-c2)/(m2-m1);<br />

y:=m1*x+c1;<br />

writeln ('Punto de intersección: (',x:4:2,',',y:4:2,')');<br />

<strong>en</strong>d;<br />

readln;<br />

<strong>en</strong>d.<br />

com<strong>en</strong>tarios<br />

declaración de<br />

variables<br />

cálculos y<br />

salida<br />

formateada<br />

Bucles<br />

En muchas ocasiones los programas repit<strong>en</strong> una serie de s<strong>en</strong>t<strong>en</strong>cias un número determinado o<br />

indeterminado de veces. Por ejemplo si deseamos leer por teclado los n vértices de un<br />

polígono, bastaría con escribir una s<strong>en</strong>t<strong>en</strong>cia de lectura g<strong>en</strong>érica, (por ejemplo que lea el<br />

vértice número i) y repetirla un total de n veces. Si recordamos, <strong>en</strong> seudocódigo exist<strong>en</strong> los<br />

bucles PARA-REPETIR, MIENTRAS y REPETIR-HASTA. Veremos sus modificaciones a<br />

<strong>Pascal</strong>.<br />

S<strong>en</strong>t<strong>en</strong>cia while (Mi<strong>en</strong>tras)<br />

• Sintaxis:<br />

while expresión_lógica do<br />

s<strong>en</strong>t<strong>en</strong>cia1;<br />

• s<strong>en</strong>t<strong>en</strong>cia1 puese ser una s<strong>en</strong>t<strong>en</strong>cia compuesta, <strong>en</strong> cuyo caso se escribiría:<br />

while expresión_lógica do<br />

begin<br />

conjunto se s<strong>en</strong>t<strong>en</strong>cias;<br />

<strong>en</strong>d;<br />

S<strong>en</strong>t<strong>en</strong>cia for (Para-Repetir)<br />

• Utilidad: escribir m<strong>en</strong>os <strong>en</strong> ciclos controlados por una variable contador.<br />

• Es m<strong>en</strong>os g<strong>en</strong>érica que while, exist<strong>en</strong> ciclos, que por su condición de iteración, pued<strong>en</strong><br />

expresarse mediante una s<strong>en</strong>t<strong>en</strong>cia while, pero no mediante una for.<br />

• Sintaxis:<br />

for vcb := valor_inicial to/downto valor_final do<br />

s<strong>en</strong>t<strong>en</strong>cia1;<br />

• Características:<br />

1) La variable de control del bucle (vcb) no debe cambiarse d<strong>en</strong>tro del bucle. Sus valores<br />

pued<strong>en</strong> utilizarse pero no deb<strong>en</strong> cambiarse. Esto es, la vcb puede aparecer <strong>en</strong> una<br />

expresión pero no debería aparecer <strong>en</strong> la parte izquierda de una s<strong>en</strong>t<strong>en</strong>cia de<br />

asignación.<br />

2


2) La vcb se increm<strong>en</strong>ta o decrem<strong>en</strong>ta automáticam<strong>en</strong>te <strong>en</strong> uno. Si necesita increm<strong>en</strong>tar o<br />

decrem<strong>en</strong>tar por otro valor debe usar while o repeat.<br />

3) Si s<strong>en</strong>t<strong>en</strong>cia1 es compuesta debe ir <strong>en</strong>cerrada <strong>en</strong>tre un par begin-<strong>en</strong>d.<br />

S<strong>en</strong>t<strong>en</strong>cia repeat (Repetir-Hasta)<br />

• Sintaxis:<br />

repeat<br />

s<strong>en</strong>t<strong>en</strong>cia1;<br />

until expresión_lógica;<br />

• s<strong>en</strong>t<strong>en</strong>cia1 puede ser compuesta, <strong>en</strong> cuyo caso se utiliza la misma sintaxis. Existe una<br />

difer<strong>en</strong>cia fundam<strong>en</strong>tal con la s<strong>en</strong>t<strong>en</strong>cia while. Ahora el bucle se ejecuta al m<strong>en</strong>os una vez<br />

porque la condición está ubicada al final del bucle, y nada impide que pase el flujo del<br />

programa la primera vez. Por otro lado, la condición de parada <strong>en</strong> un bucle suele ser justo la<br />

contraria <strong>en</strong> un caso que <strong>en</strong> otro. Es lógico, uno es mi<strong>en</strong>tras ocurra una cosa y el otro es hasta<br />

que esa cosa se cumpla.<br />

Por ejemplo supongamos un algoritmo que lea las coord<strong>en</strong>adas de tres puntos y los mueva<br />

tres puntos <strong>en</strong> la coord<strong>en</strong>ada x y escriba el resultado <strong>en</strong> algún dispositivo de salida:<br />

ALGORITMO lee_tres_vertices<br />

ENTRADA: las coord<strong>en</strong>adas (x,y) de tres puntos<br />

SALIDA: las coord<strong>en</strong>adas (x,y) de los tres puntos movidos 3 puntos hacia la<br />

derecha.<br />

VARIABLES: i:<strong>en</strong>tera<br />

x,y: real<br />

INICIO<br />

PARA i←1 HASTA 3 CON INCREMENTO +1<br />

ESCRIBE "Abscisa del punto número ", i<br />

LEER x<br />

ESCRIBE "Ord<strong>en</strong>ada del punto número ", i<br />

LEER Y<br />

ESCRIBE "El punto es (" x+3","y")"<br />

FIN_PARA<br />

FIN<br />

El programa equival<strong>en</strong>te a este algoritmo se muestra a continuación. Como podemos apreciar<br />

<strong>en</strong> un programa <strong>en</strong> <strong>Pascal</strong> es importantísimo no olvidar detalles de sintaxis. Por ejemplo cada<br />

s<strong>en</strong>t<strong>en</strong>cia termina <strong>en</strong> punto y coma. De cualquier forma es inmediato apreciar los simples<br />

cambios exist<strong>en</strong>tes.<br />

program lee_tres_vertices;<br />

var x,y:real;<br />

i:integer;<br />

begin<br />

for i:=1 to 3 do<br />

begin<br />

write ('Abscisa del punto número ',i); readln(x);<br />

write ('Ord<strong>en</strong>ada del punto número ',i); readln(y);<br />

writeln (' El punto es (',x+3,',',y,')');<br />

<strong>en</strong>d;<br />

<strong>en</strong>d;<br />

Estructuras de datos: Arrays<br />

Declaración de un tipo array: TYPE id<strong>en</strong>tificador = array[valor_inicial..valor_final] of tipo;<br />

Declaración de una variable array:<br />

VAR id<strong>en</strong>tificador : array[valor_inicial .. valor_final] of tipo;<br />

3


VAR id<strong>en</strong>tificador : tipomatrizdefinida<strong>en</strong>TYPE;<br />

Si hay un único subrango t<strong>en</strong>emos un array unidim<strong>en</strong>sional o vector. Si exist<strong>en</strong> varios, un array<br />

multidim<strong>en</strong>sional.<br />

Un elem<strong>en</strong>to de un array puede ser utilizado <strong>en</strong> cualquier lugar donde se pueda poner una<br />

variable, la sintaxis para acceder es:<br />

id<strong>en</strong>tificador[expresión]<br />

las expresiones deb<strong>en</strong> coincidir con los valores permitidos del array correspondi<strong>en</strong>tes.<br />

Aunque un array debe ser pasado por valor <strong>en</strong> un subprograma siempre que no vaya a ser<br />

modificado, es preferible hacerlo por variable o refer<strong>en</strong>cia.<br />

Ejemplos de arrays:<br />

En nuestro caso hemos decidido definir tanto un punto como un polígono mediante arrays de la<br />

sigui<strong>en</strong>te forma:<br />

TYPE<br />

TipoPunto = array [0..1] of real;<br />

TipoPoligono = array [0..MAX_PUNTOS_POLIGONO-1] of TipoPunto;<br />

Pero recordar, esto sólo es la definición de los datos. Para poder utilizarlos se debe hacer<br />

mediante la declaración de una varialble:<br />

VAR<br />

a,b,c:TipoPunto;<br />

Ahora pued<strong>en</strong> operarse con a, b y c;<br />

AreaTriangulo2 := (a[0]*b[1]-a[1]*b[0] +<br />

b[0]*c[1]-b[1]*c[0] +<br />

c[0]*a[1]-c[1]*a[0]) ;<br />

Por supuesto también podemos hacer cosas como :<br />

a[0]:=3;<br />

b[1]:=5*a[1]-8;<br />

write (a[1]);<br />

readln( b[0]);<br />

{etcétera}<br />

La definición de TipoPolígono es algo más cojmpleja porque se trata de una matriz<br />

bidim<strong>en</strong>sional:<br />

x y<br />

Como ejemplo de uso, el sigui<strong>en</strong>te código lee una serie de puntos de teclado para formar un<br />

polígono:<br />

TYPE x=0; y=1;<br />

...<br />

for i:=0 to n-1 do<br />

begin<br />

write('P[',i,',x]= '); read(p[i,x]);<br />

write('P[',i,',y]='); readln(p[i,y]);<br />

4


<strong>en</strong>d;<br />

Procedimi<strong>en</strong>tos y funciones<br />

En el caso anterior hemos resuelto el problema realizando un programa. Sin embargo los<br />

programas reales ti<strong>en</strong>d<strong>en</strong> a ser bastante más grandes. Para que se facilite la tarea de<br />

programar sería adecuado dividir el problema <strong>en</strong> módulos, de modo que el programa no se<br />

construyera con innumerables líneas de código sino con una serie de llamadas a<br />

subalgoritmos, con las v<strong>en</strong>tajas de la mejora de la claridad <strong>en</strong> los programas, la reutilización de<br />

código y el mant<strong>en</strong>imi<strong>en</strong>to de los programas.<br />

Recordaremos que exist<strong>en</strong> dos tipos de subalgoritmos, procedimi<strong>en</strong>tos y funciones. Para<br />

decantarnos <strong>en</strong> utilizar un tipo u otro t<strong>en</strong>dremos <strong>en</strong> cu<strong>en</strong>ta la sigui<strong>en</strong>te tabla.<br />

Salida Simple Salida Estructurada<br />

1 Salida Función Procedimi<strong>en</strong>to<br />

Más de una salida Procedimi<strong>en</strong>to Procedimi<strong>en</strong>to<br />

Se considera un valor de salida a aquel que se obti<strong>en</strong>e d<strong>en</strong>tro del subalgoritmo a partir de otros<br />

de <strong>en</strong>trada. El tipo de dato de salida se considera simple cuando es un tipo definido por el<br />

propio l<strong>en</strong>guaje, como los <strong>en</strong>teros, reales, lógicos, etc. Los tipos estructurados los suele crear<br />

el usuario a partir de otros tipos de datos simples, por ejemplo un polígono, una lista de notas<br />

de alumnos, etc. Exist<strong>en</strong> otros datos definidos por el usuario que sin embargo pued<strong>en</strong><br />

considerarse simples, puestos que están compuestos de un número muy pequeño de<br />

elem<strong>en</strong>tos, un punto, un número complejo, etc. Sin embargo nosotros lo consideraremos<br />

estructurados para simplificar.<br />

Por ejemplo la suma de tres valores <strong>en</strong>teros es una función porque indep<strong>en</strong>di<strong>en</strong>tem<strong>en</strong>te del<br />

número de elem<strong>en</strong>tos que <strong>en</strong>tran sólo sale un valor y éste es simple<br />

a<br />

b<br />

c<br />

suma<br />

Sin embargo un subalgoritmo que intercambie los cont<strong>en</strong>idos de dos variables o que devuelva<br />

un polígono, será un procedimi<strong>en</strong>to. En el primer caso porque sal<strong>en</strong> dos variables y <strong>en</strong><br />

segundo porque el tipo de dato de salida es estructurado.<br />

a<br />

b<br />

Recordaremos brevem<strong>en</strong>te los procedimi<strong>en</strong>tos y funciones <strong>en</strong> seudocódigo y sus equival<strong>en</strong>cias<br />

<strong>en</strong> <strong>Pascal</strong>.<br />

FUNCION Suma (a,b,c:<strong>en</strong>tero):<strong>en</strong>tero<br />

ENTRADA; a,b,c<br />

SALIDAD: a+b+c<br />

VARIABLES:<br />

INICIO<br />

Suma ← a+b+c<br />

FIN<br />

b<br />

a<br />

FUNCTION Suma (a,b,c:integer):interger;<br />

BEGIN<br />

Suma := a+b+c;<br />

END;<br />

5


PROCEDIMIENTO Intercambio(var a,b:<strong>en</strong>tero)<br />

ENTRADA: a,b<br />

SALIDA: a,b<br />

VARIABLES: aux<br />

INICIO<br />

aux ← a<br />

a ← b<br />

b ← aux<br />

FIN<br />

PROCEDURE Intercambia(var a,b:integer);<br />

VAR: aux<br />

BEGIN<br />

aux := a;<br />

a := b;<br />

b := aux;<br />

END;<br />

Como podemos observar el paso de seudocódigo a pascal es inmediato, sólo es necesario<br />

recordar las reglas de sintáxis y algunos aspectos básicos.<br />

• Los subalgoritmos terminan con (;) y no con (.)<br />

• Los parámetros pasados por refer<strong>en</strong>cia se distingu<strong>en</strong> por llevar igualem<strong>en</strong>te la partícula<br />

var. Se pasan por valor <strong>en</strong> caso contrario.<br />

• Nunca se realizan operaciones de <strong>en</strong>trada/salida <strong>en</strong> un procedimi<strong>en</strong>to o función, toda la<br />

información <strong>en</strong>tra y sale como parámetro.<br />

La pregunta ahora es determinar cuando un parámetro es pasado por valor o por refer<strong>en</strong>cia.<br />

Para ello nos ayudará la sigui<strong>en</strong>te tabla:<br />

Para cada parámetro tipo de dato tipo de dato<br />

simple<br />

estructurado<br />

de <strong>en</strong>trada por valor por refer<strong>en</strong>cia<br />

de salida o de<br />

<strong>en</strong>trada/salida<br />

por refer<strong>en</strong>cia por refer<strong>en</strong>cia<br />

Esto nos ayuda a saber porqué los parámetros a,b y c de la función está pasados por valor<br />

(son de <strong>en</strong>trada y simples), mi<strong>en</strong>tras que los parámetros a y b del procedimi<strong>en</strong>to son pasados<br />

por refer<strong>en</strong>cia (son de <strong>en</strong>trada y salida al mismo tiempo).<br />

Ahora estamos <strong>en</strong> disposición de modificar el programa que calcula el punto de intersección<br />

<strong>en</strong>tre dos rectas. Sería muy conv<strong>en</strong>i<strong>en</strong>te mant<strong>en</strong>er un subalgoritmo con esta operación y<br />

simplem<strong>en</strong>te hacer una llamada siempre que nos interese, de este modo, basta con escribirlo<br />

una vez y utilizarlo siempre que fuera necesario.<br />

At<strong>en</strong>di<strong>en</strong>do al programa, vemos que:<br />

• El procedimi<strong>en</strong>to queda después de la definición del programa, las constantes y variables y<br />

antes del programa principal.<br />

• Se consideran com<strong>en</strong>tarios lo que quede <strong>en</strong>tre llaves o <strong>en</strong>tre los símbolos (*...*)<br />

• La <strong>en</strong>trada/salida se realiza <strong>en</strong> el programa principal, no <strong>en</strong> el procedimi<strong>en</strong>to, a no ser que<br />

sea un procedimi<strong>en</strong>to exclusivo de <strong>en</strong>trada o salidada.<br />

• El procedimi<strong>en</strong>to se invoca mediante una llamada. Los parámetros se correspond<strong>en</strong> por<br />

posición, no por nombre. Así p<strong>en</strong>di<strong>en</strong>te1 se correspond<strong>en</strong> con el parámetro m1, const1 con<br />

c1, y así sucesivam<strong>en</strong>te.<br />

• Los parámetros x e y (coincid<strong>en</strong> <strong>en</strong> nombre por casualidad) son pasados por refer<strong>en</strong>cia<br />

porque son de salida.<br />

6


program interseccion;<br />

const infinito=9.9e9;<br />

var p<strong>en</strong>di<strong>en</strong>te1, p<strong>en</strong>di<strong>en</strong>te2, const1, const2,x,y:real;<br />

procedure Intersec_Rectas (m1,c1,m2,c2:real; VAR x,y:real);<br />

begin<br />

if abs(m2-m1) < 0.00001 (*p<strong>en</strong>di<strong>en</strong>te infinita*)<br />

th<strong>en</strong> begin<br />

x:=infinito; y:=infinito;<br />

<strong>en</strong>d<br />

else begin<br />

x:=(c1-c2)/(m2-m1);<br />

y:=m1*x+c1;<br />

<strong>en</strong>d;<br />

<strong>en</strong>d;<br />

{ -------------------PROGRAMA PRINCIPAL------------------}<br />

begin<br />

writeln ('Datos de la primera recta');<br />

write ('p<strong>en</strong>di<strong>en</strong>te1= '); readln(p<strong>en</strong>di<strong>en</strong>te1);<br />

write ('const1= '); readln(const1);<br />

writeln ('Datos de la segunda recta');<br />

write ('p<strong>en</strong>di<strong>en</strong>te2= '); readln(p<strong>en</strong>di<strong>en</strong>te2);<br />

write ('const2= '); readln(const2);<br />

Intersec_Rectas(p<strong>en</strong>di<strong>en</strong>te1,const1,p<strong>en</strong>di<strong>en</strong>te2,const2, x,y);<br />

if x=infinito<br />

th<strong>en</strong> writeln ('rectas paralelas')<br />

else writeln ('intersección <strong>en</strong> (',x:4:2,',',y:4:2,')');<br />

readln;<br />

<strong>en</strong>d.<br />

Com<strong>en</strong>tarios:<br />

Como no puede tratarse computacionalm<strong>en</strong>te el valor infinito, supongamos que tomamos un<br />

valor constante cualquiera sufici<strong>en</strong>tem<strong>en</strong>te alto. De esta forma trataremos el problema.<br />

Ejemplo: Intersección de dos segm<strong>en</strong>tos<br />

Si quisieramos conocer si intersectan o no dos segm<strong>en</strong>tos definidos por los sus puntos<br />

extremos, t<strong>en</strong>dremos que realizar los pasos sigui<strong>en</strong>tes:<br />

1. conocer las ecuaciones de la recta que pasan que pasan por ambos segm<strong>en</strong>tos<br />

2. calcular el punto de intersección <strong>en</strong>tre las dos rectas que conti<strong>en</strong>e a ambos segm<strong>en</strong>tos<br />

3. ver si el punto de intersección de ambas rectas queda d<strong>en</strong>tro de los segm<strong>en</strong>tos.<br />

Como vemos, el paso número 2 ya está implem<strong>en</strong>tado con el procedimi<strong>en</strong>to Intersec_Rectas,<br />

una de las v<strong>en</strong>tajas que ti<strong>en</strong>e la programación modular. También sería interesante realizar un<br />

subalgoritmo que dado un segm<strong>en</strong>to construya devuelva la ecuación de la recta que lo<br />

conti<strong>en</strong>e. Una vez construido dicho procedimi<strong>en</strong>to se llamará dos veces, una para cada<br />

segm<strong>en</strong>to implicado.<br />

Como hemos visto <strong>en</strong> teoría, es siempre más recom<strong>en</strong>dable utilizar la aritmética de <strong>en</strong>teros<br />

que la de reales, sin embargo, si lo que deseamos es conocer el punto de intersección de dos<br />

rectas o segm<strong>en</strong>tos no hay más remedio que emplear esta última.<br />

program Interseccion_Segm<strong>en</strong>tos;<br />

CONST x=0; y=1;<br />

infinito=9.9e9;<br />

TYPE<br />

TipoPunto = array [0..1] of real;<br />

var<br />

a,b,c,d:TipoPunto;<br />

xx,yy:real;<br />

7


{--------------------------------------------------------------------}<br />

{(x,y) ser el punto de intersecci¢n de las rectas (m1,c1) y (m2,c2)<br />

si son paralelas x e y son igual a infinito}<br />

procedure Intersec_Rectas (m1,c1,m2,c2:real; VAR x,y:real);<br />

begin<br />

if (m1=infinito) and (m2=infinito) {rectas verticales paralelas}<br />

th<strong>en</strong> begin<br />

x:=infinito; y:=infinito;<br />

<strong>en</strong>d<br />

else if m1=infinito {la ecuación de la recta es x=c1}<br />

th<strong>en</strong> begin<br />

x:=c1; y:=m2*x+c2;<br />

<strong>en</strong>d<br />

else if m2=infinito<br />

th<strong>en</strong> begin<br />

x:=c2; y:=m1*x+c1;<br />

<strong>en</strong>d<br />

else if abs(m2-m1) < 0.00001 (*son rectas paralelas*)<br />

th<strong>en</strong> begin<br />

x:=infinito; y:=infinito;<br />

<strong>en</strong>d<br />

else begin<br />

x:=(c1-c2)/(m2-m1);<br />

y:=m1*x+c1;<br />

<strong>en</strong>d;<br />

<strong>en</strong>d;<br />

{-------------------------------------------------------------------------}<br />

{devuelve la ecuación de la recta (m,c) que forma un segm<strong>en</strong>to dado por los<br />

puntos (p1,p2); si la recta resultante es vertical, la p<strong>en</strong>di<strong>en</strong>te m=infinito}<br />

procedure Segm<strong>en</strong>toARecta (var p1,p2:TipoPunto; var m,c:real);<br />

begin<br />

if abs(p2[x]-p1[x]) < 0.00001 (*p<strong>en</strong>di<strong>en</strong>te infinita *)<br />

th<strong>en</strong> begin<br />

m:=infinito; {la ecuación de la recta es x=x1, hacemos x=c1}<br />

c:=p1[x];<br />

<strong>en</strong>d<br />

else begin<br />

m:=(p2[y]-p1[y])/(p2[x]-p1[x]); {m=(y2-y1)/(x2-x1)}<br />

c:=p1[y]-m*p1[x]; {c=y1-mx1}<br />

<strong>en</strong>d;<br />

<strong>en</strong>d;<br />

{--------------------------------------------------------------------}<br />

{indica el punto <strong>en</strong> que intersectan dos segm<strong>en</strong>tos, <strong>en</strong> el caso de no hacerlo<br />

xx e yy son igual a infinito}<br />

procedure Intersec_Segm<strong>en</strong>tos (var a,b,c,d:TipoPunto; var xx,yy:Real);<br />

var<br />

m1,m2,c1,c2:real;<br />

begin<br />

Segm<strong>en</strong>toARecta(a,b,m1,c1);<br />

Segm<strong>en</strong>toARecta(c,d,m2,c2);<br />

Intersec_Rectas (m1,c1,m2,c2,xx,yy);<br />

{la x está <strong>en</strong> el rango del segm<strong>en</strong>to (a,b)}<br />

if not (((a[x]


writeln ('Datos del primer segm<strong>en</strong>to');<br />

writeln ('Datos del primer punto del segm<strong>en</strong>to');<br />

write ('x1= '); readln(a[x]);<br />

write ('y1= '); readln(a[y]);<br />

writeln ('Datos del segundo punto del segm<strong>en</strong>to');<br />

write ('x2= '); readln(b[x]);<br />

write ('y2= '); readln(b[y]);<br />

writeln ('Datos del segundo segm<strong>en</strong>to');<br />

writeln ('Datos del primer punto del segm<strong>en</strong>to');<br />

write ('x1= '); readln(c[x]);<br />

write ('y1= '); readln(c[y]);<br />

writeln ('Datos del segundo punto del segm<strong>en</strong>to');<br />

write ('x2= '); readln(d[x]);<br />

write ('y2= '); readln(d[y]);<br />

Intersec_Segm<strong>en</strong>tos (a,b,c,d,xx,yy);<br />

writeln ('intersecci¢n <strong>en</strong> el punto (',xx:4:2,',',yy:4:2,')');<br />

readln;<br />

<strong>en</strong>d.<br />

Registros<br />

Los registros permit<strong>en</strong> mant<strong>en</strong>er información de distinto tipo bajo el mismo concepto. Por<br />

ejemplo, el registro alumno t<strong>en</strong>dría el nombre y apellidos, el DNI, las asignaturas cursadas <strong>en</strong><br />

el curso actual, la calificaciones, etc. Todos estos datos son de distinta naturaleza (<strong>en</strong>teros,<br />

cad<strong>en</strong>as de caracteres, etc), sin embargo, pose<strong>en</strong> la característica de pert<strong>en</strong>ecer a la <strong>en</strong>tidad<br />

alumno. Por tanto, ti<strong>en</strong>e s<strong>en</strong>tido almac<strong>en</strong>arse bajo un mismo nombre alumno, y eso lo<br />

conseguiremos defini<strong>en</strong>do un registro. Cada uno de los elem<strong>en</strong>tos definidos d<strong>en</strong>tro de un<br />

registro se llaman campos. Veamos de forma g<strong>en</strong>érica la definición.<br />

TYPE nombre_tipo = RECORD<br />

id<strong>en</strong>tificadorCampo1 : tipo1;<br />

...<br />

id<strong>en</strong>tificadorCampoN : tipoN;<br />

END;<br />

Id<strong>en</strong>tificador de campo: es el nombre de una compon<strong>en</strong>te de un registro.<br />

Por ejemplo, un punto, una recta, un número complejo, etc. son tipos de datos estructurados<br />

porque están compuestos a su vez de otros tipos de datos. Ya hemos visto que<br />

computacionalm<strong>en</strong>te hablando, es mejor definir un punto mediante un array de dos posiciones.<br />

Esto es posible hacerlo porque sus dos campos son del mismo tipo. Vamos a definir para<br />

variar, el tipo de dato TipoRecta como un registro con dos campos, la p<strong>en</strong>di<strong>en</strong>te y la constante<br />

según indica la fórmula y=mx+c.<br />

type<br />

TipoRecta = RECORD<br />

m,c:real;<br />

<strong>en</strong>d;<br />

Cuando deseemos declarar una variable de tipo TipoRecta, lo haremos de la sigui<strong>en</strong>te forma:<br />

var<br />

r:TipoRecta;<br />

Para acceder a cada uno de los campos de un registro utilizaremos:<br />

. . En el ejemplo anterior:<br />

y=r.m*x+r.c<br />

9


ya que tanto m como c son campos del registro r.<br />

Las unidades <strong>en</strong> <strong>Pascal</strong> (UNIT)<br />

Una unidad <strong>en</strong> <strong>Pascal</strong> no es más que una librería de funciones y procedimi<strong>en</strong>tos que el usuario<br />

ti<strong>en</strong>e definidos y que utiliza <strong>en</strong> cada programa cuando lo necesite. Por ejemplo, p<strong>en</strong>semos <strong>en</strong><br />

una librería de funciones matemáticas sobre manejo de matrices. Una vez que la operación de<br />

suma de matrices esté definida y funcione perfectam<strong>en</strong>te, bastará con incluir la unidad donde<br />

está escrita y hacer la llamada a la función como si estuviera ubicada <strong>en</strong> el mismo fichero del<br />

programa principal.<br />

Una unidad se d<strong>en</strong>omina unit y posee dos partes. La d<strong>en</strong>ominada INTERFACE donde se<br />

defin<strong>en</strong> los tipos de datos, las constantes necesarias y las cabeceras de los procedimi<strong>en</strong>tos y<br />

funciones. Posteriorm<strong>en</strong>te aparece la palabra reservada IMPLEMENTATION, a partir de donde<br />

se escrib<strong>en</strong> todas las funciones y procedimi<strong>en</strong>tos completos cuyas cabeceras están <strong>en</strong> la zona<br />

interface.<br />

Vamos a escribir una unidad completa con una serie de procedimi<strong>en</strong>tos y funciones válidos <strong>en</strong><br />

nuestra asignatura de geometría computacional. Posee las funciones ya previam<strong>en</strong>te vistas, la<br />

de intersección de dos rectas y dos segm<strong>en</strong>tos. Pero además aparec<strong>en</strong> otras que pued<strong>en</strong> ser<br />

igualem<strong>en</strong>te útiles:<br />

UNIT GEOMLIB;<br />

INTERFACE<br />

CONST x=0; y=1;<br />

infinito=9.9e9;<br />

MAX_PUNTOS_POLIGONO = 100;<br />

TYPE<br />

TipoPunto = array [0..1] of real;<br />

TipoPoligono = array [0..MAX_PUNTOS_POLIGONO-1] of TipoPunto;<br />

TipoRecta = RECORD<br />

m,c:real;<br />

<strong>en</strong>d;<br />

TipoSegm<strong>en</strong>to = array [0..1] of TipoPunto;<br />

procedure Intersec_Rectas (r1,r2:TipoRecta; VAR x,y:real);<br />

procedure Segm<strong>en</strong>toARecta (var p1,p2:TipoPunto; var r:TipoRecta);<br />

procedure Intersec_Segm<strong>en</strong>tos (var a,b,c,d:TipoPunto; var xx,yy:Real);<br />

function AreaPoligono2 (var p:TipoPoligono; n:integer): real;<br />

function AreaTriangulo2 (var a,b,c:TipoPunto) : real;<br />

procedure LeerPoligonoTeclado (var p:TipoPoligono; var n:integer);<br />

procedure LeerPoligonoFichero (var f:string; var p:TipoPoligono; var<br />

n:integer);<br />

procedure EscribirPoligonoFichero (var f:string; var p:TipoPoligono;<br />

n:integer);<br />

procedure EscribirPoligonoPantalla (var p:TipoPoligono; n:integer);<br />

IMPLEMENTATION<br />

{(x,y) ser el punto de intersección de las rectas (m1,c1) y (m2,c2)<br />

si son paralelas x e y son igual a infinito}<br />

procedure Intersec_Rectas (r1,r2:TipoRecta; VAR x,y:real);<br />

begin<br />

if (r1.m=infinito) and (r2.m=infinito) {rectas verticales paralelas}<br />

th<strong>en</strong> begin<br />

x:=infinito; y:=infinito;<br />

<strong>en</strong>d<br />

else if r1.m=infinito {la ecuación de la recta es x=c1}<br />

th<strong>en</strong> begin<br />

x:=r1.c; y:=r2.m*x+r2.c;<br />

<strong>en</strong>d<br />

else if r2.m=infinito<br />

10


th<strong>en</strong> begin<br />

x:=r2.c; y:=r1.m*x+r1.c;<br />

<strong>en</strong>d<br />

else if abs(r2.m-r1.m) < 0.00001 (*son rectas paralelas,<br />

intersectan <strong>en</strong> el infinito*)<br />

th<strong>en</strong> begin<br />

x:=infinito; y:=infinito;<br />

<strong>en</strong>d<br />

else begin<br />

x:=(r1.c-r2.c)/(r2.m-r1.m);<br />

y:=r1.m*x+r1.c;<br />

<strong>en</strong>d;<br />

<strong>en</strong>d;<br />

{devuelve la ecuación de la recta (m,c) que forma un segm<strong>en</strong>to dado por los<br />

puntos (p1,p2); si la recta resultante es vertical, la p<strong>en</strong>di<strong>en</strong>te m=infinito}<br />

procedure Segm<strong>en</strong>toARecta (var p1,p2:TipoPunto; var r:TipoRecta);<br />

begin<br />

if abs(p2[x]-p1[x]) < 0.00001 (*son rectas paralelas, intersectan <strong>en</strong> el<br />

infinito*)<br />

th<strong>en</strong> begin<br />

r.m:=infinito; {la ecuación de la recta es x=x1, pero lo dejamos <strong>en</strong> c}<br />

r.c:=p1[x];<br />

<strong>en</strong>d<br />

else begin<br />

r.m:=(p2[y]-p1[y])/(p2[x]-p1[x]); {m=(y2-y1)/(x2-x1)}<br />

r.c:=p1[y]-r.m*p1[x]; {c=y1-mx1}<br />

<strong>en</strong>d;<br />

<strong>en</strong>d;<br />

procedure Intersec_Segm<strong>en</strong>tos (var a,b,c,d:TipoPunto; var xx,yy:Real);<br />

var<br />

r1, r2: TipoRecta;<br />

begin<br />

Segm<strong>en</strong>toARecta(a,b,r1);<br />

Segm<strong>en</strong>toARecta(c,d,r2);<br />

Intersec_Rectas (r1,r2,xx,yy);<br />

if not (((a[x]


AreaPoligono2 := suma;<br />

<strong>en</strong>d;<br />

procedure LeerPoligonoTeclado (var p:TipoPoligono; var n:integer);<br />

var i:integer;<br />

begin<br />

write ('Número de vértices del polígono: '); readln (n);<br />

for i:=0 to n-1 do<br />

begin<br />

write('P[',i,',x]= '); read(p[i,x]);<br />

write('P[',i,',y]='); readln(p[i,y]);<br />

<strong>en</strong>d;<br />

<strong>en</strong>d;<br />

procedure EscribirPoligonoPantalla (var p:TipoPoligono; n:integer);<br />

var i:integer;<br />

begin<br />

writeln ('Escribiremos el polígono de ',n,' v‚rtices');<br />

for i:=0 to n-1 do<br />

begin<br />

write('P[',i,',x]= ',p[i,x]:4:2); write(' '); writeln('P[',i,',y]=<br />

',p[i,y]:4:2);<br />

<strong>en</strong>d;<br />

<strong>en</strong>d;<br />

procedure LeerPoligonoFichero (var f:string; var p:TipoPoligono; var<br />

n:integer);<br />

var i:integer;<br />

fich: TEXT;<br />

begin<br />

assign (fich, f);<br />

reset (fich);<br />

readln (fich,n);<br />

for i:=0 to n-1 do<br />

read(fich,p[i,x]); readln(fich,p[i,y]);<br />

close (fich);<br />

<strong>en</strong>d;<br />

procedure EscribirPoligonoFichero (var f:string; var p:TipoPoligono;<br />

n:integer);<br />

var i:integer;<br />

fich: TEXT;<br />

begin<br />

assign (fich, f);<br />

rewrite (fich);<br />

writeln (fich,n);<br />

for i:=0 to n-1 do<br />

write(fich,p[i,x]:4:2); write(fich,' ');writeln(fich,p[i,y]:4:2);<br />

close (fich);<br />

<strong>en</strong>d;<br />

<strong>en</strong>d.<br />

FICHEROS<br />

Para terminar aclararemos dos de los procedimi<strong>en</strong>tos anteriorm<strong>en</strong>te implem<strong>en</strong>tados <strong>en</strong> la<br />

unidad geomlib.pas, se trata de los procedimi<strong>en</strong>tos LeerPoligonoFichero y<br />

EscribirPoligonoFichero que utilizan ficheros.<br />

Si nos fijamos son muy similares a los de leer de teclado y escribir <strong>en</strong> pantalla, sin embargo, la<br />

<strong>en</strong>trada y salida será ahora a través de fichero. Esto significa que los datos de <strong>en</strong>trada, los<br />

puntos, estarán dispuestos <strong>en</strong> un fichero de texto (lo escribe el usuario con cualquier editor de<br />

textos); la salida, los resultados, también serán llevados a un fichero.<br />

12


Cuando el fichero sirve de <strong>en</strong>trada al programa, los datos deb<strong>en</strong> estar <strong>en</strong> el fichero antes de la<br />

ejecución del programa. Cuando el fichero es de salida, éste comi<strong>en</strong>za estando vacío y termina<br />

con los resultados del programa.<br />

En nuestro ejemplo, el fichero de <strong>en</strong>trada y de salida posee la sigui<strong>en</strong>te estructura:<br />

n<br />

x0 y0<br />

x2 y2<br />

x3 y3<br />

....<br />

xn-1 yn-1<br />

Por ejemplo para un polígono de 4 vértices:<br />

4<br />

0 0<br />

5 1<br />

3 4<br />

-3 2<br />

Todo fichero debe t<strong>en</strong>er un nombre datos.dat, poligono.dat, valores.txt, o cualquier otro que el<br />

usuario decida. El nombre del fichero será <strong>en</strong> estos procedimi<strong>en</strong>tos el primer parámetro, la<br />

cad<strong>en</strong>a de caracteres o string. La operación assign asigna un nombre de fichero a una variable<br />

fichero. Luego se puede abrir el fichero para leer (reset) o para escribir <strong>en</strong> él (rewrite). El resto<br />

de operaciones, leer y escribir, son idénticas a las correspondi<strong>en</strong>tes para pantalla y teclado, sin<br />

embargo, observamos que el primer parámetro es el nombre de la variable fichero. Hay que<br />

t<strong>en</strong>er especial cuidado con el formato del fichero. Para que no haya problemas utilizaremos la<br />

terminación ln <strong>en</strong> las operaciones de write y read siempre que después haya que realizar un<br />

salto de línea.<br />

13

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!