Está en la página 1de 101

Tema 4

Instrucciones Estructuradas

4.1. Instrucciones compuestas


4.2. Instrucciones de selección
4.3. Instrucciones de iteración
4.4. Corrección y depuración de
instrucciones estructuradas
Objetivo

Exponer al alumno la forma de controlar el


orden de ejecución de las acciones del
programa:
– Control por Selección
– Control por Iteración

Presentar la correcta construcción de


programas que utilizan dichas
construcciones
4.1 Instrucciones compuestas

Bloque de instrucciones:
– Concatenación secuencial de instrucciones

Sintaxis:
– secuencia de instrucciones
– separadas por el carácter ;
– delimitada por BEGIN y END

Semántica
– un bloque representa una única instrucción compuesta
Ejemplo: Composición de instrucciones
bloque 1: 4 instrucciones
BEGIN {bloque 1}
write('Introduzca x,y:');
readln(x,y);
BEGIN {bloque 1.1}
aux:=x;
x:=y;
y:=aux
END; {bloque 1.1}
writeln('x,y = ',x,',',y)
END; {bloque 1}
bloque 1.1: 3 instrucciones
Composición de instrucciones
Composición de instrucciones:
– Subprogramas:
• se usan para modelar subproblemas y sus
soluciones algorítmicas en el marco del diseño
descendente y del refinamiento sucesivo
• son acciones/cálculos lógicos (para el programador)
– Bloques de instrucciones:
• se usan dentro de las instrucciones estructuradas
(de selección y de interacción)
• no tienen por qué formar una entidad lógica
(para el programador)
4.2 Instrucciones de Selección

La instrucción IF

La instrucción CASE
Instrucciones de Selección
Estructura de control de selección:
– permiten elegir dinámicamente (en tiempo de
ejecución) entre diferentes secuencias de
instrucciones
– Ejemplo:
SI en el examen de mañana apruebo ENTONCES
haré las maletas y
me iré de vacaciones
SI NO
me quedaré en casa y
estudiaré para el examen de septiembre
La instrucción IF
Sintaxis:
IF <Expresión Booleana> THEN
<Instrucción1>
ELSE
<Instrucción2>

Semántica:
– se evalúa <Expresión Booleana>
– si el resultado es true, se ejecuta <instrucción1>
– si el resultado es false, se ejecuta <instrucción2>
Ejemplo: versión 1
{bloque de instrucciones para
calcular el máximo de dos números}

BEGIN {bloque}
readln(x,y);
IF x > y THEN
max := x
ELSE
max := y;
writeln('El máximo es ',max)
END; {bloque}
Selección de secuencias de instrucciones

Se acepta sólo una instrucción en la rama


IF y sólo una instrucción en la rama ELSE

Para elegir entre secuencias de


instrucciones, hay que definirlas como un
bloque

Al igual que las instrucciones, dichos


bloques han de sangrarse adecuadamente
Ejemplo: versión 2
BEGIN {bloque exterior}
readln(x,y);
IF x > y THEN BEGIN
max := x;
writeln('El máximo es ',max)
END
ELSE BEGIN
max := y;
writeln('El máximo es ',max)
END
END; {bloque exterior}
Opcionalidad del ELSE
Es posible omitir la rama del ELSE
Semántica:
– si la expresión booleana evalúa a true, se ejecuta la
instrucción 1
– de lo contrario, no se hace nada
Utilidad:
– Con la instrucción IF … THEN … ELSE se elige entre
dos instrucciones alternativas
– Con la instrucción IF … THEN se decide si se ejecuta
una instrucción o no
Opcionalidad del ELSE
Ejemplo:
– Utilizar la instrucción IF sin la rama ELSE para tratar
“casos excepcionales”
BEGIN {bloque}
readln(anyo);
noDias := 365;
IF anyo mod 4 = 0 THEN
noDias := 366;
writeln(anyo,'tiene ',noDias, 'dias')
END; {bloque}
Errores comunes

IF ... THEN ... ELSE es una sola instrucción


Un ; delante del ELSE produce un error
sintáctico
Ejemplo:
IF x > y THEN
max := x; ERROR
ELSE
max := y;
Errores comunes
El sangrado facilita la lectura del
programa para el programador
El compilador ignora el sangrado

Se ejecuta: como:
IF <cond.> THEN IF <cond.> THEN
instrucción1; instrucción1;
instrucción2; instrucción2;
… …
instrucciónN instrucciónN
Recomendaciones
Sangrar adecuadamente las instrucciones
que forman parte del IF (usando
tabuladores)
Si se utilizan instrucciones compuestas,
documentar el fin del bloque con un
comentario
No se deben repetir instrucciones comunes
a las dos ramas de la estructura IF
– la versión 1 del ejemplo es preferible a la versión 2
Recomendaciones
No utilizar instrucciones IF para la
asignación de valores booleanos
– en vez de:
IF (x>=0) and (x<10) THEN
B:=true
ELSE
B:=false;
– mejor usar:
B:= (x>=0) and (x<10)
Alternativas múltiples

Una sola instrucción IF permite elegir


únicamente entre dos alternativas

Para elegir entre tres o más alternativas:


– anidar instrucciones IF

– usar la instrucción CASE


Instrucciones IF anidadas: Ejemplo
FUNCTION Max3(x,y,z:integer):integer;
{ Pre: x,y,z  N}
{ Post: Max3 es el máximo de x,y,z}
BEGIN {Max3}
IF x > y THEN
IF x > z THEN
Max3:=x Cada ELSE se corresponde
ELSE con el THEN soltero más
Max3:=z próximo
ELSE
IF y > z THEN
Max3:=y
ELSE
Max3:=z;
END; {Max3}
La instrucción CASE
Sintaxis: CASE <exp. selectora> OF
<etiqueta1>: <Instrucción1>;
<etiqueta2>: <Instrucción2>;
...
<etiquetaN>: <InstrucciónN>;
[ELSE
<InstrucciónELSE>; {no en P. Estándar}
END {CASE} {es opcional}
Semántica:
– se evalúa <expresión selectora>
– se ejecuta la primera instrucción cuya etiqueta coincida
con el valor de <expresión selectora>
– si no hay coincidencia y hay ELSE, se ejecuta
<InstrucciónELSE>
La instrucción CASE
El expresión selectora ha de ser de tipo ordinal
(no sólo boolean, sino también integer o char)
Las etiquetas pueden ser
– constantes anónimas (p.e.: 16)
– listas de constantes (p.e.: 30,31)
– subintervalos de tipos ordinales (p.e.: 1..15)
El tipo de la expresión selectora ha de coincidir con
el tipo de los elementos de la etiqueta
Pueden usarse bloques de instrucciones
La instrucción CASE
Ejemplo:
CASE opcion OF
1..15: writeln('Primera Quincena');
16: writeln('Primera Prueba');
17..29: BEGIN {bloque}
writeln('Esto es un bloque');
writeln('Segunda Quincena')
END; {bloque}
30,31: writeln('Segunda Prueba');
ELSE writeln(‘valor erroneo’);
END {CASE}
IF anidado y CASE
CASE:
– usar cuando haya alternativas múltiples que
dependen de la misma expresión selectora
– p.e. CASE round((nota1+nota2+nota3)/3) OF
...

IF anidado
– usar cuando haya alternativas múltiples que
dependen de selectores diferentes
Ejemplo: IF anidado
Ejemplo:
– decidir si se alquila un coche en función de dos
variables selectoras:
• la posesión del carnet de conducir
• la edad
– regla:
• no tiene carnet • no se alquila coche
• tiene carnet y es menor de 25 • se alquila a precio
alto
• tiene carnet y es mayor de 25 • se alquila a
precio bajo
Ejemplo: IF anidado
IF tieneCarnet THEN
IF edad <= 25 THEN
{tienecarnet  edad  25}
writeln('precio alto')
ELSE
{tienecarnet  (edad  25)}
writeln('precio bajo')
ELSE
{ tienecarnet}
writeln('no se alquila coche');
4.3 Instrucciones de Iteración
Iteración:
– Proceso de ejecutar repetidamente el mismo
bloque de instrucciones.
– En cada iteración se ejecutan las mismas
acciones en el mismo orden.
Ciclo (ó bucle):
– Secuencia de enunciados que se repite
– Iteración: Acto de ejecutar repetidamente un ciclo
– Una iteración: Acto de ejecutar una vez un ciclo
Objetivos de Iteración

Establecer un ciclo que se ejecute


repetidamente:

– mientras se cumpla una condición (WHILE)


– hasta que se cumpla una condición
(REPEAT..UNTIL)
– un número preestablecido de veces (FOR)
La estructura WHILE
Sintaxis:
WHILE <expresión booleana> DO
<instrucción>
Semántica:
– Si la evaluación de <exp. booleana> es true, se ejecuta
<instrucción>
– Seguidamente se evalúa de nuevo <exp. booleana>,
• repitiéndose el proceso si el resultado es true, ó
• ejecutándose la siguiente instrucción del programa
si el resultado es false
– Bucle de 0 a n iteraciones
Semántica del WHILE

Instrucción N-1;

WHILE <condición> DO ¿Condición?


BEGIN Condición = true
instrucN1; Condición = false
...
instrucNk
END; {WHILE}

Instrucción N+1;
Ejemplo
Ejemplo: Calcular  i = 1+2+...+n utilizando WHILE
BEGIN {bloque}
readln(n);
suma := 0;
contador := 1;
WHILE contador <= n DO BEGIN
suma := suma + contador;
contador := contador+1
END; {WHILE}
writeln(suma);
END {bloque}
Ciclos infinitos

Ciclos infinitos WHILE:


– se produce un ciclo infinito WHILE cuando, por
muchas veces que se repita el cuerpo del bucle, la
condición booleana nunca evalúa a false

Evitar ciclos infinitos


– es tarea del programador prevenir estos ciclos
infinitos
– ha de modificarse al menos una variable en el
cuerpo
Errores comunes

Prevenir errores comunes


– asegurar que las variables de la expr. booleana
están iniciadas antes de evaluarlas por primera
vez
– Nunca colocar un ; detrás del DO, ya que
indicaría que el cuerpo está vacío
– No olvidar delimitar el cuerpo del bucle con
BEGIN y END (cuando sea necesario)
Características del WHILE
La estructura WHILE modela ciclos
preprobados:
– Si la expresión booleana es falsa en la primera
evaluación, el bloque no se llegará a ejecutar, y se
ejecutará la instrucción N+1

La estructura WHILE realiza un número variable


de iteraciones :
– el número de veces que se ejecuta el cuerpo se
determina dinámicamente, en función de las
repetidas modificaciones de las variables en el
mismo cuerpo
Estructuras WHILE anidadas
Es posible anidar estructuras WHILE:
WHILE <condición-1> DO BEGIN
<instrucciones>;
WHILE <condición-2> DO BEGIN
<instrucciones>
END; {WHILE interior}
<instrucciones>
END {WHILE exterior}

Antes de usar estructuras WHILE anidadas,


comprobar detenidamente si un ciclo normal no
es suficiente
Ejemplo: estructuras WHILE anidadas
Problema:
– contar el número de caracteres y líneas del fichero
input

Funciones booleanas predefinidas


– eoln: es true si el carácter actual del archivo es una
marca fin de línea, y false de lo contrario
– eof: es true si el carácter actual del archivo es la marca
fin de fichero, y false de lo contrario
– si se llaman sin argumentos, dichas funciones se
refieren al fichero input
Ejemplo: estructuras WHILE anidadas
BEGIN {bloque}
numLin := 0; {inicializar contadores}
numCar := 0;
WHILE not eof DO BEGIN
WHILE not eoln DO BEGIN
read(c);
numCar := numCar+1
END; {WHILE interior}
readln; {consumir eoln}
numLin := numLin+1;
END; {WHILE exterior}
writeln(numCar,' ',numLin)
END; {bloque}
Estructura REPEAT ... UNTIL
Repeat … until: repetir ... hasta que.
Sintaxis:
REPEAT
<instrucción1> ;
...
<instrucciónN> ;
UNTIL <expresión booleana>
Nótese:
– Excepcionalmente, todas las instrucciones entre REPEAT
y UNTIL se consideran un bloque de instrucciones,
aunque no estén delimitadas por BEGIN y END
Semántica del REPEAT...UNTIL

Semántica:
– El bloque de instrucciones se ejecuta siempre la
primera vez (de 1 a n iteraciones).
– Luego se evalúa la expresión booleana
• si evalúa a true, se ejecuta la siguiente instrucción
• si evalúa a false, continuarán las iteraciones hasta
que se cumpla la expr. booleana.

La comprobación se hace al final del ciclo.


Semántica del REPEAT...UNTIL

Instrucción N-1;

REPEAT
instr N1;
. . .
instr Nk
UNTIL <condición> ¿Condición?
Condición = true Condición = false
Instrucción N+1;
Ejemplo 1
Ejemplo: Calcular  i = 1+2+...+n utilizando REPEAT
BEGIN {bloque}
readln(n);
suma := 0;
contador := 1;
REPEAT
suma := suma + contador;
contador := contador+1
UNTIL contador > n;
writeln(suma)
END; {bloque}
Ejemplo 2
Aplicación preferente: lectura de datos
– seguir pidiendo datos hasta que se introduzcan
valores válidos
BEGIN {bloque para leer un entero positivo}
REPEAT
write('Introduzca un entero pos.: ');
readln(numero)
UNTIL numero > 0;
{número > 0}
END; {bloque}
Errores comunes
prevenir ciclos infinitos REPEAT:
– es tarea del programador prevenir ciclos infinitos,
por lo que ha de modificarse al menos una variable
en el cuerpo
– el ciclo termina cuando la condición evalúa a true
(contrario al WHILE)
– asegurarse que todas las operaciones durante la
primera ejecución del cuerpo son válidas (que no
haya división por cero etc.)
– tener en cuenta que también la primera ejecución
del cuerpo afecta a algunas de las variables de la
expresión booleana
Características del REPEAT
La estructura REPEAT modela ciclos
postprobados:
– La expresión booleana se evalúa después de las
instrucciones del cuerpo, por lo que éstas se ejecutan
al menos una vez

La estructura REPEAT realiza un número variable


de iteraciones:
– el número de veces que se ejecuta el cuerpo se
determina dinámicamente, en función de las repetidas
modificaciones de las variables en el mismo cuerpo
WHILE y REPEAT ... UNTIL

Cualquier ciclo REPEAT puede


traducirse en un ciclo WHILE

C := false;
REPEAT
WHILE not C DO BEGIN
I1;
I1;
... traducción
In ...
In
UNTIL C;
END; {WHILE}
WHILE y REPEAT...UNTIL
Recomendaciones técnicas (preliminares):

¿Se sabe de antemano que el cuerpo del bucle


ha de ejecutarse al menos una vez?

SI NO

Usar ciclo Usar ciclo


REPEAT...UNTIL WHILE
Estructura FOR .. TO .. DO
Tipo de ciclo común:
– en el cuerpo se modifica una variable contador
– la condición de salida se cumple cuando dicha
variable contador llega a un valor cota
Realización en Pascal
– ciclo FOR...TO...DO
– simplifica un bucle WHILE equivalente
(y permite su optimización)
Estructura FOR .. TO .. DO

Ciclo ascendente
– WHILE
cont:=cotaInferior;
WHILE cont<=cotaSuperior DO BEGIN
<instrucciones>;
cont:=succ(cont);
END; {WHILE}
– FOR equivalente
FOR cont:=cotaInferior TO cotaSuperior DO
BEGIN
<instrucciones>;
END; {FOR}
Estructura FOR .. TO .. DO
Ciclo descendente
– WHILE
Cont:=cotaSuperior;
WHILE cont>=cotaInferior DO BEGIN
<instrucciones>;
cont := pred(cont);
END; {WHILE}

– FOR equivalente
FOR cont:=cotaSuperior DOWNTO cotaInferior DO
BEGIN
<instrucciones>;
END; {FOR}
Sintaxis: FOR .. TO .. DO
En general, tanto la cota inferior como la cota
superior pueden ser expresiones
Sintaxis (ciclo ascendente):
FOR indice:= <expr. inicial> TO <expr. final> DO
<instrucción>

Sintaxis (ciclo descendente):


FOR indice:= <expr. inicial> DOWNTO <expr. final> DO
<instrucción>
Semántica ciclo FOR ascendente

false
¿Indice<=ExpFinal?
IN-1; true
FOR Indice:=ExpIni TO ExpFinal DO
BEGIN
Indice :=
succ(Indice)
instrN1;
...
instrNk
END; {FOR}
IN+1;
Semántica ciclo FOR descendente

false
¿Indice>=ExpFinal?
IN-1; true
FOR Indice:=ExpIni DOWNTO ExpFinal DO
BEGIN
Indice :=
pred(Indice)
instrN1;
...
instrNk
END; {FOR}
IN+1;
Ejemplo
Ejemplo: Calcular i = 1+2+...+n utilizando FOR
BEGIN {bloque}
readln(n);
suma := 0;
FOR contador := 1 TO n DO BEGIN
suma := suma + contador;
END; {FOR}
writeln(suma)
END; {bloque}
La variable contadora
Indice:
– se llama variable contadora o índice del ciclo
– se ha de declarar como variable (no debe ser
parámetro formal etc.)
– ha de ser ordinal (no sólo integer, sino también char o
boolean). Por ejemplo:
FOR c:= 'A' TO 'Z' DO
write(c);
writeln
Expresión inicial y final
Exp. Inicial y Exp. Final:
– han de ser de tipos compatibles con el tipo de índice
– expIni y expFinal se evalúan sólo una vez, antes de la
ejecución del ciclo
– no se ejecuta el ciclo (ni una sólo vez)
• Si inicialmente expFinal<expInicial en ciclo
ascendente ó
• Si inicialmente expFinal>expInicial en ciclo
descendente
Restricciones para la variable contadora
El número de iteraciones se determina una vez al
iniciar la ejecución del ciclo FOR
Durante el ciclo no se debe alterar el número de
iteraciones.
Restricciones para índice:
– No se le debe asignar un valor
– No se debe pasar como parámetro VAR a un
subprograma
– No se debe llamar a read o readln con índice
– No se debe “reutilizar” como índice de un FOR anidado
– Al salir del ciclo FOR, habrá que suponer que el valor
de indice está sin definir
Estructuras FOR anidadas
Ejemplo:
– escribir los valores de una matriz n x m
– siendo cada elemento Mi,j= ½(i+j)

BEGIN {bloque}
writeln('Tamaño de la matriz: ');
readln(n,m);
FOR i:= 1 TO n DO
FOR j:= 1 to m DO
writeln('M[',i,',',j,']=',(i+j)/2)
END; {bloque}
Errores comunes y limitaciones
Prevenir errores comunes:
– no hay peligro de ciclos infinitos, a no ser que se
modifique la variable contadora en el cuerpo
– Nunca colocar un ; detrás del DO ya que indicaría que el
cuerpo está vacío
– No olvidar delimitar el cuerpo del bucle con BEGIN y END
Limitaciones:
– En Pascal no es posible definir ciclos FOR con
incrementos o decrementos distintos de 1 (siempre se
toma el sucesor o el predecesor del valor actual)
– en estos casos, habrá que usar un ciclo WHILE
equivalente
Características del FOR
La estructura FOR modela ciclos preprobados:
– Si la variable indice inicialmente es mayor que la
expresión inicial (o: menor, para ciclos descendentes),
el cuerpo no se llegará a ejecutar, y se ejecutará la
instrucción n+1

La estructura FOR realiza un número fijo de


iteraciones
– el número de veces que se repite el cuerpo depende
de la diferencia entre la expresión inicial y la expresión
final, la cual se fija sin considerar las instrucciones del
cuerpo
WHILE , REPEAT y FOR
Recomendaciones técnicas:
¿ Se sabe de antemano cuántas veces el
cuerpo del bucle ha de ejecutarse?

SI NO

Usar ciclo ¿ Se sabe de antemano que el cuerpo del


FOR bucle ha de ejecutarse al menos una vez?

SI NO

Usar ciclo Usar ciclo


REPEAT...UNTIL WHILE
Esquematización de algoritmos iterativos

Se pueden identificar 2 estrategias


diferenciadas para diseñar algoritmos
iterativos
Cada estrategia da lugar a un esquema
iterativo distinto:
– esquema de recorrido
– esquema de búsqueda
La elección de uno u otro dependerá de la
naturaleza del problema
Esquema de recorrido
Problema 1. Contar las apariciones de la letra ‘a’
en una secuencia de caracteres acabada en ‘.’
BEGIN {bloque}
Read(car);
num_a:= 0;
WHILE car <> ‘.’ DO BEGIN
IF car = ‘a’ then
num_a := num_a + 1;
Read(car);
END; {WHILE}
writeln(num_a);
END {bloque}
Esquema de recorrido
Problema 2. El número e se define como la suma de la
siguiente serie: 1/1! + 1/2! + 1/3! + ..., se desea obtener
el valor de la serie para n términos
BEGIN {bloque}
Readln(n);
serie:= 0;
fact:=1;
FOR i:=1 TO n DO BEGIN
fact:= fact * i;
serie:= serie + 1/fact
END; {FOR}
writeln(serie);
END {bloque}
Esquema de recorrido
Coincidencias entre los 2 problemas:
– En ambos casos hay que procesar todos
los elementos de una secuencia (letras de
una frase, n términos de una serie)
Diferencias entre los 2 problemas:
– Saber o no a priori el numero de elementos
– Afecta al tipo de bucle que se puede utilizar
(While, Repeat, For)
Esquema de recorrido
Esquema de recorrido si no sabemos a priori
el numero de elementos (iteraciones) y éste
puede ser 0
obtener/calcular primer elemento
iniciar tratamiento
WHILE no último elemento DO BEGIN
tratar elemento
obtener/calcular siguiente elemento
END;
tratamiento final
Esquema de recorrido
Esquema de recorrido si sabemos a priori el
numero elementos (iteraciones)

iniciar tratamiento
FOR primer elemento TO ultimo elemento DO
BEGIN
tratar elemento
END;
tratamiento final
Esquema de búsqueda
Problema 1. Determinar si aparece la letra ‘a’ en
una secuencia de caracteres acabada en ‘.’

BEGIN {bloque}
Read(car);
WHILE (car <> ‘.’) AND (car <> ‘a’) DO
Read(car);
esta:= car = ‘a’;
END {bloque}
Esquema de búsqueda
Se pretende localizar un elemento que
cumpla una determinada propiedad A
Es suficiente con localizar al primero de
los elementos que la cumplen
obtener/calcular posible primer elemento
iniciar tratamiento
WHILE no último elemento y no satisface A DO
obtener/calcular siguiente elemento
determinar si encontrado
Esquematización de algoritmos iterativos

A partir de los 2 esquemas básicos se


pueden construir algoritmos que consistan
en variantes más o menos complicadas de
uno de ellos o de ambos

Si se combinan ambos esquemas


podemos hablar de un esquema mixto
Esquema mixto
Problema 1. Contar el número de caracteres
anteriores a la primera aparición de la letra ‘a’ en
una secuencia de caracteres acabada en ‘.’
BEGIN {bloque}
Read(car);
num_car:= 0;
WHILE (car <> ‘.’) AND (car <> ‘a’) DO BEGIN
num_car:= num_car + 1;
Read(car);
END; {WHILE}
writeln(num_car);
END {bloque}
Esquema mixto
Problema 2. El número e se define como la suma
de la siguiente serie: 1/1! + 1/2! + 1/3! + ....
Escribe un bloque de programa que pida un
umbral de error y aproxime el número e hasta
que la diferencia entre 2 aproximaciones
sucesivas sea menor que el umbral.
Esquema mixto
BEGIN {bloque}
Readln(error);
aprox_ant:= 0;
aprox_sig:= 1;
fact:=1;
i:=1;
WHILE (aprox_sig-aprox_ant)>= error DO BEGIN
i:= i + 1;
fact:= fact * i;
aprox_ant:= aprox_sig;
aprox_sig:= aprox_ant + 1/fact
END; {WHILE}
writeln(error, aprox_sig);
END {bloque}
4.4. Complejidad de instrucciones estructuradas

Complejidad en espacio:
– las instrucciones estructuradas no
aumentan la complejidad en espacio

Complejidad en tiempo:
– reglas de cálculo de complejidad para
• instrucciones de selección
• instrucciones de iteración
Complejidad en tiempo
La complejidad en tiempo depende del valor de
ciertas variables
{n = 3} {n = 7}
WHILE n>2 DO WHILE n>2 DO
n:= n-2; n:= n-2;

complejidad: T(3)=4 complejidad: T(7)=10


Convenciones:
–T(n): Comp. en tiempo en función del valor de n
–Tc(n): Complejidad en tiempo de la condición c
–TI(n): Complejidad en tiempo de la instrucción I
Complejidad en tiempo: selección
Instrucción IF
IF c THEN
I1 Tc(n) + TI1(n) si c=true
ELSE
T(n) =
Tc(n) + TI2(n) si c=false
I2

Instrucción CASE
CASE ExpSel OF
1: I1
...
T(n) = TExpSel(n) + TIj(n)
j: Ij
... para ExpSel =j
n: In
END
Complejidad en tiempo: iteración
Instrucción FOR
– FOR j:= ExpIni TO ExpFinal DO I
– complejidad la inicialización Tinit(n)
• complejidad de evaluar ExpIni
• complejidad de evaluar ExpFinal
• complejidad de iniciar j con ExpIni: 1
• complejidad de comparar j con el valor de ExpFinal: 1
– complejidad del incremento Titer
• complejidad de incrementar/decrementar j: 1
• complejidad de comparar j con el valor de ExpFinal: 1
Complejidad en tiempo: iteración
Instrucción FOR
ExpFinal
– Complejidad: T (n ) = Tinit (n ) +  (T (n) + T )
I Iter
k = ExpIni

– Ejemplo:
6
FOR i:= 2 TO 7-1 DO T = 3 +  (TI + 2 )
k =2
k:=i;
6 6
IF k<4 THEN T = 3 +  TI +  2
l:=j k =2 k =2

ELSE T = 3 + (2 * 2 ) + (3 * 3) + (5 * 2 )


l:=j+1 T = 3 + (4 + 9 ) + 10 = 26
Complejidad en tiempo: iteración
Instrucción WHILE
– WHILE c DO I
– suponemos que el cuerpo I se ejecuta m veces
m
– complejidad: T (n ) = Tc (n ) +  (TI (n ) + Tc (n ))
k =1

– Ejemplo:
n div 2

{n0} T (n ) = 1 +  (2 + 1)
k =1
WHILE n>=2 DO
n:= n-2; T (n ) = 1 + 3 * (n div 2)
iteraciones: m = n div 2 p.e. T (5) = 7
Complejidad en tiempo: iteración
Instrucción REPEAT
– REPEAT I UNTIL c
– suponemos que el cuerpo I se ejecuta m veces
m
– complejidad: T (n ) =  (TI (n ) + Tc (n ))
k =1

– Ejemplo:
n div 2
T (n ) =  (2 + 1)
{n0}
REPEAT k =1
n:= n-2;
UNTIL n<2 T (n ) = 3 * (n div 2)
p.e. T (5) = 6
iteraciones: m = n div 2
4.4. Depuración y Corrección

Depuración

Verificación formal
– Corrección parcial de instrucciones de
selección
– Corrección parcial de instrucciones de iteración
– Terminación y Corrección total
Depuración de instrucciones estructuradas

Modos de depuración de instrucciones


estructuradas
– como una única instrucción primitiva
– como un conjunto de subinstrucciones
• selección: instrucciones de las diferentes ramas
• iteración: instrucciones del cuerpo del ciclo
Depuración de instrucciones estructuradas

Por defecto, el depurador de TurboPascal pasa


por todas las subinstrucciones de una instrucción
estructurada
Para depurar instrucciones estructuradas
completas:
– crear un punto de rotura después de la instrucción
• Menu “Debug”
• Opción “Breakpoints”
– ejecutar el programa hasta dicho punto de rotura
Verificación: Selección
Idea:
– verificar que la postcondición q se cumple
siempre, independiente de la alternativa que se
ejecute
Instrucción IF: IF C THEN I1
ELSE I2

Regla : p  C I1 q; p  C I 2 q (RIF)


 p if C then I1 else I 2  q 
Verificación: Selección
Ejemplo. Demostrar que
{true} if x  y then z:=x-y else z:= y-x {z=|x-y|}
1.- (x  y) → (x -y  0)
2.- {x -y  0} z:=x-y {x -y  0  z = x-y} AA
3.- (x -y  0  z = x-y) → (z =|x-y|)
4.- {x  y} z:=x-y {z =|x-y|} 1,2,3 RC
5.- {(x  y)} z:=y-x {z = y-x  (x  y)} AA
6.- (z = y-x  (x  y)) → (z =|x-y|)
7.- {(x  y)} z:=y-x {z =|x-y|} 5,6, RC
8.- {true} if x  y then z:=x-y else z:= y-x
{z=|x-y|} 4,7, RIF
Verificación: Selección

Instrucción IF sin rama ELSE


– verificar como un IF normal, suponiendo que
hay una instrucción vacía en la rama ELSE

Instrucción CASE
– verificar que la postcondición q se pueda
deducir en la rama de cada una de las
etiquetas si
Verificación: Iteración
La verificación de las instrucciones de
iteración se apoya en el concepto de
invariante
Invariante de ciclo:
– aserción que se cumple antes, durante, y
tras la ejecución de un ciclo
– describe la semántica del ciclo,
caracterizando el efecto de la iteración
Ejemplo: Calcular n!
BEGIN {bloque}
readln(n);
i := 0;
f := 1;
{f=i!  0in} antes
WHILE i < n DO BEGIN
durante
{f=i!  0in}
i := i + 1
f := f * i;
END; {WHILE}
{f=i!  0in ( ¬(i<n))} tras
END {bloque}
Verificación: Iteración
Idea de la verificación:
– encontrar una propiedad invariante (INV)
– probar que INV se cumple inmediatamente
antes de entrar en el ciclo
– probar que INV es conservada por el cuerpo
del ciclo
– deducir que INV se cumple inmediatamente
después de salir del ciclo
Verificación: Iteración

Instrucción WHILE:
WHILE B DO I

Regla :

INV  B I INV 
(RWH)
 INV  while B do I  INV  B 
Verificación: Ejemplo
Verificar el siguiente programa para computar el
máximo común divisor (mcd) de dos enteros
positivos
u = X  v = Y  u  0  v  0
WHILE u  v DO
IF u  v THEN
u := u − v
ELSE
v := v − u
u = mcd ( X , Y )
Verificación: Iteración
En la demostración se utilizará implícitamente que
mcd ( A, B) = mcd (B, A)
Además, se aplicarán explícitamente dos
teoremas
T1 : mcd ( A, B ) = mcd ( A − B, A) si A B
T2 : mcd ( A, A) = A
Invariante del ciclo WHILE:

mcd (u, v ) = mcd ( X ,Y )  u  0  v  0


Ejemplo: Corrección parcial de mcd
El invariante se cumple antes del ciclo
1. u = X  v = Y  u  0  v  0 →
mcd (u, v ) = mcd ( X , Y )  u  0  v  0

El invariante se conserva en el ciclo


T1
2. u  v  u  v  mcd (u, v ) = mcd ( X , Y )  u  0  v  0 →
mcd (u − v, v ) = mcd ( X , Y )  u − v  0  v  0
3. mcd (u − v, v ) = mcd ( X ,Y )  u − v  0  v  0 u := u − v
mcd (u, v ) = mcd ( X ,Y )  u  0  v  0 (AA)

4. u  v  u  v  mcd (u, v ) = mcd ( X ,Y )  u  0  v  0 u := u − v


mcd (u, v ) = mcd ( X ,Y )  u  0  v  0 (RC: 2+3)
Ejemplo: Corrección parcial de mcd
u<v T1
5. u  v  u  v  mcd (u, v ) = mcd ( X , Y )  u  0  v  0 →
mcd (u, v − u ) = mcd ( X , Y )  u  0  v − u  0

6. mcd (u, v − u ) = mcd ( X ,Y )  u  0  v − u  0 v := v − u (AA)


mcd (u, v ) = mcd ( X ,Y )  u  0  v  0
7. u  v  u  v  mcd (u, v ) = mcd ( X ,Y )  u  0  v  0 v := v − u
mcd (u, v ) = mcd ( X ,Y )  u  0  v  0 (RC: 5+6)

8. u  v  mcd (u, v ) = mcd ( X ,Y )  u  0  v  0


IF u  v THEN u := u − v ELSE v := v − u (RIF: 4+7)
mcd (u, v ) = mcd ( X , Y )  u  0  v  0
Ejemplo: Corrección parcial de mcd
Se deduce el invariante como postcondición
9. mcd (u, v ) = mcd ( X , Y )  u  0  v  0
WHILE u  v DO (RWH:8)
IF u  v THEN u := u − v ELSE v := v − u
u  v  mcd (u, v ) = mcd ( X , Y )  u  0  v  0
10. u  v  mcd (u, v ) = mcd ( X , Y )  u  0  v  0 → u = mcd ( X , Y )
T2
11. u = X  v = Y  u  0  v  0
WHILE u  v DO
IF u  v THEN u := u − v ELSE v := v − u (RCS: 1+9+10)
u = mcd ( X , Y )
Verificación: Iteración
Instrucciones REPEAT y FOR:
– se podrían definir reglas de inferencias
propias para dichas instrucciones
– como alternativa:
• transformar bucles REPEAT y FOR en bucles
WHILE con semántica equivalente
• verificar los programas transformados, que sólo
contienen bucles WHILE
Los invariantes también pueden usarse
para la construcción de ciclos
Verificación: Terminación
Corrección parcial:
– Todo programa S que comienza en un estado
que satisface p, si termina, lo hace en un
estado que satisface q
{p} S {q}

Corrección total:
– Todo programa S que comienza en un estado
que satisface p, termina en un estado que
satisface q: {p} [S] {q}
Verificación: Terminación
Terminación:
– Todo programa S que comienza en un estado que
satisface p, termina al cabo de un nº finito de
pasos
TER(p, S)
Corrección parcial y total:
– Si S no contiene iteración ni recursión (Tema 5):
{p} [S] {q} = {p} S {q}
– de lo contrario
{p} [S] {q} = {p} S {q} + TER(p,S)
Verificación: Terminación
Idea: encontrar una expresión cota que
– es una cota del nº de pasos restantes de la
iteración (en función de algún estado de
cómputo)
– demostrar que:
• inicialmente esta expresión evalúa a una cota
positiva (un número natural)
• el valor de la expresión decrece estrictamente en
cada iteración
Verificación: Terminación
Regla:
para probar TER(INV, while B do I ) hay que
encontrar una expresión cota e (formada por
variables que son modificadas por I), y
demostrar que

a) INV  B → e  N
b) INV  B  e = V  I e  V 
Verificación: Terminación
El método para la instrucción REPEAT se
obtiene de forma similar
En general se verifica la terminación,
probando que una expresión e decrece con
respecto a cualquier orden bien fundado (O,
 ), del cual (N, ) es un caso especial
Ejemplo: Corrección de mcd
Terminación del programa mcd:
– Invariante del ciclo WHILE:
mcd (u, v ) = mcd ( X ,Y )  u  0  v  0

– Expresión cota e:
max(u, v )

– Demostración:
a) e toma valores en N
u = X  v = Y  u  0  v  0  u  v → max(u, v )  0
→ max(u, v )  N
Ejemplo: Terminación de mcd
b) e decrece en cada iteración
v >0
1. INV  u  v  u  v  max(u, v ) = C → max(u − v, v )  C
2. max(u − v, v )  C u := u − v max(u, v)  C (AA)
3. INV  u  v  u  v  max(u, v) = Cu := u − v max(u, v)  C (RC: 1+2)
u >0 v>u
4. INV  u  v  u  v  max(u, v ) = C → max(u, v − u)  C
5. max(u, v − u)  C v := v − u max(u, v )  C (AA)
6. INV  u  v  u  v  max(u, v) = Cv := v − u max(u, v)  C (RC: 4+5)
7. INV  u  v  max(u, v ) = C
IF u  v THEN u := u − v ELSE v := v − u (RIF: 3+6)
max(u, v )  C

También podría gustarte