ComputacionI A

225
, COMPUTACION I Lógica, resolución de problemas, algoritmos y programas FUNDAMENTOS DE INFORMÁTICA Lógica, resolución de problemas, programas y computadoras ALLEN B. TUCKER Bowdoin College W. JAMES BRADLEY Calvin College ROBERT D. CUPPER Allegheny College DAVID K. GARNICK Bowdoin College Traducción: Manuel Ortega Ortiz de Apodaca Universidad Europea de Madrid Revisión técnica: Antonio Vaquero Sánchez Escuela Superior de Informática Universidad Complutense de Madrid FUNDAMENTOS DE PROGRAMACIÓN Algoritmos y estructura de datos (Segunda edición) LUIS JOYANES AGUILAR Departamento de Lenguajes y Sistemas Informáticos y de Ingeniería de Software Escuela Universitaria de Informática Universidad Pontificia de Salamanca en Madrid MADRID. BUENOS AIRES. CARACAS. GUATEMALA. LISBOA. MÉXICO NUEVA YORK. PANAMÁ. SAN JUAN. SANTAFÉ DE BOGOTÁ. SANTIAGO· SAO PAULO AUCKLAND. HAMBURGO • LONDRES. MILÁN. MONTREAL • NUEVA DElHI • PARís SAN FRANCISCO. SIDNEY • SINGAPUR • STo LOUIS • TOKIO. TaRaNTa

Transcript of ComputacionI A

Page 1: ComputacionI A

,

COMPUTACION ILógica, resolución de problemas,

algoritmos y programasFUNDAMENTOS DE INFORMÁTICALógica, resolución de problemas,programas y computadoras

ALLEN B. TUCKERBowdoin College

W. JAMES BRADLEYCalvin College

ROBERT D. CUPPERAllegheny College

DAVID K. GARNICKBowdoin College

Traducción:

Manuel Ortega Ortiz de ApodacaUniversidad Europea de Madrid

Revisión técnica:

Antonio Vaquero SánchezEscuela Superior de Informática

Universidad Complutense de Madrid

FUNDAMENTOS DE PROGRAMACIÓNAlgoritmos y estructura de datos(Segunda edición)

LUIS JOYANES AGUILARDepartamento de Lenguajes y Sistemas

Informáticos y de Ingeniería de Software

Escuela Universitaria de Informática

Universidad Pontificia de Salamanca en Madrid

MADRID. BUENOS AIRES. CARACAS. GUATEMALA. LISBOA. MÉXICONUEVA YORK. PANAMÁ. SAN JUAN. SANTAFÉ DE BOGOTÁ. SANTIAGO· SAO PAULO

AUCKLAND. HAMBURGO • LONDRES. MILÁN. MONTREAL • NUEVA DElHI • PARísSAN FRANCISCO. SIDNEY • SINGAPUR • STo LOUIS • TOKIO. TaRaNTa

Page 2: ComputacionI A

Prólogo\

En el pasado próximo, la Universidad Nacional Abierta ofrecía, en el curso introductorio a laComputación, contenidos programáticos que incluían elementos de la globalidad de temas quecomprende esta disciplina. Al abarcar tan amplio espectro se debilitaba el objetivo final del cur­so (resolver problemas algorítmicos con la ayuda de la' computadora digital), el cual, en térmi­nos prácticos, lo reflejaba la ponderación de los objetivos evaluables de la asignatura.

Este nuevo texto delimita los temas tratados a los estrictamente necesarios para el cabal do­minio del objetivo de aprendizaje general del curso, logrando tratar los temas de importancia conmayor claridad, extensión y profundidad. Otros temas de la disciplina son trasladados en el dise­ño curricular a un curso introductorio en Informática y a otros cursos posteriores de los ejes deComputación y Sistemas de Información de la carrera de Ingeniería de Sistemas.

El texto guía del nuevo curso, un esfuerzo editorial conjunto de la Universidad NacionalAbierta y McGraw-Hill Interamericana de Venezuela, S. A., aglutina el tratamiento de temas quevan desde conjuntos y funciones, lógica, problemas algorítmicos y su solución, hasta la codifica­ción de estas soluciones en lenguajes computacionales de alto nivel, por autores de reconocidatrayectoria en la informática y su enseñanza, como son los profesores Allen B. Tucker y DavidGarnick, del Bowdoin College; W. James Bradley, del Calvin College; Robert D. Cupper, delAllegheny College, y Luis Joyanes Aguilar, de la Universidad Pontificia de Salamanca. Los con­tenidos son selectivamente tomados de los textos Fundamentos de Informática, lógica, resoluciónde problemas, programas y computadoras, de los cuatro primeros autores, y Fundamentos deProgramación, algoritmos y estructura de datos, del último, con el objetivo de conformar un tex­to que cubra los requisitos específicos en términos de contenidos, del nuevo Plan de Curso de laasignatura Computación I de la carrera de Ingeniería de Sistemas de la Universidad NacionalAbierta, diseñado por los profesores Edgar Blanco, NelIy Mendoza y Juana Marrero como Pro­yecto Especial del área de Actualización de Cursos del Vicerrectorado Académico de la mencio­nada institución.

DR. EOGAR BLANCO

ING. NELLY MENOOZA

ING. JUANA MARRERO

UNIVERSIDAD NACIONAL ABIERTAEstudios Profesionales IComputación I (301)

Diseño de InstrucciónEdgar Blanco (UNA)Juana Marrero (UNA)NelIy Mendoza (UNA)

Especialista en evaluaciónCarmen Velásquez (UNA)

Coordinador de Ingenieríade SistemasDr. Luis Márquez Gordones

v

Page 3: ComputacionI A

UNIVERSIDAD NACIONAL ABIERTA

N° de Rfig¡~tl'O .....2.Q.,§.9..5.../t.:.f¿..-::t-~Centro de ReQursos Múltiples

e.t. METROPOLITANO

COMPUTACIÓN l. Lógica, resolución de problemas, algoritmos y programas

No está permitida la reproducción total o parcial de este libro, ni su tratamiento infor­mático, ni la transmisión de ninguna forma o por cualquier medio, ya sea electrónico,mecánico, por fotocopia, por registro u otros métodos, sin el permiso previo y por escri­to de los titulares del Copyright.

DERECHOS RESERVADOS © 2000, respecto a la primera edición en español, porMcGRAW-HILL/INTERAMERICANA DE ESPAÑA, S. A. U.Edificio Valrealty, 1." plantaBasauri, 1728023 Aravaca (Madrid)

ISBN: 84-481-2545-2Depósito legal: M. 40.896-1999

Compilado de las siguientes obras:Allen B. Tucker; W. James Bradley; Robert D. Cupper, y David K. Garnick.FUNDAMENTOS DE INFORMÁTICA. Lógica, resolución de problemas, programasy computadoras.ISBN: 84-481-1875-8DERECHOS RESERVADOS © 1994, respecto a la primera edición en español. porMcGRAW-HILUINTERAMERICANA DE ESPAÑA, S. A. U.

Luis Joyanes Aguilar. FUNDAMENTOS DE PROGRAMACIÓN. Algoritmos y estruc­tura de datos (Segunda edición).ISBN: 84-481-0603-2DERECHOS RESERVADOS © 1996, respecto a la segunda edición en español, porMcGRAW-H1LUINTERAMERICANA DE ESPAÑA, S. A. U.

Esta obra se terminó deImprimir en junio del 2005Litográfica IngramexCenteno Núm. 162 - 1Col. Granjas EsmeraldaDelegación Iztapalapa09810 México, D.F.

Page 4: ComputacionI A

I

Nota del editor

COMPUTACIÓN l. Lógica. resolución de problemas, algoritmos y programas es una obra naci­da de la unión de dos textos para atender a las necesidades de la Universidad Nacional Abierta.Dichos textos son los siguientes:

• Tucker, A. B.; Bradley, W. 1.; Cupper, R. D., YGarnick, D. K.: Fundamentos de Informática.Lógica, resolución de problemas, programas y computadoras. Madrid, McGraw-Hill. 1994.

• Joyanes Aguilar, L.: Fundamentos de programación. Algoritmos y estructura de datos. Madrid,McGraw-Hill. 1996.

Se ha respetado el formato de ambas obras, de ahí que el tamaño y tipos de letra son distin­tos. Asimismo, se ha mantenido la numeración de los capítulos de cada libro. Por ello, COMPU­TACIÓN I. Lógica. resolución de problemas, algoritmos y programas comienza en el Capítulo 2,continúa hasta el Capítulo 6 (correspondientes a la obra de Tucker y otros) y finaliza en los Ca­pítulos 1 a 5 (pertenecientes al texto de Joyanes).

Madrid. octubre de 1999

vi

Page 5: ComputacionI A

Contenido

Prólogo .Nota del editor .

Capítulo 2. Conjuntos y funciones .2.1. Conjuntos .

2.1.1. Relaciones entre conjuntos: los diagramas de Venn .2.1.2. Variables tipos y estados .2.1.3. Operaciones entre conjuntos ..2.1.4. Propiedades de las operaciones entre conjuntos ..2).5 Conjuntos de cadenas de caracteres .EJercIcIos .

2.2. Funciones .2.2.1. Conceptos básicos .2.2.2. Funciones continuas y discretas .2.2.3. Formas alternativas de definir funciones .Ejercicios .2.2.4. Funciones uno-a-uno y funciones inversas .2.2.5. Funciones booleanas, enteras, exponenciales y logarítmicas ..2..2.6.. . Series finitas y funciones relacionadas .EJerCICiOS .

2.3. Sumario .Ejercicios .

Capítulo 3. Lógica : .3.1. Lógica proposicional .

3.1.1. Representaciones de frases en castellano utilizando la lógica proposicional .3.1.2. Evaluación de proposiciones: Tablas de verdad .

~j~:ciciOf~~~·~·I.~.~.~~.~ .. :::::::;::;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::3.2. Razonamiento con proposIcIOnes .

3.2.1. Equivalencia .3.2.2. Propiedades de la equivalencia ..3.2.3. Reglas de inferencia: La idea de demostración .3.2.4. Estrategias de demostración .3..2.5 Resolución de problemas de la vida real .EJercIcIos .

3.3. Lógica de predicados .3.3.1. Los cuantificadores universal y existencial ..3.3.2. Otros cuantificadores .3.3.3. Variables libres y ligadas .

3.4. Predicados y programas .3.4.1. El estado de un cálculo ..3.4.2. Cuantificadores y programación: bucles .

3.5. Razonamiento con predicados: prueba por inducción ..

3.6. ~j::::~~~s.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::~::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::Capítulo 4. Problemas algorítmicos y su solución .

4.1. ~I;r~~~~o.~.~.:.~~~~~.~.~.~ .. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::4.2. Definición de problemas y descripción de algoritmos .

4.2.1. Los estados inicial y final de un algoritmo: entrada y salida .4.2.2. Los estados intermedios de un cálculo: introducción de variables .

vvi

I2448

10JI1315161820222428343338384141444751525454555861656669717676777778818686899093939395

vii

Page 6: ComputacionI A

viii Contenido

4.3.

4.4.

4.5.Capítulo 5.

5.1.

5.2.

5.3.

5.4.

5.5.

5.6.

Capítulo 6.6.1.

6.2.6.3.

6.4.

6.5.

6.6.

Capítulo 1.1.1.

~~e:~~~j~S ~ig~;ft~'i'~~"::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::4.3.1. Sintaxis y semántica .4.3.2. Repetición y bucles: inicialización, invarianza y terminación .4 ..3.3 Tres visiones de la misma solución al problema ..EjercIcIos ,Más problemas algorítmicos ..4.4.1. Cálculo de a" ..4.4.2. Contar palabras de un texto .

I 4.4.3.. . Representación del problema de Las Tres-en-Raya ..EjercIcIOs .Resumen .Resolución de problemas algorítmicos .Necesitamos una metodología .5.1.1. Generalidades sobre el método MAPS ..Construcción de software para su reutilización: la rutina ..5.2.1. Encapsulamiento de rutinas para la reutilización. Abstracción procedimental ..5.2.2. Identificación de rutinas nuevas y definición de sus abstracciones ..5.2.3. Funciones recursivas: Una alternativa a la repetición ..5.2.4. Aprendizaje de rutinas ya existentes: Bibliotecas y características de los lenguajes5.2.5. Selección y reutilización de tipos de datos y estructuras ..5.2.6. A.rr~~s de ,cadenas de carac~eres ..5.2.7 TlplÍlcaclon fuerte y coerclOn .EjerCICIos .Resolución de un problema utilizando la metodología MAPS ..5.3.1. El diálogo ..5.3.2. Las especificaciones .

t~:c·iciO;a..~.~.~~~~~~~.:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::Definiciones de abstracciones: unificación de rutinas viejas con ideas nuevas ..5.4.1. Reutilización de rutinas ..5.4.2. Utilización de la creatividad para diseñar nuevas rutinas ..5.4.3. Utilización del conocimiento del dominio en el diseño de rutinas nuevas .Terminación del caso de estudio ..5.5.1. Coditicación ..5.5.2. Prueba y veriticación ..5.5.3. Presentación .Resumen .Ejercicios .Robustez y prueba de los algoritmos .

g~~~~~~~n..~..~~~~~.~e.~ .. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::Resolución de problemas de procesamiento de texto, utilizando MAPS: Criptografía ..R~sol.u~ión de problemas gráticos utilizando MAPS: el Juego de la Vida .EjerCICIOs .Garantía de la robustez. Diseño de casos de prueba ..6.4.1. Ejemplo: Prueba de un procedimiento o función completos ..6.4.2. Ejemplo: Prueba de un programa completo .Garantía de corrección: verificación de programas ..6.5.1. Tableau de demostración .6.5.2. La regla de inferencia de la asignación ..6.5.3. Reutilización de las reglas de inferencia de la lógica .6.5.4. Reglas para las condicionales ..6.5.5. Verificación de bucles .6.5.6. Verificación formal frente a verificación informal de programas ..Resumen ..Ejercicios .Algoritmos y programas ..Los sistemas de procesamiento de la información ..

9798

100103108111112113116121126130131131132134134140144146147149150152156156158159161162163166167169169171171173174177178182182187196196197202203203206209209212216217218221222

Page 7: ComputacionI A

Contenido

1.2. Concepto de algoritmo .1.2.1. Características de los algoritmos .

1.3. Los lenguajes de programación .1.3.1. Instrucciones a la computadora .1.3.2. Lenguajes máquina .1.3.3. Lenguajes de bajo nivel .1.304. Lenguajes de alto nivel .1.3.5. Traductores de lenguaje .

\ 1.3.5.1. Intérpretes ..1.3.5.2. Compiladores .

1.3.6. La compilación y sus fases ..lA. Datos, tipos de datos y operaciones primitivas ..

104.1 . Datos numéricos .104.2. Datos lógicos (booleanos) .104.3. Datos tipo carácter y tipo cadena .

1.5. Constantes y variables .1.6. Expresiones .

1.6.1. Expresiones aritméticas ..1.6.1.1. Reglas de prioridad .

1.6.2. Expresiones lógicas (booleanas) .1.6.2. l. Operadores de relación ..1.6.2.2. Operadores lógicos ..

. 1.?2.3. Prioridad de los operadores en las expresiones lógicas ..1.7. FunClOnes mternas .

1.8. T.~~~era~~~~=c~~~~:~~~ti~~':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::1.8.2. Asignación lógica .1.8.3. Asignación de cadenas de caracteres ..1.804. Conversión de tipo ..

1.9. Entrada y salida de información ..

~j~t;~t~¡':e~.~~.~~~.~.~~.~.~~~~~ ..~~.~~~~~~~ .. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::Capítulo 2. La resolución de problemas con computadoras y las herramientas de programación .

2.1. La resolución de problemas .2.2. Análisis del problema .2.3. Diseño del algoritmo .

2.3.1. Escritura inicial del algoritmo .204. Resolución del problema mediante computadora .2.5. Representación gráfica de los algoritmos .

2.5.1. Diagramas de flujo ..2.6. Diagramas de Nassi-Schneiderman (N-S) .2.7. Pseudocódigo .A.ctivid.ades de programación resueltas .EJercIcIOs .

Capítulo 3. Estructura general de un programa .3.1. Concepto de un programa .3.2. Partes constitutivas de un programa .3.3. Instrucciones y tipos de instrucciones .304. Tipos de instrucciones .

304.1. Instrucciones de asignación .304.2. Instrucciones de lectura de datos (entrada) .304.3. Instrucciones de escritura de resultados (salida) .304.4. Instrucciones de bifurcación .

3.5. Elementos básicos de un programa .3.5.1. Bucles ..3.5.2. Contadores .3.5.3. Acumulador .3.504. Decisión o selección .3.5.5. Interruptores .

ix

224225226227227228229230230231231233233235235236237238240242242244245246247248249249249251251257259260260261263265266266276278279284287287288289290290291292292293294296299300301

Page 8: ComputacionI A

x Contenido

3.6. Escritura de algoritmos/programas 304

3.6.1. Cabecera del programa o algoritmo 304

3.6.2. Declaración de variables 304

3.6.3. Declaración de constantes numéricas 305

3.6.4. Declaración de constantes y variables carácter 305

3.6.5. Comentarios 306

3.6.6. Estilo de escritura de algoritmos/programas 307

A~\Ív~d.ades de programación resueltas . 308

EjercIcIOs313

Capítulo 4. Introducción a la programación estructurada 315

4. l. Técnicas de programación 316

4.2. Programación modular 316

4.2.1. Tamaño de los módulos 317

4.2.2. Implementación de los módulos 318

4.3. Programación estructurada 319

4.3.1. Recursos abstractos 319

4.3.2. Diseño descendente (top-down) 319

4.3.3. Teorema de la programación estructurada: estructuras básicas 320

4.4. Estructura secuencial 320

4.5. Estructuras selectivas 324

4.5.1. Alternativa simple (si-entonces / if-then) 324

4.5.2. Alternativa doble (si-entonces-si_no / if-then-else) 325

4.5.3. Alternat.i~a múltiple (según-sea, caso de / case) 331

4.6. Estructuras repettttvas 337

4.6.1 . Estructura mientras (<<while») 340

4.6.2. Estructura repetir (<<repeab» 345

4.6.3. Estructura desde/para (<<for») 348

4.6.4. Salidas internas de los bucles 352

4.7. Estructuras de decisión anidadas 358

4.8. Estructuras repetitivas anidadas 362

4.9. La instrucción ir_a (<<goto») 364

A.ctiv.i~ades de programación resueltas 365

EjercIcIOs380

Referencias bibliográficas381

Capítulo 5. Subprogramas (subalgoritmos): procedimientos y funciones 383

5.1. Introducción a subalgoritmos o subprogramas 384

5.2. Funciones386

5.2.1. Declaración de funciones 387

5.2.2. Invocación a las funciones 388

5.3. Procedimientos (subrutinas) 393

~.3.1. Sustitución de argumentos/parámetros 394

5.4. Ambito: variables locales y globales 398

5.5. Comunicación con subprogramas: pa<¡o de parámetros 401

5.5.1. Paso de parámetros 402

5.5.2. Paso por valor 403

5.5.3. Paso por referencia 404

5.5.4. Comparaciones de los métodos de paso de parámetros 405

5.5.5: Síntesis de. la. transmisión de ~arámetros407

5.6. FuncIOnes y procedimientos como parametros 410

5.7. Los efectos laterales 412

5.7.1. En procedimientos 412

5.7.2. En funciones 413

5.8. Recursión (recursividad) 414

A.ctiv.id.ades de programación resueltas 417

EjercIcIos422

Page 9: ComputacionI A

CAPíTULO 2CONJUNTOS Y FUNCIONES

En este capítulo introducimos las nociones matemáticas básicas sobre los con­juntos y las funciones, junto con su notación. Estas nociones son fundamenta­les para la disciplina de la informática. Más adelante veremos cómo los con­juntos y funciones se entremezclan con las nociones claves de la informática ysu aplicación. Estos conceptos y notaciones se utilizarán a lo largo de todo eltexto. (Algunos lectores encontrarán estas materias familiares. Sin embargo,esta presentación tiene como objetivo reorientar estas ideas, quizá familiares,hacia aquellas partes de la informática en que se utilizan.)

¿En qué forma se relacionan los conjuntos y funciones con la informática?Generalmente, podemos considerar un programa para una computadora,

como la realización de una función o como una correspondencia entre dosconjuntos: la entrada del programa que representa un elemento particular deldominio de la función, y la salida que representa el resultado de aplicar lafunción a dicha entrada. Introduciremos esta idea en este capítulo, ejercitándo­la en las prácticas de laboratorio que le acompañan. En los Capítulos 4, 5 Y6afianzaremos este concepto, ejercitándonos en la programación y mediante ladiscusión exhaustiva de programas. Los conjuntos y las funciones están tam­bién íntimamente relacionados con la propia computadora como dispositivo.Así, podemos decir que una computadora es una máquina que realiza una fun­ción determinada, cuando ejecuta un programa que realiza, paso a paso, dichafunción. También se insiste en esta idea en las prácticas de laboratorio queacompañan a este capítulo. También, en el Capítulo 7, insistiremos sobre esteconcepto al estudiar la estructura de las computadoras.

Algunos conjuntos son especialmente importantes para la programación ypara las computadoras. Por ejemplo, los números enteros y reales, los valoresbooleanos, los caracteres que encontramos en el teclado de la computadora (elconjunto de caracteres ASCII) y las «cadenas» * construidas con esos caracte-

* N. del T.: De las diversas traducciones que suelen realizarse de la palabra inglesa «string»,hemos preferido la acepción «cadena» o «cadena de caracteres», que serán utilizadas de formaindistinta.

Pedro Pacheco
Highlight
Page 10: ComputacionI A

2 Computación l. Lógica, resolución de problemas, algoritmos y programas

res, representan conjuntos que son esenciales para la informática; todos ellos

están incluidos en los lenguajes de programación y las computadoras moder­

nas. En este capítulo estudiaremos la correspondencia que existe en programa­

ción entre estos conjuntos y el concepto de «tipo~~. Algunas funciones resultan

de vital importancia en programación. Entre ellas se incluyen las funciones

discretas, la{> funciones exponenciales y logarítmicas, y funciones que se repre­

sentan mediante series finitas.Estudiaremos todas ellas en este capítulo, poniendo especial interés en des­

tacar por qué son importantes para la informática.

2.1. CONJUNTOS

En la vida cotidiana son corrientes las colecciones de objetos o números.

Podemos pensar en la colección de personas de nuestra clase, la colección de

dígitos y letras de la matrícula de un automóvil, o la colección de los nombres

de aerolíneas que vuelan al aeropuerto ü'Hare de Chicago. Estas colecciones,

en el lenguaje matemático, reciben el nombre de conjuntos. Una descripción

más precisa la podemos realizar de la forma siguiente.

Definición. Un conjunto es cualquier colección bien definida de objetos. A

menudo, los objetos que forman un conjunto comparten alguna caracterís­

tica en común. Un elemento de un conjunto es cualquiera de los objetos

que lo constituyen. Se dice que un elemento de un conjunto pertenece a

dicho conjunto. Si S es un conjunto que contiene el elemento x, para expre­

sar que x pertenece a S escribiremos x E S.

Una de las formas de describir un conjunto es encerrando los elementos que lo

componen entre corchetes {y}. Por ejemplo, el conjunto de los días laborables

de la semana se puede describir como:

{Lunes, Martes, Miércoles, Jueves, Viernes}

Las Ecuaciones 2.1 a 2.7 son otros ejemplos de definición de conjuntos:

{O, 1, 2, 3,4, 5, 6, 7, 8, 9} es el conjunto cuyos elementos son los (2.1)

dígitos decimales.

{O, 1} es el conjunto de dígitos que se utiliza para escribir números (2.2)

binarios.

{a, b, c, ..., z} es el conjunto de letras minúsculas del alfabeto. (2.3)

{+, -, *, /} es el conjunto de las cuatro operaciones aritméticas (2.4)

más importantes.

{1, 2, ... , 100} es el conjunto de números enteros del 1 al 100, ambos (2.5)

inclusive.

Page 11: ComputacionI A

Conjuntos y funciones 3

Notación. Obsérvese la utilización de la coma y los puntos suspensivos.Las comas separan elementos individuales del conjunto, mientras que lospuntos suspensivos (...) denotan la repetición de un patrón claramente esta­blecido, como ocurre en las Ecuaciones 2.3 y 2.5.

También podemos definir un conjunto, estableciendo las propiedades que de­btln satisfacer todos sus elementos, por ejemplo:

{xix es entero y 1 ~ x ~ lOO} (2.6)

Esta notación requiere una variable al comienzo, una barra vertical y, al final,una descripción de los elementos. Con esta notación, la Ecuación 2.6 se lee «elconjunto de los x tales que x es un número entero entre 1 y 100, ambosinclusive». Claramente, este ejemplo describe el mismo conjunto de la Ecua­ción 2.5. La Ecuación 2.7 es otro ejemplo de esta alternativa para la descrip­ción de conjuntos:

{plp es un polinomio de grado 2} (2.7)

Ejemplos de elementos del conjunto definido por la Ecuación 2.7 son los si­guientes:

x 2 + 2x + 1 .01n2 - 100n - 3 SOOOy2 - 67

Algunos conjuntos tienen un número finito de elementos, mientras que otrostienen un número infinito de ellos. Por ejemplo, los conjuntos definidos por lasEcuaciones 2.1 a 2.6 son finitos, mientras el conjunto definido por la Ecua­ción 2.7 es infinito.

Definición. Se denomina cardinalidad de un conjunto al número de ele­mentos del que consta. El conjunto vacío es aquel que no contiene ningúnelemento y, por tanto, su cardinalidad es O. El conjunto vacío se simbolizapor {} o por </>.

Por ejemplo, la cardinalidad del conjunto definido por la Ecuación 2.3 es 26.Existen cuatro conjuntos que tienen una importancia especial, tanto para lainformática como para las matemáticas:

N

Z

R

{O, 1, 2, 3, ...}

{... , -3, -2, -1, 0,1,2,3, oo.}

{xl- infinito < x < + infinito}

{O, 1, 2, ..., n - 1}

número naturales

los enteros

los números reales

los enteros módulos n

Page 12: ComputacionI A

4 Computación ,. Lógica, resolución de problemas, algoritmos y programas

Los tres primeros son infinitos, mientras que el último es finito y tiene cardina­lidad n. Por ejemplo, el conjunto Z2 = {O, 1} tiene cardinalidad 2; el conjuntoZ10 = {O, 1, ..., 9} tiene cardinalidad 10.

2.1.1. Relaciones entre conjuntos: los diagramas de Venn

El orden en 'que aparecen enumerados los elementos de un conjunto no tieneespecial relevancia; además, la duplicidad de elementos es redundante. Es decir,{a, b, e} y {b, a, e, a} representan el mismo conjunto.

Es bastante habitual que los elementos de un conjunto sean también miem­bros de otro diferentes. Por ejemplo, todos los elementos del conjunto V == {a, e, i, o, u} son también elementos del conjunto L = {a, b, '00' z}. Ladefinición siguiente sirve para formalizar estos conceptos:

Definición. Si dos conjuntos A y B contienen los mismos elementos, se diceque son iguales y se simboliza escribiendo A = B. Si todos y cada uno delos elementos de A también lo son de B, y se simboliza por A e B. Si A esun subconjunto de B, decimos que B es un superconjunto de A y se simbolizapor A ::J B. Si se verifica que A i= B, Yademás A e B, entonces se dice queA es un subconjunto propio de B. Si todos los elementos de un conjunto o deuna colección de conjuntos se obtienen de un conjunto común, a este con­junto se le denomina conjunto universal.

Obsérvese la diferencia que existe entre elemento y subconjunto. Por ejemplo,sea A = {O, 1, 2, 3, 4, 5, 6, 7}. Entonces el dígito O es un elemento de A(simbolizado por OE A), yel conjunto {O} es un subconjunto de A (y se denotapor {O} e A). Sería incorrecto decir que Oes un subconjunto de A, puesto queno es un conjunto. De forma análoga, sería incorrecto decir que {O} es unelemento de A.

Frecuentemente, se representan los conjuntos utilizando diagramas deVenn (véase Fig. 2.1). Un diagrama de Venn es un dibujo en el que los conjun­tos se representan como círculos etiquetados, dentro de una caja rectangular,que representa el conjunto universal del que se dibujan los elementos.

2.1.2. Variables tipos y estados

Dos nociones fundamentales de la informática son las de variable y estado.Una variable es un mecanismo de notación que se toma prestado de las mate­máticas, que permite representar ideas complejas mediante un simple símbolo,y que aporta concisión y precisión. Frecuentemente, leemos frases como: «Re­presentemos mediante x una letra del alfabeto». A continuación, podemosutilizar el símbolo x y entender de forma precisa lo que significa, puesto que seha definido anteriormente el símbolo, para representar la noción de «cualquierelemento del conjunto L = {a, b, oo., z}. Cuando se utiliza de esta forma, xrecibe el nombre de «variable», puesto que su valor puede variar entre diversasalternativas (26 para ser exactos).

Page 13: ComputacionI A

Conjuntos y funciones 5

al

bl

Figura 2.1. Diagramas de Venn. a) Dos conjuntos A y B que puedentener varios elementos comunes. b) La relación A e B.

Definición. Una variable es un símbolo que se asocia con un valor simple,que de hecho puede ser un elemento de un conjunto bien definido. A lolargo de los pasos que implican un cálculo, el valor de una variable puedecambiar de ser uno de los miembros del conjunto a ser otro distinto. Elconjunto sobre el que se define una variable recibe el nombre de tipo de lavariable.

Por ejemplo, la variable x que se ha definido anteriormente es del tipo L (o demanera informal, del tipo letra).

Otra noción fundamental en la informática es la de estado. Por ejemplo, unprograma que juegue al ajedrez tiene muchos estados posibles -uno por cadaposible colocación de las piezas sobre el tablero-o Un programa gráfico debecontrolar millones de «pixels» [puntos de una pantalla de un monitor, cadauno de los cuales puede estar iluminado (on) o no iluminado (ofl)]. Su estado,en cada momento, es el valor on u off que tienen el millón de pixels. La nociónde estado se puede definir más formalmente de la forma siguiente:

Definición. Supongamos que tenemos una lista de variables Xl' X 2' .oo, X n

cuyos tipos están definidos por los conjuntos 51' 52' oo., Sm respectivamente.

Page 14: ComputacionI A

6 Computación l. Lógica, resolución de problemas, algoritmos y programas

Supóngase que el valor de Xl es SI E SI' el valor de X2 es S2 E S2' y así

sucesivamente. Entonces se dice que la expresión

representa el estado de las variables xl' X 2 , ... , X w El conjunto de todos los

estados postbles de Xl' X 2, ... , Xn recibe el nombre espacio de estados de esas

variables.

Esta importante noción se ilustra en los Ejemplos del 2.1 al 2.3:

Ejemplo 2.1. Supongamos que un programa de computadora tiene dos

variables i y j, utilizadas como contadores. Ambas tienen como tipo el

conjunto de los números naturales. El estado inicial del programa podría

ser:

i=O y j=O

Un estado posterior podría ser

i=5 Y j=6

Ejemplo 2.2. Si los pixels controlados por un programa son Xl' X 2' ...,

XIOOOOOO, un estado de ese programa tendría 1 millón de entradas, una por

cada variable. Por ejemplo, la expresión

Xl = on y X2 = off y

describe un posible estado del programa.

y XIOOOOOO on

Ejemplo 2.3. Considérese un programa con tres variables, las tres del tipo

rea l (la analogía en programación al conjunto R). Tres posibles estados

de este programa son:

X O e y 0, junto con z = °X -3,1 e y J2 junto con z = 1

-1n. 1789X = e y "2 Junto con z

Frecuentemente, es de gran ayuda visualizar el estado de un programa,

como puntos del espacio. Por ejemplo, los puntos de la Figura 2.2 están repre­

sentados los dos estados del Ejemplo 2.1. La gráfica tridimensional de la Figu­

ra 2.2b representa el espacio estado del Ejemplo 2.3, donde se ha marcado el

punto correspondiente a uno de los estados del programa. Cuando en un

programa las variables cambian de estado, el efecto que se produce es como si

nos desplazáramos de un punto a otro del espacio de estados.

Page 15: ComputacionI A

2 3 4 5 6

a)

7 ~""---r-..---r---..-....-....,

61--+--+......,f-+--+~r-;

51--+--+......,f-+--+-+--I

41--t--+-+-+-+-+--;

31--+--+""",'--+--+-+--1

21-+--+---1'--+--+-+--1

o t-Jf-+-+-+--+-t-+--- 1 L..-.J----L_.1.--L---J,_.L---.J

-1 Oz

Conjuntos y funciones 7

y

.;.- x

b)

Figura 2.2. Representación gráfica del estado de un programa.al Dos estados del espacio de estados del Ejemplo 2.1. bl Un

estado del espacio de estados del Ejemplo 2.3.

Considérese un programa con tres variables reales z, x e y (variable rea lsignifica lo mismo que variable del tipo rea l). Supóngase que el programacontiene una instrucción de la forma

x:= 1.0

Esta instrucción asigna el valor de 1.0 a la variable x. Si no se ha realizadoninguna restricción sobre las otras dos variables z e y, todo el plano x = 1 es elconjunto de posibles estados de este programa, después de que se ejecute laasignación (véase la Figura 2.3).

y

/1/ I

IIII

;-+----x

z

Figura 2.3. El estado x = 1 en un programacon tres variables reales z, x e y.

Page 16: ComputacionI A

8 Computación l. Lógica, resolución de problemas, algoritmos y programas

2.1.3. Operaciones entre conjuntos

Considérense los conjuntos siguientes:

s {O, 1, 01, 10, 11, OO}T {l, 10, 100, 1000, 10000}

\

Los números 1 y 10 son los únicos elementos que pertenecen a ambos conjun­tos, pero existen entre S y T otros nueve elementos diferentes. Los conceptos deintersección, unión y diferencia de conjuntos nos ayudan a describir en diferen­tes maneras la existencia de elementos comunes entre conjuntos.

Definición. Sean A y B dos conjuntos. La unión de A y B simbolizada porA u B, es aquel conjunto cuyos elementos pertenecen como mínimo a unode los dos conjuntos, A o B. La intersección de A y B, simbolizada por A (\ B,es el conjunto que incluye aquellos elementos que pertenecen tanto a A comoa B. La diferencia (o complemento relativo) de A y B, simbolizado por A \ B, esel conjunto que contiene aquellos elementos que están en A, pero no en B.

La Figura 2.4 representa tres diagramas de Venn, en los que las áreassombreadas representan la unión, la intersección y la diferencia.

b)

e)

Figura 2.4. Diagramas de Venn: a) Unión. b) Intersección. e) Diferencia de dosconjuntos A y 8.

Page 17: ComputacionI A

Conjuntos V funciones 9

Es posible escribir algunos ejemplos adicionales, utilizando la notación deconjuntos. Sean a = {1, 3, 5, 7, 9}, YB = {- 3, - 1, 1, 3, 5}. Las relacionessiguientes son ciertas:

AnBA u B

A \ B

{1, 3, 5}{-3, -1,1,3,5,7, 9}p, 9}

Como ejemplo adicional, supóngase que

A = {plp es un polinomio de la forma n2 + bn, donde b es una constante real}B = {plp es un polinomio de la forma n 2 + e, donde e es una constante real}

Dos posibles elementos del conjunto A serían n2 + n y n2 + 4,5n, mientras quedel B serían n2

- 3 Yn2 + 7. Las siguientes relaciones son ciertas:

AnBAuB

A \ B

{n2}

{plp es un polinomio de la forma n2 + bn + e,donde b = O o e = O}

{plp es un polinomio de la forma n2 + bn, donde b "# O}

El conjunto vacío <p es extremadamente útil. Por ejemplo, si e es el conjun­to de consonantes (excluida la y), y V el conjunto de vocales (incluida la y),entonces e n V no contiene elementos.

Definición. Decimos que dos conjuntos son disjuntos si su intersección esel conjunto vacío.

Definición. El complementario de un conjunto S es aquel conjunto Si alque pertenecen todos los elementos del conjunto universal U, que no per­tenecen aS.

Por ejemplo, si e y S representan el conjunto de consonantes y vocales, respec­tivamente, y U es el alfabeto completo, entonces C' = V Y V' = C. Es decir,todas las letras que no son consonantes son vocales y viceversa. (Se ha supues­to que la letra y es una vocal). La Figura 2.5 ilustra los conceptos de conjuntosdisjuntos y complementarios utilizando diagramas de Venn.

Ejemplo 2.4. Supongamos que x e y son enteros. Sea S el espacio deestados compuesto por todos los posibles pares de enteros (x, y). Si defini­mos los conjuntos A = {(x, y)lx ;?; Oe y ;?; O}, YB = {(x, y)lx < Oe y < O},entonces A y B son disjuntos. Esto se ilustra en la Figura 2.6, donde lasáreas sombreadas representan los conjuntos A y B. Obsérvese que B "# A'puesto que A' = {(x, y Jlx < Oo y < O}.

Page 18: ComputacionI A

10 Computación l. Lógica, resolución de problemas, algoritmos y programas

al bl

Figura 2.5. Representación mediante diagramas de Venn de:al Conjuntos disjuntos. bl Conjuntos complementarios.

x

Figura 2.6. Conjuntos disjuntos.

2.1.4. Propiedades de las operaciones entre conjuntos

Las operaciones aritméticas entre números tienen determinadas propiedades,como asociatividad, conmutatividad, inversa, y así sucesivamente. Hacemosuso de estas propiedades, de forma casi automática, cuando simplificamosecuaciones algebraicas. Los conjuntos y sus operaciones tienen propiedadessimilares, y las podemos utilizar para simplificar operaciones complejas entreconjuntos. Las principales propiedades de las operaciones entre conjuntos seresumen en la Tabla 2.1.

Page 19: ComputacionI A

Conjuntos y funciones 11

Tabla 2.1. Propiedades y operaciones de los conjuntos. (A y B son conjuntos;U es el conjunto universal sobre el que están definidos A y B)

Conmutatividad

AnB==BnAAuB==BuA

\ Asociatividad

A n (B n C) == (A n B) n CA u (B u C) == (A u B) u C

Distributividad

A n (B u C) == (A n B) u (A n C)A u (B n C) == (A u B) n (A u C)

Leyes de Morgan

(A n B)' == A' u B '(A u B)' == A' n B'

Propiedad de la negación

(A')' == A

Ley de exclusión del término medio

A u A' == U

Ley de la contradicción

A n A' == <p

u -simplificación

A uA == AAu<p==AAuV==V

n-simplificación

A nA == AAnV==AAn<p==<p

Complementariedad

V' <p<P' == V

2.1.5. Conjuntos de cadenas de caracteres

El tipo s tri ng (cadena de caracteres) * es muy importante en informática.Informalmente, puede definirse una «cadena» como una secuencia de elemen­tos contiguos, pertenecientes todos a un conjunto universal conocido comoalfabeto. A continuación, se pueden ver algunos ejemplos de conjuntos cuyoselementos son cadenas de caracteres.

Ejemplo 2.5. El conjunto {aa, ab, ba, bb} es el conjunto de todaslas posibles cadenas de dos elementos, construidas a partir del alfabeto{a, b}.

* N. del T.: El tipo string es un tipo característico de la mayoría de los lenguajes deprogramación modernos. Sin embargo, al tratarse de un capítulo dedicado a los conjuntos, tradu­ciremos el término string al castellano. En capítulos posteriores, en los que aparece el tipo comoperteneciente a un lenguaje de programación, dejaremos el término sin traducir.

Page 20: ComputacionI A

12 Computación l. Lógica, resolución de problemas, algoritmos y programas

Ejemplo 2.6. M = {abe, acb, bae, bca, eab, eba} es el conjuntoformado por todas las posibles colocaciones o permutaciones de las tresletras a, b Y e. Obsérvese que existen seis permutaciones distintas.

Ejemplo 2.7. S = {O, 1,01,001, 100, 0100} es un conjunto de cadenas delalfabeto {O, 1}. Existen otras muchas cadenas obtenidas de este alfabeto,tales como {l, 10, 100, 1000, 10000}, Ylos propios {O, 1}. Es posible estable­cer restricc'iones a las cadenas. Por ejemplo, el conjunto {O, 1,01, 10, 11, OO}es el conjunto de todas las cadenas del alfabeto {O, 1} que tienen longitud1 ó 2.

Ejemplo 2.8. F = {abed, abdc, aebd, aedb, adbe, adeb, baed,bade, bead, beda, bdae, bdea, eabd, eadb, ebad, ebda,edab, edba, dabe, daeb, dbae, dbea, deab, deba} es el conjun­to de todas las permutaciones de las letras a, b y c. Esto puede escribirsealternativamente como F = {plp es una permutación de abed}. Obsérveseque existen 24 permutaciones distintas.

Ejemplo 2.9. Si A = {sls es una cadena sobre {O, 1} que comienza por 1},entonces A' = {E} U {sls es una cadena sobre {O, 1} que comienza por 1}.En este caso, el símbolo E simboliza la cadena vacía que no contiene ningúncarácter. La notación {E} significa «el conjunto que tiene un solo elemen­to», que es la cadena vacía. El conjunto vacío <p, por el contrario, nocontiene ninguna cadena.

Ejemplo 2.10. Sea D el conjunto formado por todas las permutaciones deabed, que terminan en d. Entonces D = { abed, aebd, bacd, bead,cabd, ebad}. Si N = {plp es una permutación de abed}, entonces D esun subconjunto propio de N, por lo que la intersección de D y N es elpropio conjunto D y la unión entre D y N es N.

Ejemplo 2.11. Sea U = {ulu es cualquier cadena sobre el alfabeto {O, 1},incluida la cadena vacía E}. Entonces U es el conjunto universal de variosconjuntos definidos sobre el mismo alfabeto, tales como S = {E, 0,1,00,01,10, 11} YT = {O, 01, 001, 0001, oO.}. Obsérvese que ni S es subconjunto de T,ni T lo es de S. En la mayoría de los casos, el conjunto universal sobre elque se definen conjuntos de cadenas particulares es tan evidente que nosuele mencionarse explícitamente.

Ejemplo 2.12. Supóngase que tenemos los dos conjuntos de cadenas si­guientes:

A {plp es una permutación de la cadena abed,que comienza por a}

{abed, abdc, acbd, aedb,adbe, adcb}

Page 21: ComputacionI A

Conjuntos y funciones 13

D {plp es una permutación de la cadena abcd que termina en d}{abcd, acbd, bacd, bcad, cabd, cbad}

Entonces las operaciones intersección, unión y complemento relativo danorigen a las cadenas siguientes:

AnDAuD

A \ D

{abcd, acbd}{abcd, abdc, acbd, acdb, adbc, adcb, bacd,bcad, cabd, cbad}

{abdc, acdb, adbc, adcb}

Obsérvese que tanto A como D tienen seis miembros, mientras que A u Btiene diez miembros, puesto que abcd y a cbd son elementos de ambosconjuntos.

Ejercicios

2.1. Supongamos que i = 1 Yj = 1 es el estado inicial. Describir el estado alque se llega después de realizar cada una de las asignaciones de losapartados a) al e). Hacer una representación bidimensional del planoxy, y dibujar el punto que corresponde al estado inicial y a los distintosestados a que conducen las asignaciones de los apartados a) al e).

a) ; := 2;j .- ; ;

b) ; .- ; + 1;j .- j + 2;

e) j .- j + 1 .r; .- i + 1 .rj .- j + ; .

r

2.2. Expresar en notación de conjunto los descritos mediante las frases si­guientes:

a) Las cadenas sobre el alfabeto {O, 1} de longitud menor o igual que5, que contengan uno o dos ceros.

b) Los enteros pares.e) El conjunto de todas las cadenas sobre el alfabeto {a, b, e} que

no contengan símbolos duplicados.d) El conjunto de todas las permutaciones de la cadena 012.e) El conjunto de todos los polinomios de grado 3 ó menor que ten­

gan a x como un factor.

Page 22: ComputacionI A

14 Computación /. Lógica, resolución de problemas, algoritmos y programas

2.3. SeaA = {(x, y)lx ~ °e y ~ O} YB = {(x, y)lx ~ 1 e y ~ 1}. Identificarcada uno de los conjuntos siguientes sobre el plano xy, sombreando elárea apropiada.

a) A n Bb) A u Be) A \ Bd) B ~ Ae) A'

2.4. Supóngase que s y t son cadenas sobre el alfabeto {a, b, ..., z}. Es posibledefinir eoneat (s, t> como la cadena que resulta de poner t a conti­nuación de s (concatenar). Por ejemplo, si s = abe y t = xy, entonceseoneat(s,t) = abexy. Del mismo modo, si S y Tson conjuntos deeste tipo de cadenas, podemos definir eoneat (S, T) como el conjuntode todas las cadenas, que resultan de concatenar una cadena arbitraria sde S, y otra t de T. Supongamos, por ejemplo, que S = {e, x, xy,xyy}, y T = {e, y, yx, yxx}. Se pide encontrar cada uno de losconjuntos siguientes:

a) eoneat (S, T>b) eoneat(T,S)e) S u Td) S n Te) S \ Tf) T \ S

2.5. Supongamos que S y T son conjuntos de cadenas. Encontrar dos ejem­plos de parejas S y T, tales que eoneat(S, T> = S u T.

2.6. Dibujar un diagrama de Venn para los conjuntos A y B, Ysombrear laspartes correspondientes a los conjuntos siguientes:

a) (A' n B') u (A n B)b) (A u BY u (A \ B)

2.7. ¿Cuántas cadenas de longitud 2 ó menor existen sobre el alfabeto (O, I)?

2.8. Decir cuáles de las afirmaciones siguientes son verdaderas y cuálesfalsas.

a) {2, 3, 4} u {2, 4, 5, 6} = {2, 3,4, 5, 6}b) {2, 3, 5} n {2, 4, 5, 6} e {2, 3, 6}e) {3, 4, 6, 8} \ {2, 4, 7, 8} ::J {3}d) (<(> n {3, 5, 7, 8}) u {3, 7} = {3, 5, 7, 8}e) {2, 3, 5} = {5, 2, 3, 2}f) {2, 4, 5} e {I, 2, 4, 5, 6}g) {3, 4, 5} e {I, 2,4, 5, 6}h) {I, 2, 6} ::J {I, 2,4,5, 6}i) «> e {2, 5}

Page 23: ComputacionI A

Conjuntos y funciones 15

2.9. Supóngase que:

S {1, 2, 3, 4, 5}T {xlO < x < 10 Y x es impar}U Z16

\ Escribir el conjunto de elementos de los conjuntos siguientes:

a) S n Tb) (S u T)'e) (S u T) \ S

2.10. Los conjuntos siguientes se han definido en forma de reglas. Reescribirlas definiciones en forma de lista de elementos.

a) {xix E N, x ::::; 10, Y x es par}b) {plp es una permutación de la cadena 012}

2.2. FUNCIONES

Un concepto fundamental para la informática es el de función. En su formamás simple, unafuneión es una tabla con dos columnas que indican una corres­pondencia entre los valores de la primera columna y los de la segunda.

Ejemplo 2.13. Considérese la tabla siguiente.

1 22 53 104 17

Esta es una función que relaciona los enteros de la primera columna conlos correspondientes de la segunda. Si quisiéramos extender la función, nosería dificil deducir que la quinta fila constaría de los pares 5 y 26. Es decir,existe un criterio, sugerido por las cuatro filas de la función, que permitegeneralizarla para cualquier número de valores.

Ejemplo 2.14. La tabla siguiente es ligeramente diferente:

1 22 51 73 22 6

Page 24: ComputacionI A

16 Computación ,. Lógica, resolución de problemas, algoritmos y programas

Puesto que en la columna de la derecha aparecen números duplicados, estatabla no parece representar una relación estable y fiable. Parece no ajustar­se a ninguna regla gracias a la cual, a partir de un valor de la izquierda,pueda calcularse el de la derecha.

Los valores no-ambiguos -es decir, que a cada valor de la primera columna lccorrespondA uno de la segunda-, son básicos para la idea de función.

La Figura 2.7 muestra dos funciones más, en este caso utilizando un gráficoen lugar de una tabla. Obsérvese que en la Figura 2.7a cada valor de x secorresponde con uno de y, y de la misma forma, cada uno de y se correspondecon uno de x. En la Figura 2.7b cada x se corresponde con uno de y; sinembargo, para un mismo y existen más de un valor de x. Para poder trabajarcon funciones es necesario definir el concepto de forma más precisa. Clarifique­mos algunas de las ideas acerca de la correspondencia presentadas en losejemplos.

y

a)

y

b)

x

Figura 2.7. Dos representaciones gráficas de funciones: al Cada x se corres­ponde con un y. bl Cada x se corresponde con una y, pero una misma y se

corresponde con varias x.

2.2.1. Conceptos básicos

Una función siempre se define utilizando dos conjuntos.

Definición. Sean X e Y conjuntos. La notación (x, y) donde x E X e y E Y,recibe el nombre de par ordenado. El producto cartesiano de X e Y, simboli­zado por X x Y, es el conjunto {(x, y)lx E X e y E Y}. Es decir, X x Yes elconjunto de todos los pares ordenados (x, y) que verifican que x E X e y E Y.

Page 25: ComputacionI A

Conjuntos y funciones 17

Ejemplo 2.15. Sea X = Y = R. Entonces, X x Yes el sistema y coordena­das xy que se muestra en la Figura 2.8a. Si 1 = J = Z, entonces 1 x J es elconjunto de todos los puntos del plano cartesiano, cuyas coordenadas sonenteras. Los puntos de 1 x J son las intersecciones de las líneas verticales yhorizontales de la Figura 2.8b.

y

al

7

6

5

4

3

x 2

O

-1-1 O 2 3 4 5 6

b)

Figura 2.8. Representación gráfica de: a) El producto cartesianode reales. b) El producto cartesiano de enteros.

Una función es un caso particular de producto cartesiano, es un conjunto depares en el que dos elementos distintos no pueden tener igual el primer elemen­to del par. De una manera formal, una función puede definirse.

Definición. Sean X e Y dos conjuntos. Una función es un subconjunto f deX x Y, tal que cada x E X se encuentra emparejado con uno, y sólo unelemento y E Y. El conjunto X recibe el nombre de dominio de la función!, ey el de rango de f

En el contexto de una representación tabular de las funciones podemos pensaren el dominio como en la primera columna de la tabla, y en el rango como enla segunda. La propia función es la correspondencia que existe entre los núme­ros de las dos columnas. De una forma similar, cuando observamos una repre­sentación gráfica de una función, se puede identificar el eje x como el dominioy el y como el rango, y la función con el conjunto de pares (x, y) que constitu­yen la gráfica (por ejemplo, como se muestra en la Figura 2.7). En cualquiercaso, la noción de que cada valor x sólo puede tener un y asociado, resalta elconcepto de dependencia o estabilidad de la correspondencia.

Page 26: ComputacionI A

18 Computación l. Lógica, resolución de problemas, algoritmos y programas

Ejemplo 2.16. Supongamos que X = {l, 2, 3, 4} e Y = {2, 4, 6, 8}.Supongamos también que tenemos el conjunto de pares f = {(l, 2),(2,4), (3, 6), (4, 8)}. Entonces f es una función; el conjunto {l, 2, 3, 4} es eldominio; y {2, 4, 6, 8} su rango. Obsérvese que para cada x E X existe unúnico y E Y emparejado con él. Obsérvese también que esta corresponden­cia particular puede representarse mediante la regla y = 2x.

\Supongamos de nuevo que X = {l, 2, 3, 4}, Yconsidérese el conjunto g = {(1,2),(2, 4), (3, 6)}. En este caso, g no es una función con dominio X, puesto queexisten elementos de X para los que g no está definida. Aquellos conjuntos quetienen todas las propiedades de las funciones, pero que no están definidassobre todo el dominio, reciben el nombre de funciones parciales. Las funcionesparciales se utilizan a menudo en la informática.

Aunque una función exige que cada x· del dominio tenga un valor delrango, y asociado con él, no es necesario que cada valor y del rango correspon­da a un x. Por ejemplo, si X = Y = {l, 2, 3, 4}, Ydefinimos la función y = 4para todo valor de X, entonces los valores 1, 2 Y 3 no se corresponden conninguno de X. Finalmente, sea h = {(l, 2), (2, 4), (3, 6), (1, 8), (4, lO)}. Elconjunto h no es tampoco una función, puesto que existe un valor de x que secorresponde con dos valores distintos de y.

Los términos siguientes suelen utilizarse al referirnos a funciones.

Definición. Seafuna función con dominio X y rango Y. Se suele simbolizaresta relación como f: X ~ Y. Cuando se han especificado el dominio y elrango, escribimos y = f(x) para simbolizar la relación que f representaentre cada elemento del dominio X, y el correspondiente del rango Y. Enesta notación, x recibe el nombre de variable independiente. El conjunto depares {(x, f(x))lx E X Y f(x) E Y) se utiliza para definir la gráfica de lafunción!

Ejemplo 2.17. Si X = Y = R e y = f(x) = 2x - 1, x es la variable inde­pendiente, e y es la dependiente. La gráfica de f se muestra en la Figura 2.9.

2.2.2. Funciones continuas y discretas

Las funciones suelen caracterizarse dependiendo de si pueden visualizarse me­diante una linea continua o no. Si no es posible, la función tiene «huecos» ensu representación en el plano xy, y recibe el nombre de función discreta.

Ejemplo 2.18. Sea X = Y = R. La función valor absoluto, dada por y = Ixlpuede definirse mediante la regla

Ixl x cuando x ? O- x cuando x < O

Page 27: ComputacionI A

Conjuntos y funciones 19

________.......,.... x

Figura 2.9. Gráfica de la función ((x) 2x - 1.

La Figura 2.10a muestra la gráfica de y = Ixl cuando el dominio y el rangode la función es R (dando origen a una función continua). Si X = Y = Z, lafunción es ligeramente diferente, como se muestra en la Figura 2.10b (unafunción discreta).

(0,0)------+------x

y

-----IlI'-----x(0,0)

(-3,3) •

(-2,2).

(-1,1) •

y

.(3,3)

• (2,2)

• (1,1)

a) b)

Figura 2.10. Gráfica de y = IxI. a) Una función continua. b) Función discreta.

Ejemplo 2.19. Lafunción suelo l_x_lse define como el mayor entero menoro igual que x. Esta función tiene como dominio a R y como rango a Z. Portanto, si x = n.d¡d1 d3 ... (donde n es un entero y di cualquier dígito), enton­ces l_x_1 = n cuando x ~ 0, o x es un entero, y l_x_1 = n - 1 en casocontrario. Por tanto, para números reales positivos, la función l_x_1 es el

Page 28: ComputacionI A

20 Computación l. Lógica, resolución de problemas, algoritmos y programas

resultado de eliminar la parte decimal de x, y para números reales negati­

vos que no sean ya enteros, l_x_1 es el resultado de eliminar la parte deci­

mal y restarle uno. La gráfica de esta función se muestra en la Figura 2.11.

Una función muy relacionada es la función techo I-x-j que se define como el

menor entero mayor o igual que x. Se calcula eliminando la parte decimal

de x, y Isi x no fuera entero, sumándole uno. Las funciones suelo y techo

también se conocen como funciones mayor entero y menor entero, respecti­

vamente.

La función valor absoluto puede calcularse en Pascal, directamente, utili­

zando la expresión abs (x), donde x puede ser una variable o expresión del

tipo rea lo; ntege r. Sin embargo, las funciones suelo y techo no tienen una

analogía exacta en Pascal. La función más próxima es la función t runC< x)

que convierte cualquier variable o expresión de tipo rea l en integer eliminan­

do los decimales. Por tanto, trunc(3.14) = 3,ytrunC<-3.14) = -3.

2.2.3. Formas alternativas de definir funciones

Hemos visto cómo se pueden definir funciones utilizando una fórmula, una

gráfica xy, una tabla de dos columnas y un conjunto de pares ordenados. Las

funciones pueden definirse de varias formas alternativas.

Definición recursiva de funciones. Algunas veces es conveniente definir las

funciones en términos de sí mismas. Esta capacidad de autorreferenciarse reci­

be el nombre de recursión, y las funciones así definidas reciben el nombre de

funciones recursivas.

y

•,I

, ,:-2 '-1 O , 1 '2 :3

x

Figura 2.11. La función suelo I_x_l.

Page 29: ComputacionI A

Conjuntos y funciones 21

Ejemplo 2.20. Supongamos X = Y = N, Y que la funciónf(n) se define dela forma siguiente:

f(n) 13 + f(n - 1)

cuandocuando

n-On > O

\ Con la definición conocemos un valor inicial para la función; es decir, suvalor cuando x = o. Mientras conozcamos cómo se puede calcular cadavalor de f a partir del anterior, no es necesario que conozcamos una reglaexplícita para calcular f(n) directamente. Es decir, el valor de f(n) pue­de calcularse aplicando reiteradas veces la relación de recurrencia a valo­res crecientes de n, comenzando por n = o. Por tanto, primero calculamosf(O) = 1, después lo utilizamos para calcular f(l) = 3 + f(O). Esto puedehacerse repetidas veces, obteniéndose la tabla siguiente:

n f(n)~_._~

O 11 42 73 10

En algunas ocasiones es fácil deducir una fórmula no-recursiva para calcu­lar f(n) a partir de la recursiva, y en otros casos es muy dificil. Por ejemplo,el caso del Ejemplo 2.20 es relativamente senciJIo, extrayendo el criterio dela tabla para obtener la fórmula equivalente f(n) = 3n + 1.

Ejemplo 2.21. Considérese la función recursiva:

f(n) = O= 1= f(n - 1) + f(n - 2)

cuandocuandocuando

n-On - 1n > 1

Aplicando reiteradas veces la relación de recurrencia se puede obtener la tabla:

n f(n)O O1 12 13 24 35 56 87 138 21

Page 30: ComputacionI A

22 Computación ,. Lógica, resolución de problemas, algoritmos y programas

Esta función recibe el nombre de serie de Fibonacci. Es una función de granutilidad en diversas áreas de las matemáticas aplicadas. Sin embargo, esdificil, sin un conocimiento más profundo de las matemáticas, encontraruna forma de la función que la calcule directamente para cualquier valorde n.

\

Utilización de un programa para definir una función. Las funciones puedendefinirse también utilizando un programa de computadora en el cual se descri­ba cómo puede calcularse un valor de rango, utilizando un valor predetermi­nado del dominio. Formalmente, un programa de estas características recibe elnombre de algoritmo. La construcción de algoritmos computacionales parauna gran variedad de funciones es el objetivo de los Capítulos 4 al 6.

Ejemplo 2.22. Podemos definir un algoritmo como un conjunto bien defi­nido de pasos, que transforman una entrada (de un conjunto de entradasdisponibles) en la salida correspondiente. Es decir, describe cómo calcularel valor de una funciónf(x) para cada valor particular x del dominio. Porejemplo, la secuencia siguiente es un algoritmo (escrito en lenguaje Pascal)que calcula los valores de la función n = Hog2n-l, donde x es un númeroreal arbitrario, mayor o igual que 1. En este caso, el valor de x es la entradadel algoritmo, y el de n la salida de la función.

read(x);n := o;whi le x >= 1.0 do

beginx:=x/2.0;n := n + 1

end;

Cuando se utiliza un algoritmo para calcular una función, el conjunto deentradas permitidas (en este caso R) se corresponde con el dominio de lafunción; el conjunto de salidas (en este caso N) se corresponde con el rango; ylos pasos de que consta definen procedimentalmente la correspondencia exis­tente entre cada valor del dominio y el correspondiente del rango. Otras for­mas de definir funciones (véase Ejemplo 1.11) no describen ningún procesoparticular, mediante el cual pueda calcularse la función. Los programas con­trolan el proceso.

Ejercicios

2.11. ¿Cuáles de los conjuntos de pares ordenadores siguientes son funciones?

a) {(1, 1), (1, n), (1, lOO)}b) {el, 1),(3,7),(5,13),(4, 19)}e) {( - 1, 1), (O, 1), (1, 1), (1, 1), (3, l)}

Page 31: ComputacionI A

Conjuntos y funciones 23

d) {(x, y)lx ~ °e y = x}e) {(l, a), (2, b), (3, a), (4, b), (5, e)}f) {(l, a), (2, b), (1, e), (2, d), (3, e)}g) {(l, e), (2, d), (3, e), (4, b), (5, a)}

2.12. Determinar el dominio y el rango de cada una de las funciones siguien­tes:

a) h(x) = x mod 17, para x = 0, 16, 17, 32 Y 69. (La función modcalcula el resto entero que resulta de la división del primer argu­mento por el segundo.)

b) b(x) = (-1:::;; x :::;; 10), para x = -2, -1,0,10 Y 15.e) l_x_1 para x = 10, n, °y -1,5.

nd) Ixl para x = -1,0,1, -49,5 Y6".

2.13. Definir las funciones que cumplan lo siguiente:

a) Tome un entero positivo y calcule el resto después de dividirlopor 67.

b) Trunque un número real a la mitad de la décima más próxima (porejemplo, 19.567 quedaría 19,5).

e) Asigne verdadero si el número es positivo, y falso si es ceroo negativo.

d) Crear una secuencia de valores para cada uno de los cuales es eldoble del anterior más uno. El primero es 1.

2.14. Tabular unos pocos valores de las siguientes ecuaciones de recurrencia,y deducir una expresión compacta para fa) f(n) 3 para n 0, y f(n) = f(n - 1) + 5 para n > O.b) f(n) = 1 para n = 0, y f(n) = 2f(n - 1) para n > O.

2.15. Marcar un punto en la gráfica (i, j) de la Figura 2.8b, para cada uno delos estados marcados con A y B, en el segmento de programa siguiente.

; := 1;j := 1;(estado A};:=;+1;j:=j+1;{estado B}

2.16. Considérese la función f(x) = (x mod 2 = O).

a) ¿Cuál es el dominio de esta función?b) ¿Cuál es el rango?e) ¿Es una función parcial o total?

Page 32: ComputacionI A

24 Computación ,. Lógica, resolución de problemas, algoritmos y programas

2.17. La función Ancestros tiene como entrada un número de generación, ydevuelve el número de ancestros que tuvo en todas las generacionesprecedentes, suponiendo que cada persona de cada generación tieneexactamente dos padres. Es decir, Ancestros(l) = 2, Ancentros(2) = 4, Yasí sucesivamente. En particular, Ancestros(O) = 1, suponiendo que cadapersona es ancestro de sí mismo o sí misma. Enunciar una definiciónre~ursiva para la función Ancestros.

2.2.4. Funciones uno-a-uno y funciones inversas

Supongamos que f es una función con dominio X y rango Y. Entonces, como sevio en la Figura 2.7b, a cada x le corresponde uno y sólo un valor de y. Sinembargo, cada valor de y puede corresponder a más de un valor de x. Unafunción de este tipo se representa en la Figura 2.12. Sin embargo, si quisiéra­mos «invertir el proceso, comenzando por y, el resultado obtenido no sería unafunción correcta». Es decir, alguna y se correspondería con más de un valor dex, mientras que algunas de ellas no se corresponderían con ningún x. Lafunción de la Figura 2.12b es diferente ---en este caso podemos invertir elproceso y seguimos obteniendo una función-o Esto es debido a que a cada xle corresponde una y distinta. La definición siguiente formaliza estas ideas.

Definición. Sea f: X -+ y una función. La función f es una función uno­a-uno si a cada x diferente le corresponde un y diferente para cada x E X ey E Y. Se dice que dos conjuntos x e Y están en una correspondencia uno­a-uno si existe una función f: X -+ y que es uno-a-uno.

Ejemplo 2.23. Las funciones resultantes de permutaciones son ejemplosclarificadores de las correspondencias uno-a-uno. Por ejemplo, considérese

y

_~.... "",__..., x

al

y

--..,~--f----- x

bl

Figura 2.12. a) Función no-uno-a-uno. b) Función uno-a-uno.

Page 33: ComputacionI A

Conjuntos y funciones 25

la cadena abcd y su permutación bdac. Si hacemos X = Y = {a, b, e,d} esta permutación puede considerarse como una función definida como:

p(a) ep(b) ap(c) dp(d) b

Es decir, p indica en qué posición se deben colocar los diferentes elementos deuna cadena arbitraria de a, b, e y d. La función p es también una funciónuno-a-uno, puesto que x diferentes se corresponden con y's distintos, y el rangode p = {a, b, e, d} = y.

Definición. Sea f : X --. Y una función uno-a-uno. Entonces f - 1 es unafunción con dominio Y y rango X, que verifica que si y = f(x), entoncesx = f - 1(y). La función f - 1 recibe el nombre de función inversa de f

No todas las funciones tienen inversa. Por ejemplo, supongamos X = Y == {a, b, c,d},yf(a) = b,f(b) = c,yf(c) =f(d) = d,como se muestra enla Figura 2.13.

x

a.~

b •

~c.~

y

• a

• b

• e

d • ------+~ • d

f

Figura 2.13. Una función f que no es uno-a-uno, por lo que no tiene inversa.

Entonces, si la inversa de f existiera,f - 1 (d) tendría como valores asociados e yd, lo que invalidaría af -1 como una función legítima. Por tanto, para que unafunción pueda tener inversa ha de ser una relación uno-a-uno.

Page 34: ComputacionI A

26 Computación ,. Lógica, resolución de problemas, algoritmos y programas

Ejemplo 2.24. El Ejemplo 2.23, puesto que p es una función uno-a-uno,

tiene inversa. Esta inversa, p - 1, puede definirse de la forma siguiente:

p-l(a) bp-l(b) dp-l(e) ap- l(d) e

Obsérvese que p-l(p(a)) = p-l(e) = a. De forma general, para cubrir

cualquier función invertible p : X -+ Y, y cada x E X, P- 1(p(x) = x. Análo­

gamente, para cada y E Y, p(p-l(y)) = y.

Ejemplo 2.25. Las funciones uno-a-uno se emplean habitualmente en la

codificación. El American Standard Code for Information Interchange (AS­

CII) define una equivalencia numérica entre O y 127 para cada carácter

regular o de control que puede ser pulsado en un teclado estándar de una

computadora. Esta función es uno-a-uno, y está incluida en lenguaje de

programación Pascal con el nombre de ord (por valor orddinal). Es decir,

para cada carácter que encontramos en el teclado, o rd(x) es un número

entero entre O y 127. Los valores ordinales de algunos caracteres familiares

del teclado se pueden ver debajo:

ord ( , O' ) = 48ord('A') =-65ord( '=') = 61ord ( , a') = 97

Una lista completa de los caracteres ASCII y sus ordinales correspondien­

tes puede encontarse en el Apéndice A.

El propósito de la función ord es definir un esquema de codificación uni­

forme para representar los caracteres del teclado. Este esquema lo utilizan

todos los constructores de software y hardware de computadoras. La existen­

cia de este estándar permite el intercambio fácil de información entre distintos

tipos de computadoras.Obsérvese que, para ser eficaz, la función o rd tiene que ser uno-a-uno; si

un código estuviera asignado a dos caracteres distintos, no existiría una forma

consistente de descodificar el código. Puesto que es una función uno-a-uno, la

función ord tiene en Pascal su inversa, denominada eh r (por Character). Si n

es un entero en el intervalo 0-127, entonces eh r (n) es el carácter del teclado

correspondiente del entero. Por ejemplo:

ehr(48) = 'O'ehr(65) = 'A'ehr(61) = '='eh r (97) = 'a'

Page 35: ComputacionI A

Conjuntos V funciones 27

Obsérvese que, puesto que ord y chr son inversas, una de la otra, se verifica:

chr<ord<x» = x y ord<chr<n» = n

Para cualquier entero entre O y 127, Ycualquier carácter del teclado.

\ Ejemplo 2.26. La criptografia (codificación de mensajes secretos) es unárea de la informática que utiliza muchos de los principios que hemosdiscutido. Por ejemplo, el cifrado de César, un esquema de codificación enel que cada letra de un mensaje es reemplazada por otra letra diferente delalfabeto, la tercera letra detrás de ella. Entonces el mensaje:

SERGEANT PEPPERS LONELy HEARTS CLUB BAND

se codifica en el cifrado de César como:

VHUJHDGW SHSSHUV ORGHOB KHDUWV FOXE EDGG

El cifrado de César es una permutación de las letras del alfabeto, y portanto una función uno-a-uno, cuyos dominio y rango son el alfabeto deletras mayúsculas. La descodificación del lenguaje implica el descubrimien­to de la función inversa a la que fue utilizada al cifrarlo.

La gran desventaja del cifrado de César es lo relativamente fácil que esdescodificarlo. Podemos construir un método más dificil de descodificar, utili­zando una permutación aleatoria y haciendo sustituciones en base a ella. Utili­zando la tabla de sustitución:

ABCDEFGHIJKLMNOPGRSTUVWXYZJSATERNICFHPLUGWVYDZOMXGBK

Permite codificar el mensaje:

SERGEANT PEPPERS LONELY HEARTS CLUB BAND como

DEYNEJUZ WEWWEYD PGUEPB IEJYZD APOS SJUT

Si el mensaje cifrado es lo suficientemente largo, incluso un cifrado aleatoriopuede descodificarse contando el número de veces que aparece cada letra,comparándola con el número de veces que aparece cada letra en un párrafo encastellano. Algunos esquemas de encriptación más sofisticados emplean funcio­nes de descodificación que encriptan bloques de letras. La criptografía es uncampo de estudio excitante y que encierra grandes desafíos. El concepto defunción uno-a-uno aporta un criterio preciso para definir la noción de conjun­tos que tienen el mismo número de elementos, y la noción de tamaño de unconjunto.

Page 36: ComputacionI A

28 Computación l. Lógica, resolución de problemas, algoritmos y programas

Definición. Dos conjuntos A y B tienen el mismo número de elementos, siestán en una correspondencia uno-a-uno. Un conjunto que está en unacorrespondencia uno-a-uno con Zn para algún valor n natural, se dice quetiene cardinalidad * n. Dicho conjunto tiene n elementos y recibe el nombrede conjunto finito. Los conjuntos que no tienen cardinalidad n para ningúnvalor de n, reciben el nombre de conjuntos infinitos.

\

La mayoría de los conjuntos que nos encontraremos en la informática sonfinitos. Por ejemplo, el conjunto de caracteres ASCII del Ejemplo 2.25 tienecardinalidad 128. Incluso el conjunto de enteros que se utiliza en la informáticaes finito -para muchas computadoras, su cardinalidad es 216

; es decir, 65.536.Este es el tipo; nteger que utiliza el lenguaje de programación Pascal, y quedifiere de la noción matemática del conjunto Z por razones evidentes. Enresumen, el rango de los enteros en matemáticas es infinito, mientras que elrango de los; ntege r en programación es finito. Nociones complementariassobre el tipo; nteger se introducen en el manual de laboratorio.

2.2.5. Funciones booleanas enteras, exponencialesy logarítmicas

Existen un conjunto de funciones especiales que aparecen con la suficientefrecuencia en la informática como para justificar un breve estudio.

Ejemplo 2.27. Supongamos que X = Z e Y = {verdadero, fa l so}.Sea f(x) = (O ~ x ~ 100). Entonces, f(l) = verdadero, f(102) =fa l so, f( - 1) = fa l so, y así sucesivamente. El dominio de f es el de losenteros y el rango el conjunto {verdadero, falso}.

Este es un ejemplo de un importante conjunto de funciones, conocidas comobooleanas en honor del matemático inglés George Boole (1815-1864), que sen­tó las bases y comenzó el desarrollo de la lógica simbólica. Esta funcionesreciben también el nombre de predicados. Estudiaremos detenidamente lospredicados y la lógica en el Capítulo 3.

Ejemplo 2.28. Sea b mod p el resto entero resultante de dividir el entero bpor el entero p. Así, por ejemplo, 8 mod 3 = 2, 15 mod 5 = O, Y asísucesivamente. Obsérvese que O ~ b mod p ~ p - 1. Si X = N, Y = Z23 yh(b) = b mod 23, entonces h(46) = O, h(70) = 1, Y así sucesivamente.

* N. del T.: En castellano se suele utilizar el término cardinalidad o simplemente cardinalde un conjunto.

Page 37: ComputacionI A

Conjuntos y funciones 29

La función h es un ejemplo sencillo de una clase de funciones conocidas comofunciones hash*, que se suelen utilizar en programas de computadoras quealmacenan y recuperan información de archivos muy grandes.

Ejemplo 2.29. Otro tipo de funciones que aparecen frecuentemente eninformática es la clase de funciones polinómicas, tales como x Z

, 2x3 + 1,, x 5

. - 5x, y así sucesivamente. La forma general de una función polinó­mIca es:

p(x) = a xn + a xn- l + '" + a x + an n-l l o

Así, si n = 3, a 3 = 2, az = al = O, yao = 1, entonces p(x) = 2x3 + 1.

Las funciones exponenciales y logarítmicas son dos clases de funciones con unaimportancia tal en la informática, que es necesario estudiarlas cuidadosamente.Comencemos por la función exponencial.

Definición. Sean X = Y = R, Yseanf(x) 2x• La función f(x) recibe el

nombre de función exponencial con base 2.

Puesto que 20 = 1 Y 2-x = 1/2x , es posible tabular algunos valores de lafunción exponencial y perfilar su gráfica, que se muestra en la Figura 2.14.

y

x Z'

-2 1/4-1 1/2

O 11 2 x2 43 84 16

Figura 2.14. La función exponencial y su representación gráfica.

* N. del T.: Es extraordinariamente dificil traducir al castellano el término «hash». Sutraducción literal sería picadillo. Más en consonancia con el concepto sería traducir «hashtable»por tabla asociativa, «hash functiom> por función asociativa, «hashing» por asodatividad, aunqueaquí no lo hemos hecho.

Page 38: ComputacionI A

30 Computación l. Lógica, resolución de problemas, algoritmos y programas

La principal características de la función exponencial es su crecimientorápido. Si la x se incrementa en 1, f(x) se dobla, puesto que 2x + 1 = 2 x 2x

.

Los dos acertijos siguientes ilustran esta propiedad; el primero se debe a losfranceses y el segundo a los persas.

Ejemplo 2.30. Supongamos que tenemos un estanque en nuestra propie­dad. En el estanque crecen nenúfares, y hemos observado que la superficiedel estanque que recubren éstos se dobla cada dia. Al principio, el creci­miento era pequeño, puesto que el área que cubrían era escaso. Sin embar­go, si llegasen a cubrir todo el estanque, eliminarían todos los demás tiposde vida en él. Después de 29 días observamos que la mitad del estanqueestá totalmente cubierto. ¿Cuántos días nos quedan para poder salvar elestanque? (La respuesta, por supuesto, es 1 día).

Ejemplo 2.31. Cierto individuo ofreció regalar al rey un precioso tablerode ajedrez si el rey le daba a él un grano de trigo en la primera casilla, dosgranos sobre la segunda, cuatro sobre la tercera, y así sucesivamente hastaque el tablero estuviera cubierto completamente. Pensando de forma super­ficial sobre lo que le pedían, el rey aceptó. El rey no tardó mucho en caer enla bancarrota.

Estimemos cuánto arroz debía dar el rey al individuo. Antes de ello, recorde­mos algunas propiedades algebraicas de las funciones exponenciales. Las cua­tro funciones que necesitamos son las siguientes:

2m2m 2m +" (2.8)

2m/2" 2m -" (2.9)

(2m)" 2m

" (2.10)

2m!" = .::12m (2.11 )

donde m y n son números naturales (estas propiedades se verifican incluso si ny m son reales, aunque nuestras aplicaciones sólo requerirán el caso más sim­ple).

No es dificil verificar esas propiedades. En la Ecuación (2.8), el lado izquier­do es el producto de m doses seguido del de n doses. El resultado es el produc­to de m + n doses. La verificación de la Ecuación (2.9) se obtiene de formaanáloga. La parte izquierda de la Ecuación (2.10) es el producto de n copias de2m

; es decir, el producto de n copias de un producto de m doses. Por tanto, es elproducto de mn doses. Para verificar la Ecuación (2.11), utilizamos la propie­dad de que la Ecuación (2.10) puede extenderse al caso en que m y n seannúmeros racionales. Es decir, 2m!" puede escribirse como (2m)l!", por lo que seobtiene directamente la Ecuación (2.11) utilizando el hecho de que 21!" =.::12.

Podemos ahora estimar la cantidad de granos de trigo que el donante deltablero de ajedrez habría recibido si el rey hubiera sido capaz de cumplir el

Page 39: ComputacionI A

Conjuntos y funciones 31

compromiso. Consideremos los primeros cuadrados. En la casilla 1 habría quedepositar 1 (= 2°) granos de trigo; en la casilla 2, 2 ( = 21) granos; en la casilla 3,4 (= 22) granos; y así sucesivamente. Así, el día 64 el individuo tendría querecibir 263 granos de trigo del rey. Pero:

Por tanto:

263 260 X 23 = (2 1°)6 X 23210 1024 ~ 1000 = 103263 ~ (103)6 X 8 = 8 X 10 18

Si hacemos una estimación de 50 granos de trigo por cada gramo, esto esaproximadamente igual a 1,6 x 10 11 toneladas métricas de trigo, que excedecon creces la producción de arroz de todo el mundo.La función exponencial es una función uno-a-uno; así, si Xl =f. x 2 , entonces2" =f. 2". Su rango es el conjunto de números reales no negativos. Por tanto, sirestringimos el dominio al conjunto {x E Rlx > O}, entonces el dominio de lafunción exponencial será igual al rango (véase de nuevo la Figura 2.14). En estecaso, la función es invertible. La función inversa de una exponencial recibe elnombre de función logarítmica.

Definición. Sea X = R e Y = {x E Rlx > O}. Seaf(x) = 2x• Entonces'¡-lrecibe el nombre de función logarítmica en base 2 y se representa por

log2(x).

Recuérdese que una función y su inversa cumplen fU - 1(x» = x yf-IU(x» = x. Esta relación nos conduce a las ecuaciones siguientes, querelacionan entre sí ambas funciones:

(2.12)

(2.13)

Ejemplo 2.32. Puesto que 23 = 8,log2 8 = 3. Es decir, 23 = 8 responde ala pregunta: «¿Qué obtendremos cuando elevamos el número 2 al cubo?».Por el contrario, log2 8 = 3 responde a la pregunta: «¿A qué potencia hayque elevar 2 para obtener 8?». Del mismo modo, tendremos que log2 16 = 4,Y log2 1024 = 10.

En la Figura 2.15 se muestra la gráfica de la función logarítmica. La principalcaracterística de la función exponencial es su rápido crecimiento. Por el con­trario, la principal característica de la función logarítmica es su crecimientolento. Obsérvese que log2 8 = 3 Y log2 16 = 4. Es decir, añadiendo 1 a x sedobla 2x, mientras que al doblar x sólo se le añade 1 a log2 x.

Otra forma de comparar las funciones exponencial y logarítmica es la si­guiente: y = 2X significa que el número 1 debe ser doblado x veces para

Page 40: ComputacionI A

32 Computación l. Lógica, resolución de problemas, algoritmos y programas

y

x

Figura 2.15. La función logarítmica.

obtener y. Si x es una potencia de 2, y = log2 x significa que x debe ser

dividido por 2 y veces, para obtener 1. Por ejemplo, log2 16 = 4 significa que

16 debe ser dividido por 2 cuatro veces para obtener 1. Las Ecuaciones (2.14) a

(2.18) describen algunas propiedades adicionales de la [unción logarítmica.

log2 1 O (2.14)

log2 2 1 (2.15)

log2 mn log2 m + log2 n (2.16)

log2 (m/n) log2 m - log2 n (2.17)

log2 (mn) n log2 m (2.18)

La verificación de esas expresiones depende del hecho de que la función loga­

rítmica es la inversa de la exponencial. Abajo verificamos las Ecuaciones (2.14)

a (2.16), dejando para el lector la verificación de las restantes.

Para verificar la Ecuación (2.14) supongamos que log2 1 = x. Entonces

2x = 1, por lo que x = O. Para verificar la Ecuación (2.15), sea log2 x = x.

Entonces 2X = 2, resultando x = 1. Para verificar la Ecuación (2.16), sea

x = log2 m e y = log2 n. Entonces m = 2x y n = 2Y• Por tanto, nm = 2x +y, y

por tanto, x + y = log2 (mn). Combinando ambas, obtenemos log2 mn = log2

m + log2 n.

Page 41: ComputacionI A

Conjuntos y funciones 33

Ejemplo 2.33. logz 3 = 1,585 Y logz 5 = 2,322. Podemos utilizar estainformación para calcular las expresiones siguientes:

a) logz 6 = logz (2 x 3) = logz 2 + logz 3 = 1 + 1,585 = 2,585b) logz 1,6 = logz (8/5) = logz 8 - logz 5 = 3 - 2,322 = 0,678e) logz 0,5 = logz (1/2) = logz 1 - 1 = - 1

Pascal incorpora las funciones exponencial y logarítmica, pero en base e enlugar de en base 2. Se simbolizan mediante exp y l n respectivamente. Esdecir, dado x para calcular en Pascal eX escribiremos la expresión exp(x).Conocido x para calcular en Pascal loge x, escribiremos l n ( x). Para másdetalles véase el manual de laboratorio.

Ejercicios

2.18. Una alternativa en criptografia para el cifrado de César es la utilizaciónde una clave de codificación, que consiste en un patrón que se repite eindica al descodificador a qué distancia a la derecha en el alfabeto seencuentra la letra correcta. Por ejemplo, A significa «desplaza °letras»;B significa «desplaza 1 letra», y así sucesívamente. Por tanto, si la clavede codificación es ABCDABC..., el mensaje (en inglés) FOURSCO­REANDSEVEN se codificaría FPWRTEOSGAOFSFXEO. Invertir elproceso para el mensaje codificado (también en inglés) OIVOCGIO­PASPIB. ¿Es este esquema una función de caracteres uno-a-uno? ¿Esuna función uno-a-uno de cadenas de caracteres?

2.19. Dibújense las gráficas de las funciones siguientes. Supóngase que eldominio es R (excepto para el apartado e que es N).

a) 12xlb) lx/3Je) logz (2x)

xd) 2>+e) x mod 7f) Ilogz xlg) rIxll

2.20. Simplificar las expresiones siguientes:

a) 3a x 3-a

b) (2Z)3e) 27"/3

d) 23/24

e) logz 4f) log3 (1/27)g) logz 2"h) 3 log3 (x + 1)

Page 42: ComputacionI A

34 Computación l. Lógica, resolución de problemas, algoritmos y programas

2.2.6. Series finitas y funciones relacionadas

Los procesos acumulativos son frecuentes en la informática. Por ejemplo, al­gunos programas repiten un determinado cálculo. Cada repetición consumeuna cierta cantidad de tiempo y memoria. El programador tiene que ser ca­paz de esÜmar la cantidad de tiempo y espacio que consumirá el programa,sin necesidad de ejecutarlo. Tales cálculos suelen implicar la suma de lar­gas listas de números o expresiones. Para facilitar todo ello, y otras expresio­nes relacionadas, se ha desarrollado la denominada notación sigma. Esta nota­ción utiliza la letra griega L (sigma) para simbolizar la «suma», un índice quedefine el intervalo de valores para los que se realiza la suma, y la función quehay que sumar. Supongamos que se quiere escribir la suma de los 20 primerosenteros, 1 + 2 + 3 + ... + 20, utilizando notación sigma. Escribiremosentonces:

Esto se lee, «calcular la suma de los i enteros comprendidos entre 1 y 20,ambos inclusive». El número 20 es el límite superior y el 1 el límite inferior,siendo la variable i la variable índice de la sumatoria.

Ejemplo 2.34. A continuación, se muestran varios ejemplos de notaciónsigma:

n

a) i~l i 1 + 2 + 3 + ... + (n - 1) + n.

n

b) i~ 3i O + 3 + 6 + 9 + '" + 3(n - 1) + 3n.

n

e) L (3i + 2)i= 1

5 + 8 + 11 + .. , + (3n - 1) + (3n + 2).

n

e) i~ i

1 + 2 + 3 + ." + (n - 2) + (n - 1).

2 + 3 + 4 + ... + (n - 1) + n.

n

f) i~ i(3i + 2) = 5 + 16 + 33 + ... + (n - 1)(3n - 1) + n(3n + 2).

Page 43: ComputacionI A

Conjuntos y funciones 35

De hecho, cualquier función de una variable índice i, puede sumarse de estaforma. Considérense las relaciones generales siguientes:

n

I f(i) = f(m) + f(m + 1) + ... + f(n)i=m

n

)' a· = a + a + .,. + aL....J I 1 2 nj= l

(2.19)

(2.20)

Obsérvese la utilización de subíndices en la Ecuación (2.20). Este tipo de nota­ción suele utilizarse para diferenciar los elementos de una lista, siendo al elprimero, a z el segundo, y así sucesivamente. Utilizaremos a menudo esta ideade lista en el diseño de programas.

Propiedades de las series finitas. Las Ecuaciones (2.21) a (2.24) reflejan algunaspropiedades básicas de las sumas utilizando la notación sigma.

1

I a¡ al (2.21)¡=1

n n

I a¡ al + ¡~a¡ (2.22)¡ = 1

n n~l

I a¡ a n + I a¡ (2.23)¡= 1 ¡= 1

n m n

I a¡ I a¡ + I a¡ SI 1 ~m < n (2.24)¡= 1 ¡= 1 ¡=m+l

Que se pueden justificar de la forma siguiente: En la Ecuación (2.21) los límitesinferior y superior son iguales, por lo que existirá un único término, el corres­pondiente al valor común de los límites. En la Ecuación (2.22) el lado derechode la expresión es simplemente igual al izquierdo, con el primer término escritopor separado. En la Ecuación (2.23), el lado derecho es igual al izquierdo, perocon el último término escrito por separado. En la Ecuación (2.24), el ladoderecho es igual al izquierdo separado en dos sumas -una hasta m, y otradesde m + 1 hasta n.

Las Ecuaciones (2.25) a (2.29) resumen otras importantes propiedades adi­cionales de las sumas en series finitas.

n

I ej= 1

en donde e es una constante (2.25)

n

I (f(i)¡= 1

n

e I f(i)i= l

(2.26)

Page 44: ComputacionI A

36 Computación ,. Lógica, resolución de problemas, algoritmos y programas

n n n

I (f(0 + g(i)) i~ f(O + j~ g(i) (2.27)j= 1

n n n

I (fU) - g(i)) I f(i) I g(i) (2.28)j= 1 j= 1 j=l

n

i~ (f(i + 1) - f(i)) = f(n + 1) - f(l) (2.29)

Es posible justificar estas ecuaciones haciendo las consideraciones siguientes:En la Ecuación (2.25), dIado izquierdo es el propio valor c sumado a sí mismon veces. En la Ecuación (2.26), dIado derecho es igual al izquierdo, tras sacar cfactor común de la suma. En la Ecuación (2.27), el lado derecho es igual alizquierdo, pero con los términos reagrupados. La Ecuación (2.28) se deja comoejercicio. La Ecuación (2.29) se conoce como las series telescópicas. El ladoizquierdo puede escribirse como:

(f(2) - f(l)) + (f(3) - f(2)) + ... + (f(n + 1) - f(n))

donde podemos ver que todos los términos entre f(n + 1) y f(l) se cancelanmutuamente, por lo que el resultado seráf(n + 1) - f(l).

Algunas series importantes para la informática. No suele ser habitual la mode­lización de procesos acumulativos, como sumas finitas, utilizando notaciónsigma. Generalmente, es deseable encontrar una fórmula que nos calcule elresultado en función de los límites inferior y superior. Se han obtenido estasfórmulas para algunas de las series más comunes, y es conveniente memorizarlas.

Una de tales series, que se utiliza frecuentemente en la informática, es laserie aritmética (también conocida como progresión aritmética):

1 + 2 + 3 + ... + (n - 1) + n

Existe una anécdota interesante sobre esta serie. Cad Friedrich Gaus (1777­1855) fue uno de los matemáticos más destacados del siglo XIX. Cuando erajoven le enviaron a un internado, más conocido por su estricta disciplina quepor su calidad académica. Como castigo, él y sus compañeros deberían realizarel ejercicio de sumar los 100 primeros enteros. Apenas el profesor había enun­ciado el problema, Gauss levantó su mano dando la respuesta correcta. Gausshabía descubierto una forma sencilla de sumar la serie aritmética para n =100. Gauss escribió la suma horizontalmente en orden creciente, y debajoescribió la misma suma, pero en orden decreciente, haciendo después la sumatérmino a término:

1 + 2 + 3 ++ 100 + 99 + 98 +

101 + 101 + 101 +

+ 99 + 100+ 2 + 1+ 101 + 101

Page 45: ComputacionI A

Conjuntos y funciones 37

Gauss pudo observar que el resultado era la mitad de 101 x 100, o 5050. Elprofesor de Gauss reconoció que el muchacho tenía un gran talento para lasmatemáticas, y recomendó a su padre que lo enviara a un colegio en el quepudiera sacar mejor partido de su capacidad. De hecho, podemos utilizar elmétodo abreviado de Gauss para sumar series en general:

1 + 2 + 3 ++ n + (n 1) + (n 2) +

(n + 1) + (n + 1) + (n + 1) +

+ (n 1) + n+ 2 + 1+ (n + 1) + (n + 1)

Puesto que hay n términos en la suma, el resultado de la suma anterior pue­de escribirse n(n + 1). Por tanto, la suma de la serie aritmética original esn(n + 1)/2, puesto que se ha sumado consigo misma para obtener la últimalínea. La forma compacta de la suma de esta serie, junto con la de otras tam­bién importantes, se muestran en las Ecuaciones (2.30) a (2.33).

n n(n + 1)i~l 2

(2.30)

n n(n + 1)(2n + 1)i~1 i2

6(2.31 )

n n2 (n + 1)2I i3 (2.32)i= 1 4

n

I 2i 2n+ 1 _ 1 (2.33)i= 1

Las Ecuaciones (2.30) a (2.32) se las conoce con el nombre de p-series por ser dela forma:

n

I iP

i= 1

para algún valor de p. La Ecuación (2.32) es un ejemplo de la que se conocecomo serie geométrica o progresión geométrica.

Ejemplo 2.35. A continuación, se estudian dos ejemplos en los que se vecómo pueden utilizarse esas propiedades para calcular sumas de series.

15 15(15 + 0_i~1 i 2

120

20 20 6 20(21) 6(7)i~i i~1 JI -2- 2 210 - 21 189

Page 46: ComputacionI A

38 Computación ,. Lógica, resolución de problemas, algoritmos V programas

Ejemplo 2.36. Considérese el problema discutido en el Ejemplo 2.31. Es

posible utilizar la Ecuación (2.33) para calcular el número total de granos

de arroz que se acumularían en 64 días, de la forma siguiente:

Obsérvese que 264 = 2 X 263 = 263 + 263, luego 264

- 1 = 263 + 263 - 1.

Recuérdese que el número de granos de trígo recibidos el día 64 fue 263.

Por tanto, el número de granos recibidos el día 64 era de ¡uno más que la

suma de los recibidos en todos los días anteriores! En general, las series

geométricas tienen esta característica. Es decir,

1 + 2 + 4 7, que es 1 menos que 8

1 + 2 + 4 + 8 = 15, que es 1 menos que 16

y así sucesivamente. Esto aporta otro punto de vista sobre el rápido creci­

miento de las funciones exponenciales.

2.3. SUMARIO

En este capítulo se han introducido algunas ideas fundamentales sobre conjun­

tos y funciones. Como se sugirió, la mayoría de estas nociones tienen directas e

importantes aplicaciones en la informática. En este libro utilizaremos los con­

ceptos de conjunto y función siempre que sea necesario. Veremos que esta

notación matemática, concisa y exacta, produce grandes beneficios en la solu­

ción de problemas informáticos, sean los propios problemas de naturaleza

matemática o no. Las propiedades de los conjuntos y las funciones tienen un

gran paralelismo con las de la lógica, como veremos en el Capítulo 3, y en el

diseño de computadoras, como se verá en el Capítulo 7. Por tanto, un conoci­

miento profundo de los conjunto y las funciones es de vital importancia en el

estudio de la disciplina informática.

Ejercicios

2.21. Desarrollar cada una de las sumatorias siguientes:

Page 47: ComputacionI A

Conjuntos y funciones 39

od) i~ a¡

2.22. Expresar las series siguientes en notación sigma:

a) 17 + 21 + 25 + ... + 65.b) 2 + 5 + 10 + 17 + .. , + 101.e) La suma de los números impares de O a 1000, inclusive.d) La suma de los enteros positivos menores que 300 y que sean divisi­

bles por 3.e) La suma de las raices cuadradas de todos los enteros positivos

menores que 1000.

2.23. a) Justificar la Ecuación (2.28).b) Justificar que la suma de los n primeros números impares es n2

2.24. Calcular la suma de las expresiones desarrolladas en el Ejercicio 2.22.

2.25. Calcular las sumas siguientes:25 n

a) ¡¡i e) ¡~1 2

13 5

b) i~ 2i(i + 1) f) ¡~ (2¡ + 1)

12 5

e) ¿ 3¡2 g) i~ ¡2¡=6

10 O

d) k~5 2k h) ¿ a¡i= 1

2.26. Un programa de computadora ordena una lista L = (al' a2, ..., a n) en laforma siguiente. Examina cada elemento de la lista, selecciona el mayor,y lo intercambia con an0 A continuación, repite el mismo proceso para lasublista (a l' a2 , ... , an _ 1)' El programa termina cuando sólo quede a 1 enla sublista.

a) Utilizar notación sigma para escribir una expresión que refleje elnúmero de exámenes realizados por el proceso.

b) Sumar la expresión.

2.27. En Nepal, el arroz se cultiva a menudo en terrazas formadas en lasladeras de las colinas. Una colección de estas terrazas, observadas a

Page 48: ComputacionI A

40 Computación l. Lógica, resolución de problemas, algoritmos y programas

vista de pájaro, se puede ver en la Figura 2.16. El cuarto de círculointerior, correspondiente a la cima, no está cultivado. Moviéndonoshacia abajo por la colina, los parterres se alternan con zonas escarpadasno cultivadas. Supongamos que, para una determinada colina, el radiodel círculo de la cima es de 75 metros, y cada círculo concéntrico de ahíhacia abajo tiene 50 metros. Supongamos que hay 10 parterres planta­dos.'

a) Utilizar la notación sigma para escribir una expresión que refleje elárea total cubierta por los parterres de arroz.

b) Calcular el área total cubierta por parterres.

75 125 175 225 275 325

Metros

Figura 2.16. Panorámica a vista de pájarode los parterres de Nepa!.

2.28. Si comenzamos con una célula de levadura el día O, y al final de cadadía cada célula se divíde en dos, ¿cómo de grande será la colonía des­pués de n días?

Page 49: ComputacionI A

CAPíTULO 3LÓGICA

La lógica está adquiriendo un papel cada vez más preponderante en la infor­mática. De hecho, algunas personas llegan tan lejos como para afirmar que lainformática no es más que lógica aplicada. En este texto, la lógica tiene tresdistintas e importantes aplicaciones: se utiliza la lógica en programación paraconstruir expresiones lógicas (Capítulo 4); se utiliza la lógica para escribir pre yposcondiciones y otros asertos que describen el comportamiento de los progra­mas (Capítulos 5 y 6); Yse utiliza la lógica como fundamento para el diseño delas computadoras mismas (Capítulo 7).

En las Secciones 3.1 y 3.2 se introduce la lógica proposicional, que es unsistema para razonar y hacer cálculos con proposiciones. La lógica proposicio­nal nació entre los años 1847 y 1854, fruto de los trabajos de George Boole.Boole observó que existía una gran similitud entre las operaciones lógicas andy or, y las operaciones aritméticas producto y suma. Boole desarrolló un siste­ma para la manipulación de expresiones lógicas, que era tan preciso paramanipular esas expresiones como la aritmética para manipular números.

En la Sección 3.3 se extiende la noción de lógica proposicional a otra másamplia, conocida como lógica de predicados. Esta extensión nos permite utili­zar la lógica en informática de una forma muy constructiva. Por ejemplo, lautilización de los denominados cuantificadores lógicos está estrechamente rela­cionada con la idea de bucles en los programas.

También se introducen las ideas de tautología y demostración. Estos con­ceptos serán revisados en el Capítulo 6, en yuxtaposición con los conceptosparalelos de prueba y verificación. Lógica y demostración son tan fundamenta­les para la informática como para otras disciplinas, tanto artísticas como cien­tíficas; por tanto, este capítulo será útil en otras áreas diferentes.

3.1. LÓGICA PROPOSICIONAL

La idea básica de Boole fue la de analizar patrones de argumentaciones lógi­cas, utilizando símbolos para representar tanto aseveraciones simples como los

Page 50: ComputacionI A

42 Computación l. Lógica, resolución de problemas, algoritmos y programas

propios patrones. Esta parte de la lógica se conoce por el nombre de lógica

proposicional (o en algunos casos lógica simbólica). En lógica proposicional,

una frase (o proposición) puede tener sólo dos valores verdadero (true) o falso

(false). Las oraciones siguientes son ejemplos típicos de proposiciones:

I

• El área de un triángulo rectángulo isósceles, que tiene una hipotenusa de

longitud 2 es 1/2.

• Todos los elementos de la lista (1 3 5 7 6 4) son menores que 10.

• 3 + 5 = 7.

• En la frase «The quick brown fox jumps over the lazy dog» están presen­

tes, al menos una vez, todas las letras del alfabeto inglés.

• Ningún alumno de informática del Calvin College, alcanzó la calificación

de B + en el curso de 1990.

Con objeto de expresar frases como las anteriores, de una forma más preci­

sa, utilizamos un estilo formal para escribir proposiciones. En la Tabla 3.1 se

presenta una lista de los operadores lógicos que se utilizan al escribir proposi­

ciones.

Definición. Una proposición es una expresión que se construye siguiendo

las reglas siguientes:

Regla 1:

Regla 2:

Regla 3:

Regla 4:

Verdadero (true) y falso (false) son proposiciones.

Cualquier variable cuyo tipo sea {verdadero, falso} (conocido

como tipo booleano) es una proposición.

Si p es una proposición, también lo es ('" p).

Si p Y q son proposiciones, también lo son (p v q), (p /\ q),

(p => q), (p <=> q).

Obsérvese que la definición anterior es recursiva, según se vio en el Capítu­

lo 2. Es decir, las reglas 3 y 4 definen una proposición en términos de una o

más proposiciones ya existentes, las cuales pueden haber sido construidas utili­

zando las reglas 3 y 4, Yasí sucesivamente. Sin embargo, debido a que existen

proposiciones elementales formadas utilizando las reglas 1 y 2, que no utilizan

la palabra proposición en la definición, el proceso para determinar si algo es

una proposición, utilizando estas reglas, no es infinito; es decir, la definición no

es circular.Por el momento, cuando trabajemos con el cálculo proposicional, manipu­

laremos sólo variables y no intentaremos simbolizar ninguna proposición en

particular. Más adelante introduciremos formas de interpretación de las varia­

bles, que son de gran utilidad en el mundo de la programación y del diseño de

las computadoras.

Page 51: ComputacionI A

Lógica 43

Tabla 3.1. Los operadores lógicos

Símbolo

V

/\

=>

-=

Equivalenteen castellano

nooyimplicasi y solo si

Significado

NegaciónDisyunciónConjunciónImplicaciónEquivalencia

i

I

Después de ver algunos ejemplos de la aplicación de estos operadores, estudia­remos otras interpretaciones.

Ejemplo 3.1. Si p, q y r son variables booleanas, entonces las siguientesexpresiones son proposiciones válidas:

pqc-· p)(p v q)(p v (q v r»(p =o> (q v (r =o> (p ~ q»»

De las Reglas 2 y 3 puede deducirse, de forma inmediata, que las cuatroprimeras son expresiones. Para la quinta expresión puede aplicarse reitera­damente la cuarta regla, siguiendo los siguientes pasos:

p, q y r son proposiciones por la segunda regla.(q v r) es una proposición según la regla 4.(p v (q v r» es una proposición según la regla 4.

Una línea de razonamiento similar sirve para demostrar que el sexto ejem­plo es una proposición:

p, q y r son proposiciones por la segunda regla.(p ~ q) es una proposición según la regla 4.(r =o> (p ~ q» es una proposición según la regla 4.(q v (r =o> (p ~ q))) es una proposición según la regla 4.(p =o> (q v (r =o> (p ~ q»))) es una proposición según la regla 4.

Ejemplo 3.2. Las expresiones siguientes no son proposiciones:

(p)(p q) p)~ (p)

Page 52: ComputacionI A

44 Computación ,. Lógica, resolución de problemas, algoritmos y programas

Observando el Ejemplo 3.2, si somos estrictos en la aplicación de las reglas,los paréntesis juegan un papel crucial en la determinación de si una expresión esuna proposición. Sin embargo, podemos prescindir de ellos siempre que el signi­ficado de la expresión esté claro. Por ejemplo, podemos escribir '" p en lugar de('" p), p v q en lugar de (p v q), y así sucesivamente.

Sin embargo, la eliminación descuidada de los paréntesis puede conducir­nos a am~igüedades. Por ejemplo, no está claro si p v q /\ r significa

((p v p) /\ r)(p v (q /\ r))

o bien,

Para evitar estas ambigüedades, se asignan prioridades a los operadores:'" tiene la prioridad más alta; /\ tiene la siguiente más elevada; y v, =:> y ~tienen sus prioridades por este mismo orden. De esta forma, la expresiónp v q /\ r siempre se debe interpretar como (p v (q /\ r)).

3.1.1. Representación de frases en castellanoutilizando la lógica proposicional

No siempre es posible representar cualquier frase arbitraria, de forma simbóli­ca, utilizando proposiciones o predicados. Es decir, muchas frases no son de­clarativas y, por tanto, no puede afirmarse que sean verdaderas o falsas. Porejemplo, «¡cierra la puerta!» es una orden, y ¿fuiste a la clase de anatomía deayer, del profesor Davidson? es una pregunta. Sin embargo, existen gran canti­dad de frases que pueden representarse como proposiciones y, más aún, quepueden representarse como predicados. En informática, la mayoría de las cosasque solemos querer representar simbólicamente, no son ambiguas, tienen unvalor verdadero o falso, también no ambiguo y son expresables en forma deproposición o de predicado.

Obsérvese que en la lógica proposicional existen cinco operadores. De he­cho, solamente es necesario uno; el resto pueden obtenerse a partir de éste(véanse los ejercicios de la Sección 3.2). La lengua castellana ofrece una grancantidad de formas para expresar la misma idea; así, al representar frasesmediante proposiciones evitaremos muchos matices del significado, centrandonuestra atención en la estructura lógica de las oraciones. Del mismo modo,utilizaremos la misma estructura lógica para expresar diferentes giros en caste­llano. Por ejemplo, si representamos la frase «Phogbound quiere ser senador»mediante la variable p, las oraciones siguientes pueden representarse ambasmediante la proposición '" p:

Phogbound no quiere ser senador.No es verdad que Phogbound pretenda ser senador.

De forma similar es posible simbolizar las frases siguientes, como p /\ q sirealizamos una asignación apopiada a las variables p y q:

Page 53: ComputacionI A

Lógica 45

El número n es un número primo menor que 100.10 ~ x ~ 100Henry Higgins era un soltero recalcitrante, pero Eliza Doolitte conquistó

su corazón.Aunque había sido un traficante de esclavos, John Newton terminó siendo

un decidido oponente a la esclavitud.I

La primera de las oraciones anteriores puede descomponerse en dos frases-«n es un número primo» y «n es menor que 100»- aunque están condensa­das en una utilizando, según es costumbre en el lenguaje coloquial. La segundatambién contiene dos frases ocultas, aunque en este caso el método de síntesiscorresponde a las matemáticas. En la tercera, el adverbio pero tiene en lógicasignificado de la operación y; introduce un matiz en la frase que no es necesa­rio para la construcción de las proposiciones. En la cuarta frase, la proposiciónaunque indica la presencia de una y, a la vez que sirve para remarcar el con­traste.

Podemos simbolizar la frase:

Algunos han nacido para la grandeza, algunos alcanzan la grandeza yalgunos soportan sobre sí la grandeza

tanto por ((p 1\ q) 1\ r) como mediante (p 1\ (q 1\ r)). En la Sección 3.2 se verá queambas expresiones lógicas son equivalentes, y que pueden eliminarse los parén­tesis, quedando, por tanto, la expresión p 1\ q 1\ r. En la frase anterior, la prime­ra coma equivale al operador 1\.

El operador v puede tener en castellano dos significados ligeramente dife­rentes, por ·10 que es necesario distinguirlo. En la frase:

Este banco proporcionará crédito a todo el que mantenga un saldo medio de500 dólares o que tenga un certificado de depósito de más de 5000 dólares.

El banco, evidentemente, no intenta excluir a aquellas personas que cumplansimultáneamente ambos requisitos. Por el contrario, podemos imaginar a unpadre diciendo: «Puedes ir a la piscina o a la pista de patinaje», que quieredecir que «puede ir a uno u otro lugar, pero no a ambos». Mientras el bancoutiliza la o inclusiva que significa que ambas posibilidades son aceptables, elpadre utiliza la o exclusiva que significa que «una de las dos posibilidades esaceptable, pero no ambas a la vez».

En proposiciones como p => q, p recibe el nombre de antecedente y q el deconsecuente. Un ejemplo en castellano de una implicación lógica es:

Si Phogbound resulta elegido, entonces estaremos apañados.

Aunque el adverbio entonces no suele incluirse en el lenguaje coloquial. Sisimbolizamos mediante p la frase «Phogbound resulta elegido», y mediante q a«estaremos apañados», podemos representar toda la frase como p => q (que

Page 54: ComputacionI A

IGIL.JIUIJIM•...i.IISIIISlIILllj!IJ"".!lI!C,;aIllJIII..lI!I!d!ll!lll.. \IIl,1!lII!fIlI""""",_4-~·'46 Computación ,. Lógica, resolución de problemas, algoritmos y programas

significa «p implica q»). De forma alternativa, es posible reescribir esa frase enla forma

Estaremos apañados si Phogbound resulta elegido,

aunque la frase anterior puede seguir representándose de forma simbólicacomo p => q.Obsérvense las distintas utilizaciones que se hacen de la proposición si, enlas siguientes frases:

Compraré entradas si representan Nuestro barrio.Compraré entradas sólo si representan Nuestro barrio.

Si representamos mediante r la proposición «representan Nuestro barrio» ymediante s la proposición «compraré entradas», la primera frase puede repre­sentarse en la forma r =::> s. Cualquier persona que pronuncie esta frase no estáafirmando nada acerca de lo que haría si se representase Maebeth. En cambio,la última frase tiene un significado ligeramente diferente, y que se simbolizamediante s => r. Esta frase puede rehacerse de la forma «si compro entradas,entonces es que se representa Nuestro barrio»; en definitiva, que la única cir­cunstancia que hará que compre entradas es que se esté representando Nuestrobarrio»; En estas circunstancias, se dice que la proposición s =::> r es la proposi­ción recíproca de r =::> s.

Otra propiedad importante de la implicación p =::> q es que no es necesariosuponer la existencia de causalidad entre p y q. Por ejemplo, cuando decimos:

Si George toca bien la viola, entonces le seleccionarán para la orquesta,

implícitamente asumimos que si George es elegido para tocar en la orquesta, esporque toca bien. La frase:

Si 1 + 1 = 2, entonces el sol es el centro del sistema solar.

También se simboliza por p => q que, desde el punto de vista de la lógica, estan válida como la afirmación de George y la orquesta.La causalidad es otra de las cosas que podemos expresar en lenguaje natu­ral, pero que no podemos expresar en el cálculo proposicional.La expresión p ~ q se utiliza para indicar que dos proposiciones sonlógicamente equivalentes; es decir, que una implica la otra y viceversa. Unejemplo típico es el siguiente:

Sea T un triángulo de lados a, b y e. Entonces a2 + b 2 = e2 sólo si T es untriángulo rectángulo.

Si representamos por p «a 2 + b 2 = e2», y por q «T es un triángulo rec­tángulo», la frase «a2 + b2 = e2 si y sólo si T es un triángulo rectángulo»

Page 55: ComputacionI A

Lógica 47

se representa mediante P ~ q. Es decir, que son ciertas simultáneamentetanto P => q como q => p.

Ejemplo 3.3. Se pueden representar como proposiciones oraciones en­teras. Veamos un ejemplo relativamente complicado: «Si conseguimoslos contratos de Dynamic Systems o de Metadyne, van Alstyne o Liurealizarán tanto el análisis como el diseño; a Frederick no se le asignaráel diseño, y Thompson será despedido». Para poder escribir la proposi­ción equivalente a esta frase, primero tenemos que asociar variables acada parte de la oración.

DSMDVAAL/VAVADL/VDFRATF

Conseguir el contrato de Dynamic Systems.Conseguir el contrato de Metadyne.Se le asigna el análisis a van Alstyne.Se le asigna el análisis a van Liu.Se le asigna el diseño a van Alstyne.Se le asigna el diseño a Liu.Se le asigna el análisis a Frederick.Thompson es despedido.

Con estas definiciones de variables, la oración anterior puede represen­tarse:

(DSvMD) =>

(((VAA 1\ VAD) v (L/VA 1\ L/VD» 1\ "" FRA 1\ TF)

3.1.2. Evaluación de proposiciones: Tablas de verdad

Recuérdese que en el Capítulo 2 definíamos el concepto de estado de unavariable. Esta noción puede aplicarse también a las proposiciones.

Definición. Sean PI' ..., Pn las variables de una proposición. El estado deesas variables PI' ..., Pn es el resultado de asignar los valores booleanosverdadero o falso a cada una de ellas.

Por ejemplo, supongamos que tenemos la proposición P v q. Puesto que laproposición consta sólo de dos variables, cada una de las cuales puede tomarsólo dos valores posibles (verdadero o falso), existen sólo cuatro posibles esta­dos para las variables de la proposición P v q. De forma alternativa, podemosconsiderar la proposición P v q como una función en dos variables P y q, condominio {verdadero, falso} x {verdadero, falso} y con rango {verdadero, falso}.Así, al contrario que las funciones con dominios infinitos (tales como N o R), lafunción P v q tiene un dominio tan reducido que pueden tabularse sus valorespara todos los estados posibles de sus variables. Estas tablas reciben el nombre

Page 56: ComputacionI A

48 Computación /. Lógica, resolución de problemas, algoritmos y programas

de tablas de verdad. La tabla de verdad de la función p v q se muestra en laFigura 3.1.

p q pvq

verdadero verdadero verdaderoverdadero falso verdaderofalso verdadero verdaderofalso falso falso

Figura 3.1. Tabla de verdad para la función pv q.

En la tabla, se puede apreciar que el valor de la función es verdadero siempreque cualquiera de las variables, o ambas, valga verdadero; en caso contrariovaldrá falso. Esta definición de la función es consistente con nuestra idea intui­tiva acerca de la disyunción, que se ilustró en la Sección 3.1.1. Supongamosque las variables p y q representan las proposiciones siguientes:

p «Tenemos un saldo medio mayor de 500 $.»q «Tenemos un certificado de depósito de más de 5000 $.»

Entonces, la proposición p v q vale verdadero, siempre que p y q, o ambas a lavez, sean verdaderas; en otro caso (p v q) valdrá falso.

Las tablas de verdad de las otras operaciones de la lógica proposicional,pueden construirse de forma análoga. Estas tablas se muestran en la Figura 3.2.La mayoría de los valores de estas operaciones son consistentes con las ideasintuitivas introducidas en la Sección 3.1.1. Asi, la negación siempre devuelve elvalor contrario al de la variable, y la conjunción lógica sólo se evalúa a verda­dero cuando ambas variables valen verdadero simultáneamente.

El operador implicación precisa una discusión más cuidadosa, sobre todoen el caso en que p vale falso. Lo anterior, no es dificil de entender si considera­mos el ejemplo siguiente:

Si representan Nuestro barrio, entonces compraré entradas.

La frase anterior se representa por p ~ q. De hecho, si no se representaNuestro barrio, la variable p vale falso. Sin embargo, no está garantizado queno queramos comprar entradas aunque no se represente Nuestro barrio; en sulugar, podemos comprar entradas para Línea de coros. Puesto que la falsedadde p no garantiza la falsedad de q, podemos permitir que la proposición resul­tante sea, en este caso, verdadera. (Otra justificación para esta decisión sepresentará en la Sección 3.2.4.)

La tablas de verdad se pueden construir para proposiciones de complejidadarbitraria. Cuando una proposición involucra a más de un operador, la evalua­ción de su valor se realiza siguiendo el orden de prioridad de los operadores.Esto se ilustra en el Ejemplo 3.4.

Page 57: ComputacionI A

Lógica 49

P q pAq

P ~p

verdadero verdadero verdaderoverdadero falso verdadero falso falsofalso verdadero falso verdadero falso

falso falso falso

a) b)

p q p=q p q p<:o>q

verdadero verdadero verdadero verdadero verdadero verdaderoverdadero falso falso verdadero falso falsofalso verdadero verdadero falso verdadero falsofalso falso verdadero falso falso verdadero

e) d)

Figura 3.2. Tablas de verdad para proposICiones: (a) Negación; (b) conjun-ción; (e) implicación; (d) equivalencia.

Ejemplo 3.4. Para construir la tabla de verdad de (p v q) = '" p comenza­mos por p y q; a continuación, se deriva la tabla para cada subproposición(p v q) y ~ p, combinando finalmente los resultados utilizando la tabla deverdad de la operación =. Habitualmente se trabaja siempre de izquierda aderecha, tal y como se muestra abajo:

p q pvq ~p (p v q) = ~p

verdadero verdadero verdadero falso falsoverdadero falso verdadero falso falsofalso verdadero verdadero verdadero verdaderofalso falso falso verdadero verdadero

Una forma alternativa de construir tablas de verdad es la de escribir la opera­ción una única vez y colocar el resultado de la evaluación de cada subproposi­ción debajo del operador correspondiente. Si lo hacemos así, debemos tenercuidado de rellenar las columnas en el orden adecuado, como se muestra en latabla de verdad siguiente:

p q (p v q) = ~p

verdadero verdadero verdadero falso falsoverdadero falso verdadero falso falsofalso verdadero verdadero verdadero verdaderofalso falso falso verdadero verdadero

Page 58: ComputacionI A

50 Computación ,. Lógica, resolución de problemas, algoritmos y programas

En este caso, comenzamos rellenando las columnas de p y q; a continua­ción, rellenamos la columna de (p v q); a continuación, la de "-' p, y finalmentela columna correspondiente a =>. La tabla de verdad de la proposición comple­ta se corresponde con los valores de la última columna obtenida, que no secorresponde forzosamente con la columna de más a la derecha.

El número de filas de una tabla de verdad crece exponencialmente con elnúmero de variables presentes en la proposición. Es decir, si una proposicióntiene una variable como, por ejemplo, "-' p, su tabla de verdad tiene dos filas.Proposiciones con dos variables como p v q tienen tablas de verdad de cuatrofilas. Proposiciones de tres variables tendrán ocho filas, puesto que existen23 = 8 formas diferentes de asignar los valores verdadero y falso a las tresvariables. En general, el tamaño de una tabla de verdad con n variables será de2n filas. Por este motivo, si trabajamos con más de cuatro o cinco variables, eltamaño de las tablas de verdad resulta inmanejable.

Una forma de acortar la longitud de las tablas de verdad es mediante labúsqueda de condiciones «da igual». Por ejemplo, cuando evaluamos la propo­sición (p v p), si p vale falso, no importa lo que valga q; la proposición seevaluará a verdadero en cualquiera de los casos. Es decir, el valor de q es unaentrada «da igual», y 10 denotaremos mediante un guión (-) en la columnacorrespondiente de la tabla de verdad. Con esto, podemos reducir en uno elnúmero de filas de la tabla de verdad para p v q:

p

verdaderofalsofalso

q

verdaderofalso

pvq

verdaderoverdaderofalso

Utilizando esta técnica, se pueden reducir de forma significativa el número delíneas de las tablas de verdad de expresiones complejas, como se muestra en laFigura 3.5.

Ejemplo 3.5. La proposición (p /\ q) => (r v (p => s)) podría tener una tablade verdad completa de 16 líneas. Sin embargo, utilizando condiciones «daigual» podemos reducir su tamaño a cinco lineas, tal y como se muestradebajo:

p q r s (p 1\ q) => (r v (p => s))

falso falso verdaderofalso falso verdadero

verdadero verdadero verdadero verdadero verdadero verdadero verdaderoverdadero verdadero falso verdadero verdadero verdadero verdadero verdaderoverdadero verdadero falso falso verdadero falso falso falso

Page 59: ComputacionI A

Lógica 51

El proceso de construcción de tablas de verdad con entradas «da igual»puede ser bastante complejo, tal y como sugiere el ejemplo. Cursos avanzadosen lógica yen diseño de circuitos tratan este tema más cuidadosamente. Intuiti­vamente podemos ver que, si reducimos el número de filas en una tabla deverdad, reduciremos también la complejidad de cualquier circuito representa­do por la proposición. Esta es una de las actividades cruciales en el diseño del(ls computadoras modernas: un objetivo primordial es la minimización delnúmero de circuitos y, por tanto, la reducción del costo de fabricación de lacomputadora. Estas ideas serán abordadas en el Capítulo 7.

3.1.3. Tautologías

Algunas proposíciones se distinguen por el hecho de que son siempre verdaderas.Es decir, cualquiera que sea la asignación de valores a sus variables, siempre seobtendrá el valor verdadero en la última columna de la evaluación de la propo­sición. Formalmente, estas proposiciones reciben el nombre de tautologías.

Definición. Una tautología es una proposición que se evalúa a verdaderoen cualquier estado; una contradicción es una proposición que se evalúa afalso en cualquier estado.

Podemos comprobar si una proposición es una tautología sin más que escribirsu tabla de verdad. También existen otros métodos para comprobar si unaproposición compleja es o no una tautología. Estos métodos implican el desa­rrollo de demostraciones, y se estudiarán en la Sección 3.2.3. Las demostracio­nes de la lógica juegan un papel trascendental en la informática, por lo que lesdedicaremos un interés especial en este capítulo.

Ejemplo 3.6. Para verificar que la proposición (p 0= q) /\ p) 0= q es unatautología, podemos desarrollar su tabla de verdad y examinar la columnamás a la derecha para comprobar que todas las entradas son verdadero.

p q ((p =;. q) /\ p) =;. q

verdadero verdadero verdadero verdadero verdaderoverdadero falso falso falso verdaderofalso verdadero verdadero falso verdaderofalso falso verdadero falso verdadero

Ejemplo 3.7. La proposlcIOn' p /\ "V P es una contradicción. Esto puedeverse en la tabla de verdad siguiente:

p

verdaderofalso

falsoverdadero

falsofalso

Page 60: ComputacionI A

52 Computación l. Lógica, resolución de problemas, algoritmos y programas

Esto confirma algo intuitivo: es imposible para una proposición ser simul­táneamente verdadera y falsa. Igualmente, p v '" p es una tautología.

p

verdaderofalso

falsoverdadero

pv ~p

verdaderoverdadero

La aseveración de que p v '" p es una tautología recíbe el nombre de ley delexclusión del caso intermedio. Es decir, para cualquier proporción, ella misma osu negación deben ser cierta; no existe una tercera posibilidad. Esto significa quealgunas frases que son comunes en el lenguaje coloquial, como «la frase que estáleyendo ahora es falsa», están excluidas del cálculo proposicional. Se han desa­rrollado otros modelos lógicos que no incluyen la ley de exclusión del casointermedio; estos modelos son de gran utilidad en el estudio de las bases dedatos. La ley de exclusión del término medio, junto con el hecho de que laproposición p 1\ "-' P es una contradicción, nos indica que cualquier proposición,o es una tautología o no lo es; no puede ser ambas cosas al mismo tiempo.

Ejemplo 3.8. La proposición '" (p 1\ q) Y ('" Pv '" q) tienen la misma tablade verdad.

p q ~p ~q ~(P/\q) (~pv~q)

verdadero verdadero falso falso falso falsoverdadero falso falso verdadero verdadero verdaderofalso verdadero verdadero falso verdadero verdaderofalso falso verdadero verdadero verdadero verdadero

La aseveración de que "-' (p 1\ q) Y ('" P v '" q) tienen la misma tabla deverdad, constituye una de las tres aseveraciones que conjuntamente constitu­yen las denominadas Leyes de Margan. Estas leyes son muy útiles en la simplifi­cación de proposiciones compuestas, especialmente si contienen negaciones. Lasegunda Ley de Morgan se analiza en el ejercicio 3.6.

Ejercicios

3.1. Razonar cuáles de las frases siguientes constituyen una proposición:

a) En esta página hay 512 palabras exactamente.b) 314159 es un número primo.e) Xl + 2x + 1 = 13.d) La edad del universo es de unos 17 billones de años, aproximada­

mente.e) Disparad al pianista.

Page 61: ComputacionI A

Lógica 53

f) x - y = o.g) ¿Por qué es azul el cielo?h) La hipotenusa es el lado más corto de un triángulo rectángulo.

3.2. Construir las proposiciones siguientes a partir de variables, aplicandouna regla de la definición en cada paso.

u) (p => (p /\ q))h) ((( "-' p) -= q) /\ ( "-' r))e) «(p v ( "-' q)) /\ (p V q)) => p)

3.3. Representar las frases siguientes, de forma simbólica, utilizando proposi­ciones. Definir claramente qué significa cada variable.

a) -l~x~l,-l~y~l

b) Aunque Manderson tenía una mente fina y analítica y grandes rique­zas, estaba incomprensiblemente loco.

e) Bien Trent estaba en París mientras Mabel estaba en Londres, bienTrent estaba en Venecia mientras Mabel estaba en París.

d) Una definición es recursiva sólo si incluye un paso de inicialización yotro de inducción.

e) Siempre que Thomas y Dumars disparen bien, los Pistons ganarán, ano ser que Rodman esté lesionado y Laimber batee mal, en cuyocaso los Pistons perderán.

f) Si el grupo de diseño cometiera un error, serían los principales res­ponsables, y los demás tendrían una responsabilidad secundaria; si elgrupo de programadores cometiera un error de codificación, enton­ces el grupo de Ted o el de Louis sería el principal responsable; si elerror fuera de prueba, tanto el grupo de FouSen como el de Ritaserían los principales responsables.

3.4. De acuerdo con la definición, ¿cuáles de las siguientes son proposicionesválidas?

verdadero(verdadero)~P/\q

p => "-'q)(p V « "-' p) /\ q))(p => p) /\ « "-' q) => q)

3.5. Construir las tablas de verdad de las proposiciones siguientes, utilizandocondiciones «da igual» siempre que resulte apropiado. Identificar las tau­tologías.

a) «p => q) /\ p) => qb) «pp => r) /\ (q => ~r)) => (p /\ q)e) p /\ (q V r) => S

d) «(p =>q) /\ (q => r)) => (p => r))

Page 62: ComputacionI A

54 Computación ,. Lógica, resolución de problemas, algoritmos y programas

e) ((p => (q /\ "-'q)) => p)f) (p => q) V (p <o:> '" q)

3.6. Demostrar que '" (p v q) y ("-' P /\ "-' q) tienen la misma tabla de verdad.

3.2. RAZONAMIENTO CON PROPOSICIONES1

En esta sección se analizan algunos aspectos fundamentales del razonamientocon proposiciones. En este contexto, razonamiento significa desarrollo de nuevainformación a partir de otra dada, expresada en forma de proposiciones (ycomo predicados).

Es necesario desarrollar métodos que permitan determinar cuándo dosproposiciones son equivalentes, de forma que una pueda ser sustituida por laotra. Es también necesario encontrar una forma alternativa a las tablas deverdad, para determinar cuándo una proposición arbitraria es una tautología.Finalmente, es necesario explorar cómo los métodos de razonamiento puedenayudarnos a resolver problemas lógicos que están planteados en castellano.Todas estas técnicas constituyen una preparación necesaria para una fase pos­terior, en la que utilizaremos técnicas de razonamiento para analizar variascaracterísticas de programas escritos en Pascal (Capítulo 6) y en el diseño decomputadoras (Capítulo 7).

3.2.1. Equivalencia

Considérese la proposición (p /\ q) V (p /\ "-' q), cuya tabla de verdad se mues­tra abajo:

p q (p /\ q) V (p /\ ~q)

verdadero verdadero verdaderoverdadero falso verdaderofalso verdadero falsofalso falso falso

Los valores de la última columna de la tabla son exactamente los mismos quelos de la columna de la p; por tanto, podemos decir que (p /\ q) V (p /\ '" q) es encierta manera equivalente a p. Por tanto, si en alguna situación nos encontra­mos con (p /\ q) V (p /\ '" q) podemos sencillamente reemplazarla por p.

En cuanto empezamos a razonar con proposiciones, se ve la necesidad desimplificar proposiciones complejas. Nuestro propósito ahora será el de definirqué significa que dos proposiciones sean equivalentes, y el ver cómo esta equi­valencia permite simplificar expresiones complejas.

Definición. Se dice que dos proposiciones p y q son equivalentes si tienenel mismo valor para cada estado. En otras palabras, p y q son equivalentessi tienen la misma tabla de verdad.

Page 63: ComputacionI A

Lógica 55

Por tanto, una forma de comprobar si dos proposiciones son equivalentes esescribiendo su tabla de verdad. Existe otro método que generalmente es máseficaz, basado en el siguiente teorema.

Teorema. Dos proposiciones p y q son equivalentes y lo simbolizamoscomo p == q, si y sólo si la proposición p <:o> q es una tautología.

El teorema no es dificil de probar. Primero, supongamos que p y q sonequivalentes. Entonces en cualquier estado ambas son bien verdaderas bienfalsas. Por tanto, en cualquier estado p <:o> q es bien (verdadero <:o> verdadero)bien (falso <:o> falso) haciendo de p <:o> q una tautología. Por el contrario,supongamos ahora que p <:o> q es una tautología, y que S es un estado en que pes falso. Puesto que p <:o> q es una tautología, q tiene que ser también falso.Igualmente, si S es Un estado en que p es verdadero, entonces q también debeserlo en ese estado.

3.2.2. Propiedades de la equivalencia

La equivalencia tiene una serie de propiedades que se verifican para todas lasproposiciones, y que son de gran utilidad en varias aplicaciones de la lógica.En la Tabla 3.2 se resumen las más importantes.

Tabla 3.2. Propiedades de la equivalencia

Conmutatividad' Asociatividad

p A q == q A P P A (q A r) == (p A q) A rp v q == q v p p v (q v r) == (p v q) v r

Distributividad

p A (q V r) == (p A q) V (p A r)p v (q A r) == (p v q) A (p V r)

Ley de la implicación

p = q == ~pvq

Propiedad de la negación

~(~p) == p

Ley de la exclusión del término medio

p v ~ p == verdadero

v -simplificación

pvp == pp v verdadero == verdaderop v falso == ppV(pAq) == P

Leyes de Morgan

~(pvq) == ~pA ~q

~(pAq) == ~pv ~q

Ley de la bicondicionalidad

p<o>q==(q=q)A(q=p)

Identidad

p == p

Ley de la contradicción

pA ~p == falso

A -simplificación

pAp == PP A verdadero == pp A falso == falsop A(p V q) == p

Page 64: ComputacionI A

56 Computación ,. Lógica, resolución de problemas, algoritmos y programas

Obsérvese que muchas de estas expresiones tienen una paralela en las quefueron estudiadas para los conjuntos (véase Tabla 2.1). Además, muchas deestas propiedades tienen también una análoga en la aritmética. Así, las propie­dades conmutativa, asociativa y distributiva permiten la simplificación de ex­presiones aritméticas. De una forma similar la asociatividad, conmutatividad ydistributividad introducidas en la Tabla 3.2 permiten la simplificación de pro­posiciones lógicas.

Estas propiedades se utilizan de diversas maneras. Por ejemplo, la conmu­tatividad se utiliza para reordenar las proposiciones y así poder realizar otrassimplificaciones. La asociatividad permite la eliminación de paréntesis. Porejemplo, puesto que p /\ (q /\ r) == (p /\ q) /\ r, de forma equivalente es posibleescribir p /\ q /\ r. Las leyes de la distributividad permiten la factorización de lasproposiciones. Esta leyes totalmente equivalente a la ley aritmética que permi­te escribir 3 x 5 + 3 x 7 = 3 x (5 + 7). Las leyes de Morgan son de granutilidad cuando se trabaja con expresiones que incluyen negaciones. La ley dela implicación permite escribir expresiones equivalentes a la implicación, peroutilizando sólo v, /\ Y "'.

Antes de utilizar las leyes de la equivalencia es necesario convencerse deque son correctas. Para ello es suficiente construir una tabla de verdad paracada lado de la equivalencia y verificar que ambas tablas son idénticas. De­mostraremos lo anterior para la ley de la implicación, dejando el resto comoejercicio.

Ejemplo 3.9. Para demostrar que (p ~ q) == ('" p v q), podemos construirsus tablas de verdad de la forma siguiente:

p q p=q -pvq (p = q)~(-pvq)

verdadero verdadero verdadero verdadero verdaderoverdadero falso falso falso verdaderofalso verdadero verdadero verdadero verdaderofalso falso verdadero verdadero verdadero

Simplificación de proposiciones mediante la utilización de las propiedades de laequivalencia. Centremos nuestra atención en la simplificación de proposicio­nes. Entendemos por simpllfzcación el proceso de modificar una proposiciónpara que resulte más útil a un determinado propósito, como el conseguir quecontenga menos variables y/o operadores que la proposición original.

Para simplificar una proposición, escribimos una serie de pasos numerados.Cada paso se compone de una proposición en la parte izquierda, y de unareferencia a una ley particular en la parte derecha. La proposición de la iz­quierda es siempre equivalente a la del paso inmediatamente anterior, en vir­tud de la propiedad escrita en la derecha. Por ejemplo, supongamos que sedesea reducir la proposición (p ~ q) v (p ~ r). En el paso 1 se escribe laproposición, y los pasos 2 al 4 contienen las proposiciones equivalentes.

Page 65: ComputacionI A

1. (p => q) /\ (p => r)2. (- p v q) /\ ( - P v r)3. '" p v (q /\ r)4. p => (q /\ r)

Ley de implicaciónDistributividadLey de la implicación

Lógica 57

Donde puede observarse que la proposición del paso 2 resulta de la del paso 1,tras la aplicación de la ley de la implicación. La del paso 3 se obtiene de ladel '2 aplicando la distributividad, y la del 4 se obtiene de la del 3 por la ley dela implicación. El Ejemplo 3.10 es más complicado:

Ejemplo 3.10. En el Ejercicio 3.5a se utilizó una tabla de verdad parademostrar que la proposición ((p => q) /\ p) => q es una tautología. Puedenutilizarse las propiedades de la equivalencia para demostrar de nuevo quelo es. En este caso demostraremos que la proposicíón anterior es equivalen­te a la proposición simple verdadero.

1. ((p => q)/\p) => q2. ((-pvq)/\p) => q3. (( - P /\ p) V (q /\ p)) => q4. (falso v (q /\ p)) => q5. (q /\ p) => q6. - ((q /\ p) /\ - q)7. - ((p /\ q) /\ - q)8. - (p /\ (q /\ - q))9. -(p/\falso)

10. - falso11. verdadero

Ley de implicaciónDistritibutividadContradicciónv -simplificaciónLey de la implicaciónConmutatividadAsociatividadLey de la contradiccíón/\ -simplificaciónNegación

El ejemplo 3.10 se ha desarrollado con excesivo detalle; cada propiedad seha aplicado en un paso separado. Cuando nos familiaricemos más con estaspropiedades, será posible abreviar los cálculos. De hecho, es lo mismo que enel caso del álgebra, donde nuestra familiaridad y costumbre en la manipulaciónde expresiones complejas nos permite la simplificación mediante la aplicaciónde varias reglas a la vez. Como ejemplo, obsérvense las dos simplificacionessiguientes:

1. 5x + 1 = 3x + 22.2x=13. x = 1/2

1. 5x + 1 = 3x + 22. (5x + 1) - 1 = (3x + 2) - 13. 5x + (1 - 1) = 3x + (2 - 1)4. 5x + O = 3x + 15. 5x = 3x + 16. 5x - 3x = (3x + 1) - 3x7. (5 - 3)x = (1 + 3x) - 3x8. 2x = 1 + (3x - 3x)9. 2x = 1 + (3 - 3)x

10. 2x = 1 + Ox

Page 66: ComputacionI A

58 Computación ,. Lógica, resolución de problemas, algoritmos y programas

11. 2x=112. (1/2)2x = 1/213. ((1/2)2)x = 1/214. Ix = 1/215. x = 1/2

La simplificación en tres pasos de la izquierda es lo habitual cuando seconocen bien las propiedades de la aritmética, mientras que la simplificaciónen 15 pasos es lo habitual en los aprendices del álgebra. Con este libro sepretende alcanzar un conocimiento suficiente de la lógica, de manera que lassimplificaciones se parezcan más a la de la izquierda, es decir, que se realicenaplicando varias leyes en cada paso. Sin embargo, el conocimiento de laspropiedades en que se basan estos argumentos, es fundamental para entenderclaramente el proceso realizado.

El ejemplo 3.11 muestra una serie de pasos más corta, en la simplificaciónde la proposición (p => (q /\ r)) /\ (~p => (q /\ s)). En ella q aparece como partedel consecuente de dos condiciones diferentes, que están conectados con eloperador /\. En la simplificación se extrae q de ambas, de forma que la propo­sición puede escribirsé como la conjunción de q con dos implicaciones.

Ejemplo 3.11. Simplificar la proposición (p => (q /\ r)) /\ (~p => (q /\ s)):

1. (p => (q /\ r)) /\ (~ p => (q /\ s))2. (~ p v (q /\ r)) /\ (p V (q /\ s))3. (~ p v q) /\ (~P v r) /\ (p V q) /\ (p V s)4. (( ~ P /\ p) V q) /\ (~ Pv r) /\ (p V s)

Ley de la implicación, negaciónDistributividad, asociatividadConmutatividad,distributividadLey de la contradicciónv -simplificaciónLey de la implicación

3.2.3. Reglas de inferencia: La idea de demostración

Cuando se estudia la lógica, el primer objetivo es el de conseguir patrones derazonamiento. Sería deseable encontrar una metodología que nos permitieraafirmar cuándo una determinada conclusión es válida -es decir, si es o no unatautología-o Sabemos que las tablas de verdad son un buen instrumentocuando trabajamos con proposiciones sencillas, pero que resultan tediosascuando las proposiciones contienen más de tres o cuatro variables u operado­res.

Por tanto, pretendemos encontrar una metodología alternativa que nospermita llegar a conclusiones válidas de una forma legítima. En dicha metodo­logía, denominada demostración, el criterio de razonamiento consiste en elencadenamiento de una serie de pasos o inferencias, cada una de las cuales esencadenable con la siguiente de una manera justificable formalmente. El proceso

Page 67: ComputacionI A

Lógica 59

de demostración es una extensión de la metodología desarrollada para simpli­ficar proposiciones. Sin embargo, las demostraciones contienen un ingredienteadicional de gran importancia: se realiza una inferencia a partir de una suposi­ción. Las inferencias de una demostración se realizan aplicando un reducidoconjunto de reglas de inferencia. Es decir, las reglas de inferencia permitenobtener proposiciones a partir de otras, de las que se conocen si son verdade­ras o se supone que lo son. Estas reglas se resumen en la Tabla 3.3.

Definición. En el cálculo proposicional, una demostración es una secuen­cia de pasos que sirven para demostrar que una determinada proposición pes una tautología. Cada paso de la demostración es bien una proposiciónya demostrada, bien una proposición que se ha obtenido de otra anteriorutilizando una regla de inferencia, o bien una proposición que se introducecomo suposición para preparar un paso posterior. Este último tipo deproposiciones (suposición) lo simbolizamos poniéndolo entre corchetescuadrados [y]; todos los demás pasos se acompañan de una justificación; yel último paso de la demostración debe ser la propia p.

La sencilla prueba del ejemplo 3.12 muestra que p => p es una tautología.Podríamos demostrar esto utilizando una tabla de verdad, pero representa unabuena oportunidad para introducir la notación y estilo de las demostraciones.

Ejemplo 3.12. Demostrar p => p:

1. [p]2. p3. p => p

1=>-introducción, 1, 2

La primera línea contiene la suposición [p]. Al comienzo de la demostración,podemos suponer cualquier cosa que creamos que puede llevarnos a la con­clusión.La suposición, junto con los pasos subsiguientes que se obtienen de ellas,sueñalen presentarse sangrados, de forma que la lógica de pasos subsiguientespueda distinguirse del resto de la prueba. Puesto que suponemos que p esverdadero, se puede deducir que p es verdadero, luego el paso 2 se obtiene del 1directamente. Colocamos un «1» en la columna de la derecha de la demostra­ción como justificación del paso realizado. A continuación utilizamos la reglade inferencia de la =>-introducción (sustituyendo p por q en la fórmula generalde la Tabla 3.3) con lo que se concluye en el paso 3 que p => p es unatautología.La Tabla 3.3 fue desarrollada por el matemático alemán Gerhard Gentzen.En ella se reflejan las reglas de inferencia que se utilizan en el razonamientonormal, y que constituyen las bases de la mayoría de los estudios y aplicacio­nes de la lógica formal. Cada regla de la tabla tiene la forma:

p

q

Page 68: ComputacionI A

60 Computación l. Lógica, resolución de problemas, algoritmos y programas

P/\q-q-

Tabla 3.3.

=-introducción

[p]

-q-­p=q

=-eliminación

(modus ponens)p=p

-p-q

(modus tollens)p=q

::!L~p

/\ -introducción

p

-q­P/\q

/\ -eliminación

P/\q-p-

Reglas de inferencia

~-introducción

p=qq=pp~q

~-eliminación

p~q p~q

p=q q=p

~ -introducción

[p]falso~p

~ -eliminación

falsop

v -introducción

-p- -q-pvq pvq

v -eliminación

[p] [q]pv q r rr

La propoSlclOn p que aparece encima de la línea indica un paso anterior(suposicióq u otro) que ya aparece en la demostración. La proposición q queaparece debajo de la línea puede obtenerse o ser iriferida en el siguiente paso dela demostración. Asi, la regla denominada =>-introducción en las tablas permiterealizar la inferencia p => q en cualquier paso de la demostración, en la que paparece como suposición y q como conclusión en un paso subsiguiente.

Una comparación cuidadosa entre estas reglas y algunas de las propiedadesde la equivalencia que se muestran en la Tabla 3.2, pone de manifiesto algunassimilitudes interesantes. Por ejemplo, la ley de la bicondicionalidad dada enla tabla, conduce directamente a las dos reglas de inferencia denominadas<=>-introducción y <=>-eliminación de la Tabla 3.3. De forma similar, la ley de lacontradicción de la Tabla 3.2 conduce directamente a la regla de inferencia dela ~ eliminación. Sin embargo, muchas de las reglas de inferencia no tienenningún precedente, entre las propiedades de la equivalencia.

Las reglas de inferencia pueden utilizarse como alternativa a las tablas deverdad en la demostración de que una determinada proposición es una tauto­logía. Sin embargo, como veremos más adelante, las demostraciones son más

Page 69: ComputacionI A

Lógica 61

versátiles que las tablas de verdad, puesto que las tablas de verdad son inmane­jables cuando analizamos las proposiciones de más de tres o cuatro variables, yademás no aportan ninguna base para razonar con proposiciones de formadeductiva.

Podemos autoconvencernos, de forma intuitiva, de que las reglas de infe­rencia tienen sentido. Por ejemplo, la regla de la 1\ -introducción nos dice que sihllmos demostrado que p y q son tautologías en dos pasos anteriores cuales­quiera de la demostración, en el paso actual podemos concluir que p 1\ q es unatautología. De forma similar, la regla de la ==>-eliminación (conocida familiar­mente como modus ponens), simplemente establece que, si en un paso anteriorhemos demostrado que p ==> q y que p es una tautología, en el paso actualpodemos concluir que q es una tautología.

En las demostraciones procederemos paso a paso para conseguir, en cadauno de ellos, una nueva tautología que nos acerque más a nuestra meta -laúltíma proposición de la prueba--. Justificaremos cada paso realizado, bien enla utilización de una regla de equivalencia (mediante la sustitución de unaparte derecha de una expresión de la Tabla 2.3, por una parte izquierda, o vi­ceversa), bien mediante la utilización de una regla de inferencia. Adicionalmen­te a lo anterior, es preciso desarrollar estrategias de demostración; es decir, mé­todos de realizar demostraciones que puedan ser de utilidad en diferentessituaciones. Estas situaciones se dan no sólo en la lógica, sino también envarias aplicaciones de la informática, las matemáticas y la ciencia en general.

3.2.4. Estrategias de demostración

En esta sección se estudian algunas estrategias básicas para demostrar que unaproposición es una tautología, mediante la utilización de las propiedades de laequivalencia y las reglas de inferencia.

Demostración deductiva. Una demostración deductiva es aquella en que seutilizan las reglas de inferencia para deducir las conclusiones, después de haberrealizado una o más suposiciones para comenzar el proceso de demostración.El ejemplo 3.13 es un ejemplo sencillo.

Ejemplo 3.13. Demostrar que p ==> (q ==> p)

1. [p]2. [q]3. p4. q => p5. p ==> (q => p)

SuposiciónSuposición1=>-introducción, 2, 3=>-introducción, 1, 4

Si se intenta demostrar que una proposición de la forma p ==> q es una tautolo­gía, es aconsejable comenzar suponiendo p y tratar de encontrar una serie depasos que nos conduzcan a q. Si lo conseguimos, el último paso de la demos-

Page 70: ComputacionI A

62 Computación J. Lógica, resolución de problemas, algoritmos y programas

tración será la propia p ~ q. Esta estrategia fue utilizada en los Ejemplos 3.12y 3.13.

Utilización del modus ponens. Supongamos que alguien dice: «Si abres lajaula, se escapará el tigre» y supongamos que yo abro la jaula. La conclusiónseguramente será, por modus ponens, que el tigre escapará. Análogamente, sioimos a alguien decir: «Si representan Nuestra Ciudad, compraré entradas», ydescubrimos que están representando Nuestra Ciudad, podemos concluir queesa persona comprará entradas. En el Ejemplo 3.14 podemos ver cómo seutiliza el modus ponens en una demostración.

Ejemplo 3.14. Demostrar que ((p ~ q) 1\ (r ~ p) 1\ r) ~ q:

1. ((p ~ q) 1\ (r ~ p) 1\ r)2. r ~ p3. r4. p5. p ~ q6. q7. ((p ~ q) 1\ (r ~ p) 1\ r) ~ q

Suposición1\ -eliminación, 11\ -eliminación, 1Modus ponens, 2, 31\ -eliminación, 1Modus ponens, 4, 5~-introducción, 1,6

Utilización de la I\-eliminación y modus tollens. En el Ejemplo 3.15 se desa­rrolla una demostración utilizando una combinación de las reglas de inferenciaI\-eliminación y modus ponens. Como en casos anteriores, se parte de suposi­ciones cuidadosamente elegidas y trabajamos deductivamente a partir de ellas.

Ejemplo 3.15. Demostrar ((p ~ q) 1\ '" q) ~ '" p:

1. [(p ~ q) 1\ '" q]2. p ~ q3. '" P4. '" P5. ((p ~ q) 1\ '" q) ~ '" p

Suposición1\ -eliminación, 11\ -eliminación, 1Modus tollens, 2, 3~-introducción, 1, 4

Utilización de la '" -eliminación y de la '" -introducción. La segunda regla de'" -eliminación dice que cuando partimos de una suposición falsa cualquierconclusión p es una tautología. Así, podemos realizar una argumentación lógi­ca muy sofisticada en la que una suposición no válida (no importa cómo denimia pueda ser ésta) hace que todos nuestros razonamientos sean erróneos.Muchas argumentaciones pueden ser válidas, tanto en cuanto no dependan desuposiciones falsas.

Ejemplo 3.16. Demostrar, sm utilizar modus tollens, la proposición((p ~ q) 1\ "'q) ~ p:

Page 71: ComputacionI A

Lógica 63

[p]q"'qfalso

1.2.3.4.5.6.1-8. '" P9. ((p ~q)A "'q) ~ ",p

SuposiciónA -eliminación, 1A -eliminación, 1SuposiciónModus ponens, 23'" -eliminación 5, 6'" -introducción, 4~-introducción, 1, 8

El ejemplo 3.17 es algo más complicado.

Ejemplo 3.17. Demostrar (p ~ (q ~ r)) ~ ((p ~ q) ~ (p ~ r)):

[p ~ (q ~ r)][p ~ q]

[p]qq~r

r

1.2.3.4.5.6.7. P ~ r8. (p ~ q) ~ (p ~ r)9. (p ~ (q ~ r)) ~ ((p ~ q) ~ (p ~ r))

(La justificación de los distintos pasos de la demostración se dejan al lectorcomo ejercicio.)

Utilización de la bicondicionalidad en las demostraciones. Para demostracio­nes de proposiciones de la forma p ~ q, una estrategia que suele ser eficaz esdemostrar primero que p ~ q y después que q ~ p, utilizando posteriormentela regla de la ~-introducción como último paso de la demostración.

SuposiciónSuposicionSuposiciónA-introducción, 2, 3'" -introducción, 4'" -eliminación, 5~-introducción, 3, 6Suposición

['" p v q]["'p]

[p]pA ",pfalsoq

p~q

[q]

Ejemplo 3.18. Para demostrar que (p ~ q) ~ ('" p v q), primero se de­muestra que (p ~ q) ~ ('" p ~ q) es una tautología (pasos 1-13), y poste­riormente se demuestra que ('" p v q) ~ (p ~ q) es una tautología (pasos14-22). Finalmente, se aplica la regla de la ~-introducción como últimopaso de la demostración. La estrategia seguida en los pasos 1-11 parademostrar que p ~ q puede realizarse suponiendo '" p (paso 2) o bien q(paso 8).

1.2.3.4.5.6.7.8.

Page 72: ComputacionI A

64 Computación l. Lógica, resolución de problemas, algoritmos y programas

9. [p]

In q

11. p=>q

12. p => q

13. ( '" Pv q) => (p => q)

14. .[p => q]

15. pv"'p16. [p]17. q18. "'pvq

19. ["'p]

20. '" p v q

21. "'pvq22. (p => q) => ('" p v q)

23. (p => q) ~ ('" p v q)

Suposición8=>-introducción, 9, 10

v-eliminación, 1, 2

=>-introducciónSuposiciónLey de exclusión del caso intermedio

SuposiciónModus ponens, 14, 16

v -introducción, 17Suposiciónv -introducción, 19v -eliminación, 15, 16, 18, 19, 20

=>-introducción, 14, 21

~-introducción, 13, 22

Demostración por contradicción (reducción al absurdo). La regla de inferencia

de la '" -introducción es la base de una importante estrategia de demostración

conocida como demostración por contradicción. Una aplicación típica de esta

técnica en las matemáticas podría ser la siguiente: Sea T un triángulo de lados

2, 3 Y 4. Supongamos que queremos demostrar que T no es un tríángulo

rectángulo. Si suponemos lo contrario, que T es un triángulo rectángulo, pode­

mos concluir por el teorema de Pitágoras que la longitud de la hipotenusa,

elevada al cuadrado, es igual a la suma de los cuadrados de los otros dos lados;

esto es, 22 + 32 = 42• Sin embargo, 4 + 9 i= 16. Esto conduce, utilizando la

eliminación, al valor falso. Entonces, por la '" -inducción, la hipótesis original

-T es un triángulo rectángulo- es también falsa.

Supongamos que queremos demostrar que «p => q) /\ p) => q es una tauto­

logía. Supongamos que es falsa en cualquier caso -es decir, que la negación es

una tautología- y analicemos si esta suposición nos conduce a una contradic­

ción. Esta es la estrategia seguida en el ejemplo 3.19.

Ejemplo 3.19. Demostrar «p => q) /\ p) => q:

1. ['" «(p => q) /\ p) => q)]

2. ",(",«p => q)/\p)vq)

3. '" q4. «p => q) /\ p)5. (p => q)6. p7. q8. Falso9. «p => q) /\ p) => q

Suposición=>-eliminación, 1Ley de Morgan, /\-eliminación, 2

/\-eliminación, 2/\ -eliminación, 4/\-eliminación, 4Modus ponens, 5, 6

'" -eliminación, 3, 7

'" -introducción, 1, 8

Page 73: ComputacionI A

Lógica 65

3.2.5. Resolución de problemas de la vida real

La lógica y los métodos de demostración pueden utilizarse en una granvariedad de problemas lógicos o problemas de la vida real, en los que puedeobtenerse información nueva, a partir de una pequeña cantidad de informa­ción inicial. En los Ejemplos 3.20 y 3.21 se utilizan las propiedades de la~quivalencia, las reglas de inferencia y las técnicas de demostración:

Ejemplo 3.20. Los deseos son caballos, a condición de que los caballosno vuelen. También, los mendigos no cabalgan, a condición de que losdeseos no sean caballos. Si se da el caso de que los mendigos cabalgan ylos deseos no sean equinos, entonces los caballos vuelan. Si la imposibi­lidad de los caballos para volar y la imposibilidad de los mendigos paracabalgar no son alternativas, entonces los mendigos no son ricos. Perolos mendigos cabalgan, ¿son ricos los mendigos?

El primer paso para resolver problemas como este, es el de introdu­cir variables que representen cada una de las proposiciones básicas quecontiene. Como suele ser habitual en problemas de la vida real, como eseste, las frases constituyen un pequeño jeroglífico que hay que descifrar.En cualquier caso, supongamos que introducimos las variables siguientes:

WHFBRDBRCH

Los deseos son caballosLos caballos vuelanLos mendigos cabalganLos mendigos son ricos

Es posible representar las cinco frases de que consta el problema origi­nal mediante las proposiciones siguientes, respectivamente:

1. -HF ~ W2. - W ~ - BRD3. - (BRD /\ - W) ~ HF4. - ( - HF v - BRD) ~ - BRCH5. BRD

Utilizándolas igual que utilizaríamos suposiciones en una demostraciónordinaria, es posible escribir la serie de inferencias siguiente, haciendoreferencia la última a la variable BRCH que es la que nos interesa:

6. W7. -BRDv W ~ HF8. -BRDv W9. HF

10. BRD/\HF11. (HF /\ BRD) ~ - BRCH12. -BRCH

Modus tollens, 2, 5Leyes de Morgan, 3v-introducción, 6

Modus ponens, 7, 8/\-introducción, 5, 9Leyes de Morgan, 4Modus ponens, 10, 11

Con lo que se demuestra que los mendigos no son ricos.

Page 74: ComputacionI A

66 Computación /. Lógica, resolución de problemas, algoritmos y programas

Ejemplo 3.2.1. Los martes, o Timson está en el cementerio o Agnesestá en la sacristía. No es posible encontrar a Timson en el cementeriosin Stanley. Stanley sólo abandona los martes el cementerio, cuando vaa pasear con Agnes. Si Hutchinson cometió el robo, Stanley no estabaen el cementerio. El robo se produjo en martes. ¿Pudo ser Hutchinsonel ladrón?

Utilicemos las variables siguientes:

p Timson estaba en el cementerioq Agnes estaba en la sacristías Stanley estaba en el cementerioh Hutchinson fue el ladrónu El robo fue en martes

Ahora es posible simbolizar el párrafo problema de la forma siguiente:

1. u => (p V q)2. p => S

3.4.5.

S

q=>sS

~h

Para poder deducir algo sobre la variable h, que es la que nos interesa,podemos razonar de la manera siguiente:

Modus ponens, 1, 5SuposiciónModus Tollens, 3, 7=>-introducción, 7, 8v-eliminación, 2, 6, 9

Modus tollens, 4, 10

6. pvq7. [q]8.9.

10.11.

Por 10 que Hutchinson no fue el ladrón.

Ejercicios

3.7. Utilizar tablas de verdad para demostrar que las expresiones siguientesson equivalencias.

a) p v (q /\ r) == (p v q) /\ (p V r)b) ~(pvq) == ~p/\ ~q

c) p => q == ~(p /\ "'-'q)d) p v falso == pe) p /\ verdadero == pf) P /\ (p V q) == p

3.8. Encontrar todas las correspondencias entre las propiedades de la equiva­lencia entre proposiciones (Tabla 3.2), y las propiedades de la equivalen­cia entre conjuntos (Tabla 2.1).

Page 75: ComputacionI A

Lógica 67

3.9. Simplificar las proposiciones siguientes, encontrando otra equivalentecon menos operadores y/o variables:

a) (pvq)/\("'pv"'q)b) (p /\ q) V (p /\ '" q) V ( '" P /\ q) V ( '" P /\ '" q)e) p v ( '" P /\ q)d) '" p ~ pe) p ~ '" pf) ((p /\ q) ~ p) ~ (p v q)g) (p~(q/\"'q))~ "'p

3.10. La función nand se define mediante la tabla de verdad siguiente:

p q p nand q

verdadero verdadero falsoverdadero falso verdaderofalso verdadero verdaderofalso falso verdadero

Demostrar que los operadores "', /\, V Y~ pueden definirse utilizandola función nand. Es decir, encontrar proposiciones construidas sólo conp's, q's y operadores nand cuyas tablas de verdad sean iguales a las de'" p, p v q, P /\ q Y P ~ q, respectivamente.

3.11. Justificar los pasos realizados en cada una de las demostraciones si­guientes:

a) ((p ~ q) /\ (q ~ r)) ~ (p ~ r)(( '" p v q) /\ ( '" q v r)) ~ ('" p v r)'" (( '" p v q) /\ ('" q v r)) v ('" p v r)( '" ( '" p v q) v '" ( '" q v r)) v ( '" p v r)(p /\ '" q) V (q /\ '" r) v ( '" p v r)((p /\ '" q) V '" p) v ((q /\ '" r) v r)( '" p v (p /\ '" q)) v (r v (q /\ '" r))(",pvp)/\("'pv ",q))v(rvq)/\(rv "'r))verdadero /\ ( '" Pv '" q) v (r v q) /\ verdadero( '" p v '" q) v (r v q)'" p v (q v '" q) v r'" p v verdadero v rverdadero

b) (p~(q/\"'q))~ "'p(p ~ falso) ~ '" p'" (p /\ '" falso) ~ '" p'" (p /\ verdadero) ~ '" p~p ~ "'p"'pvpverdadero

Page 76: ComputacionI A

68 Computación l. Lógica, resolución de problemas, algoritmos y programas

3.12. Demostrar que las proposiciones siguientes son tautologías, utilizandoreglas de equivalencia que las hagan equivalentes al valor verdadero:

a) (-pvq)=>(qv-p)b) (p => q) ~ (-q => -p)e) (p => - p) => - pd) «p v q) 1\ ""' p) => qe) (p v q) 1\ (p => s) 1\ (q => s)) => S

f) «p => q) 1\ (p => r)) => (p => q 1\ r)g) «p => q) 1\ (r => s)) => «p v r) => (q V s))h) «p => q) 1\ (r => s) 1\ ( - q v s)) => ""' PV - r

313. Utilizando reglas de inferencia, demostrar cada una de las tautologíasdel Ejercicio 3.12.

3.14. Dada la proposición «p v q) 1\ ""' p) => q.

a) Demostrar que es una tautología, utilizando una tabla de verdad.b) Demostrar que es equivalente a la oración siguiente, si se realiza

una asignación apropiada de variables a cada frase.«O los Red Sox son mejores que los A-es o los Piratas son

mejores que los Red. Los Red Sox no son mejores que los A-es. Portanto, los Piratas son mejores que los Red.»

e) Demostrar que la proposición es una tautología, utilizando lasequivalencias y reglas de inferencia apropiadas. Ayuda: comenzar lademostración suponiendo que el lado derecho de la implicación esverdadero y concluirla utilizando la regla de la =>-introducción.

3.15. Desarrollar una demostración para cada una de las tautologías siguien­tes, utilizando reglas de inferencia.

a) «p => r) 1\ (r => q)) => (p => q)b) «p v q) 1\ (p => s) 1\ (q => s)) => S

3.16. En la isla Paradoja, todos sus residentes pertenecen a uno de dos clanes.Los miembros de uno de los dos clanes siempre dicen la verdad, mien­tras que los del otro siempre mienten. Un visitante de la isla Paradoja seencuentra con tres nativos. Einstein, Planck y Bohr. Einstein dice: «obien Bohr o bien yo pertenecemos a un clan distinto de los otros dos.»¿A qué clan pertenece Bohr? *

3.17. Abigail, Bridget y Claudia cenan a menudo juntas. Después de cenartoman café o té. Si Abigail pide café, entonces Bridget pide lo mismoque Claudia. Si Bridget pide café, entonces Abigail pide lo contrario delo que pida Claudia. Si Claudia pide té, entonces Abigail pide lo mismo

* Adaptado del libro de GEORGE J. SUMMERS, titulado The Great Book C?f Mind Teasers andMind Puzzles, Ed. Sterling Publishing Co., Nueva York, 1986.

Page 77: ComputacionI A

Lógica 69

que Bridget. ¿Cuál de las tres (si es que existe) pide siempre lo mismodespués de cenar?

3.3. LÓGICA DE PREDICADOSLa programación puede considerarse como una actividad dirigida por un objeti­vo. ~s decir, el propósito de un programa puede describirse como la consecuciónde una tarea, que genera una salida de un determinado tipo. Por tanto, el puntode partida en la construcción de un programa es la definición de la salida que seespera que produzca. Otra tarea a completar en la construcción de programasestá estrechamente relacionada con la anterior. Definir un conjunto de condicio­nes que describan todas las entradas posibles para las que el programa produzcala salida deseada. Suele definirse primero la salida, porque describe el objetivodel programa. Para entender esto, considérese el problema de encontrar todaslas posibles rutas para viajar en automóvil desde Cleveland a Dretoit. Pararesolver este problema, no solemos analizar todas las carreteras que salen deCleveland y ver cuáles llegan a Detroit; lo normal es localizar Detroit y desdeahí ver sólo cuáles son las posibles carreteras que llegan desde Cleveland.

Para el diseño de problemas, necesitamos un lenguaje muy preciso paradescribir entradas y salidas. Por ejemplo, supongamos que queremos construirun programa que reorganice una lista de 30 enteros, de forma que los deje enorden descendente (a este proceso se le conoce vulgarmente como ordenación).Podemos describir, informalmente, las entradas y salidas de la forma siguiente:

Entrada = Cualquier lista de treinta enterosSalida = Los 30 enteros originales, en orden descendente

Sin embargo, esta forma de descripción suele no ser lo suficientemente precisapara definir un problema. Por ejemplo, no se da un criterio para determinarque los enteros están en orden descendente. Esto puede parecer trivial, puestoqe todos tenemos una idea clara de lo que esto significa. Esto es debido a que,por la experiencia que compartimos, damos por hecho que conocemos estainformación. Sin embargo, una computadora no tiene estas ventajas, y enalgún punto del proceso de programación tenemos que indicarle un métodocon el que determinar si la lista de enteros está ordenada en orden descendenteo no. Por tanto, una descripción más precisa es la siguiente:

EntradaSalida

Cualquier lista A = (el' el' ..., e30 ) de enteros.Una lista B = (e'¡, e~, ..., e30) permutación de A para la que severifica que eí+ 1 ~ eí para cada entero i en el intervalo 1 al 29,ambos inclusive.

Esta descripción alternativa clarifica la relación entre la entrada y la salida, yaporta una definición no ambigua de lo que significa «en orden descendente».

Aunque nuestra segunda definición es más precisa que la primera, tambiénes más prolija. Es, por tanto, necesario encontrar una notación más sintéticapara expresar los estados de entrada, salida y otros intermedios del programa.

Page 78: ComputacionI A

70 Computación l. Lógica, resolución de problemas, algoritmos y programas

Esta notación puede ser la denominada «lógica de predicados», que no es más

que una extensión de la lógica proposicional presentada en las Secciones 3.1

y 3.2. En esta sección se introduce la notación básica de la lógica de predica­

dos, junto con las nociones necesarias para trabajar con ella y utilizarla en la

descripción de los estados de los programas.

Las descripciones de entrada y salida anteriores no son más que formas

relajadas 'de predicados. De forma intuitiva, podemos considerar un predicado

como una frase que incluye variables, las cuales, al tener un determinado valor,

convierten la frase en una proposición.

Definición. Un predicado es un aserto constituido por constantes aritméti­

cas y booleanas (números enteros, reales y los valores lógicos verdadero y

falso); variables aritméticas y booleanas, operaciones aritméticas (=, *, etc.);

operaciones relacionales (<, ~, >, ~, =, i=, E, etc.) y operadores lógicos

(1\, v, ~, etc.), que tiene el valor verdadero o falso dependiendo de los

estados de sus variables.

En Pascal, este tipo de predicados se conocen con el nombre de expresiones

booleanas, y tienen gran cantidad de usos en programación.

En la Sección 3.1 se definió la sintaxis de las proposiciones de forma preci­

sa. Podríamos hacer lo mismo con los predicados; sin embargo, en su lugar,

utilizaremos nuestros conocimientos y experiencia con ese tipo de expresiones

en otros campos de las matemáticas~especialmente álgebra y programa­

ción- junto con los conocimientos adquiridos sobre proposiciones. Comence­

mos destacando que cualquier proposición es también un predicado.

Ejemplo 3.22. Las proposiciones siguientes son también predicados. Las

expresiones equivalentes en Pascal se muestran a la derecha.

x < 10 x < 10

i2 + / = 25 i*i + j*j = 25

al < a 2 1\a 2 < a3(a[1] < a([2]) and (a[2] < a[3])

Obsérvese en el tercer predicado del Ejemplo 3.22 que, aunque no es necesario

utilizar paréntesis para representar el predicado, si 10 es en la expresión en

Pascal equivalente. Esto es debido a que los operadores 1\ y v tienen menor

prioridad que los operadores relacionales «, ~, >, etc.). Sin embargo, en

Pascal, los operadores and y or tienen una prioridad mayor que los operadores

relacionales «, ~, >, etc.) en una expresión booleana. Por ello, para conse­

guir una interpretación equivalente, es necesaria la utilización de paréntesis *.

Las expresiones siguientes no son predicados:

i + 1y2 < 10 i=x := x + 1

* Para una mayor información sobre las expresiones booleanas en Pascal, consúltese el

manual de laboratorio.

Page 79: ComputacionI A

Lógica 71

i + 1 no es un predicado, puesto que no tiene un valor lógico; simplemente esuna expresión aritmética que tiene un valor numérico. y2 < 10 :1: podría serlo,si hubiera otra expresión a la derecha del símbolo :1:; pero, tal y como estáescrita, carece de significado. La expresión x := x + 1 es una instrucción válidaen Pascal, pero no es una expresión que tenga un valor lógico.Es posible evaluar un predicado reemplazando todas sus variables por susvalpres, en un determinado estado, y calcular el resultado utilizando las leyesde la aritmética. Así, x < 10 se evalúa a verdadero en el estado x = 1, Ya falsoen el estado x = 11. Decimos que x = 1 es un estado que satisface el predica­do x < 10. A un predicado que posee estado en el que puede ser satisfecho, sele denomina satisfactible. Por ejemplo, el predicado x < 10 es satisfactible,mientras que el predicado 11 < 10 no es satisfactible.

Definición. Un predicado que se satisface en cada estado se dice que esválido.

Por ejemplo, si i es un entero, el predicado i ~ Ov i ~ 1 es válido, puesto quees verdadero para cualquier valor de i. Por tanto, el concepto de validez paralos predicados es como la noción de tautología para las proposiciones.

Ejemplo 3.23. Los predicados se utilizan frecuentemente en la definiciónde conjuntos. Por ejemplo, en cada una de las definiciones siguientes, elconjunto definido contiene todos los estados que satísfacen el predicadoque haya la derecha de la barra vertical. El apartado d utiliza cadenas decaracteres como dominio; el dominio del resto de las variables es el conjun­to de los números naturales N.

a) {(i, j) I i < j}b) {(i,j) I i 2 + / = 25)}c) {(a o, al' a2) I ao = máx(a 1, a2)}d) {(Si' S2) / Sl es un prefijo para S2}e) {(i, j) I i < j v j = O}f) {(i, j) I i2 + / = 25 1\ j > 2}

3.3.1. Los cuantificadores universal y existencial

Recuérdese de un ejemplo anterior, que es posible describir la salida de unprograma como una lista de la forma

B = (e'¡, eí, ..., e30)

que es una permutación de otra lista A, y que tiene la propiedad de que para ientre 1 y 29, ambos inclusive, ej+ 1 ~ ej. Esta frase es la conjunción de dos

Page 80: ComputacionI A

72 Computación l. Lógica, resolución de problemas, algoritmos y programas

predicados. El primero, «B es una permutación de A», es un predicado contreinta variables. El segundo, «para cada i entre 1 y 29, ambos inclusive, ei+ 1

~ ~ ei», contiene 29 predicados de la forma ei + 1 ~ e¡, uno por cada enteroentre el 1 y el 29. Es decir, sirve como abreviatura para el predicado

Debido a que expresiones como «para cada», «para todo», «para cadauno» aparecen con frecuencia en matemáticas y lógica, todos ellos se simboli~

zan de forma abreviada con el símbolo V, denominado cuantificador universal.En el ejemplo, podemos escribir la frase:

«para cada i entre 1 y 29, ambos inclusive, ei+ 1 ~ eiVi E {1, 2, ..., 29}: e¡+ l ~ e;

como

donde, a continuación del símbolo V, aparece un predicado que indica el domi­nio de la variable i, y a continuación de este otro predicado que indica 10 quees verdadero cuando la variable toma valores en ese dominio.

De forma general, el predicado siguiente puede construirse con los predica­dos R(i) y P(i):

V R(i) : P(i)

Donde R(i) se utiliza para describir el dominio de i, y el predicado P(i) debesatisfacer para todos los valores de i pertenecientes a su dominio, para que elpredicado VP(i) : R(i) resultante sea válido -es decir, valga verdadero en todoslos casos-o Este tipo de predicados puede utilizarse para sintetizar conjuncio­nes como P(i 1) 1\ P(i 2 ) 1\ ... , donde i l , i 2 ••. , simbolizan todos los valores de i quesatisfacen R.

Ejemplo 3.24. Cada una de las frases de abajo va seguida de su represen­tación como predicado, que utiliza el cuantificador universal:

a) Cada elemento e¡ de la lista desde el hasta e21 es distinto de 9.

Vi E{l, 2, oo., 21}: e¡ =1= 9

b) Todos los ej entre em y en son números positivos.

Vj E {m, m + 1, ..., n}: ej > O

c) El punto (a, b) está arriba y a la derecha de cada punto (i, j) de algunaregión rectangular R del plano xy (véase Figura 3.3).

V (j, j) E R: i < a 1\ j < b

Page 81: ComputacionI A

Lógica 73

y

'(a, bl

R

--r----------- x

Figura 3.3. Representación gráfica delpredicado V (j, j) E R: i < a /\ j < b.

d) En una lista A = (el' e2, 000' en) los elementos hasta elj-ésimo, excluidoél mismo, están colocados en orden creciente (véase Figura 3.4)0

Vi E {l, 2, ..o,j - 2}: e¡ ~ e¡+l

(1 3 5 6 7

Ie,

9 2 8 4)

Iej

Figura 3.4. Ejemplo de predicado.

e) La proposición P(p, q, r ) es una tautología.

Vp, q, r E {verdadero, falso}: P(p, q, r)

Obsérvese que no se realiza ninguna exigencia de. que las proposicionessean siempre verdaderas. El apartado e requiere algún comentario adicional:P(p, q, r) es una proposición; sin embargo, la frase «la proposición P(p, q, r) esuna tautología» puede reescribirse «para todos y cada uno de los estados delas variables p, q y r, P(p, q, r) es verdadera. Por tanto, con el cuantificadoruniversal, el aserto P(p, q, r) del apartado e vale verdadero en todos sus ochoposibles estados.

Hay veces en que el cuantificador del predicado puede omitirse, si estáclaro por el contexto -es decir, cuando el conjunto universal ha sido expresa­do con claridad-o Por ejemplo, si sabemos que i es un entero (como sueleocurrir frecuentemente), es posible escribir:

Vi:i<i+l

Page 82: ComputacionI A

74 Computación l. Lógica, resolución de problemas, algoritmos y programas

De forma similar, siempre es posible escribir

V R(i) : P(i)

como Vi : R(i) ~ P(i). Por ejemplo

(Vi E {l, ..., 2l}: e¡ "1= 9)

es lo mismo que (Vi: 1 ~ i ~ 21 ~ e¡ "1= 9).

El otro cuantificador de interés es el cuantificador existencial, simbolizadopor 3. Su significado es «existe», o bien «existe al menos» o «para algúo». Seutiliza para abreviar múltiples ocurrencias de disyunciones cuando varios pre­dicados similares están relacionados con este operador.

Ejemplo 3.25. Las frases siguientes se acompañan con su representaciónabreviada utilizando el cuantificador existencial:

a) Existe un elemento de la lista (el' e2 , ••• , en) que es cero.

3iE {l, ...,n - l}:e¡ = O

b) Los elementos de (el' e2 , •.•, en) no están todos en orden ascendente.

3j E {l, ..., n - l}: ej + 1 > ej

e) Algún punto del conjunto del plano R, se encuentra en el tercer cua­drante.

3 (i, j) E R : i < O/\ j < O

d) Existen enteros a b y e, distintos de cero, que verifican a3 + b3 c3•

e) Existe alguna fila del tablero que no tiene ninguna pieza.

3 una fila R en el tablero: R no tiene piezas

f) Existe una frase en este texto con al menos una falta de ortografía.

3 una frase S en este texto: S tiene al menos una falta de ortografía.

El cuantificador universal, al igual que el existencial, representa una notaciónabreviada. Por ejemplo, 3 i E {l, ..., n}: e¡ = Oes la notación abreviada de (el == O) v (e 2 = O) v ... v (en = O). Es decir, al igual que el cuantificador universalrepresenta una forma abreviada de una secuencia de operaciones and, el cuan­tificador existencial representa una forma abreviada de secuencias de oro

Page 83: ComputacionI A

Lógica 75

La relación entre ambos cuantificadores podemos encontrarla en la genera­lización de las leyes de Morgan siguiente:

- V R{i) : P(i) = 3 R{i): - P(i)

- 3 R(i) : P(i) = V R(i): - P(i)

(3.1)

(3.2)

La Ecuación (3.1) dice que la frase «no es cierto que todos los íes en el dominiosatisfacen p» es equivalente a «para algún i del dominio, P es falso». La Ecua­ción (3.2) tiene una interpretación similar: la frase «no es cierto que algún i enel dominio satisfate P» es equivalente a la frase «para cada i en el dominio, Pes falso».Estas son generalizaciones de la versión simple de las leyes de Morgan, quefueron introducidas anteriormente en este capítulo. Téngase en cuenta que loscuantificadores utilizados ahora representan abreviaturas de conjunciones ydisyunciones. Por ejemplo, las equivalencias siguientes son interpretacio­nes válidas de las Ecuaciones (3.1) y (3.2), cuando el rango de i es el conjun­to {1, 2}:

-(P(l) /\ P(2)) - -P(I) v -P(2)

-(P(I) v P(2)) -P(I) /\ -P(2)

Ejemplo 3.26. A continuación, se muestran dos ejemplos concretos:

a) - 3i E {1, oo., n}: e¡ = O es equivalente a

Vi E {l, .oo, n}: e¡ :f. O.

b) - 3i E {1, oo., 21}: e¡ :f. 9 es equivalente a

Vi E {1, oo., 21}: e¡ = 9.

(3.3)

(3.4)

A menudo son necesarios ambos cuantificadores para expresar un únicopredicado. Por ejemplo, supongamos que queremos expresar que, simbólica­mente, B = {e'}, eí, OO" e~o} es una permutación de A = {el' e2 , •.. , e30 }.Supongamos también que todos los a¡ son distintos. Es posible expresar todolo anterior como:

perm (B, A) = Vi E {l, oo., 30} 3j E {1, oo., 30}: ei = ej'

Dicho en castellano, B es una permutación de A, si para cada elemento ei de Bexiste un elemento idéntico ej en A, aunque no necesariamente en la mismaposición (es decir, los índices i y j no necesitan ser idénticos para que e; = ejsea verdadero).

Page 84: ComputacionI A

76 Computación l. Lógica, resolución de problemas, algoritmos y programas

3.3.2. Otros cuantificadores

En informática suelen utilizarse otros cuantificadores junto con los dos ante­riores, 3 y V. Estos cuantificadores pueden verse a continuación:

Num R(i): P(i)Mio R(i): P(i)Max R(i): P(i)Sum R(i): f(i)Prod R(i): f(i)

Num R(i): P(i) da el número de valores de i en el rango determinado por R, quesatisfacen el predicado P. Mio devuelve el valor mínimo de la función f(i),donde i está restringida al rango especificado por R. Max es similar a Mio,pero devuelve el valor máximo. También se ha visto la función Sum, que seutilizó en la Sección 2.4 (donde se simbolizó mediante la letra griega L). Prodes similar a Sum, pero simboliza el producto en lugar de la suma. (En matemá­ticas suele simbolizarse el producto mediante la letra griega n.)

Ejemplo 3.27. Las expresiones siguientes muestran la utilización de estoscuantificadores. El valor que resulta de evaluarlas aparece a la derecha:

a) Num i E {O, oo., 3}: i2 > i 2b) Mio i E {O, ..., 3}: i2 > i 2e) Max i E {O, oo., 3}: i2 > i 3d) Sum i E {O, ..., 3}: i2 - i °+ °+ 2 + 6 = 8e) Prod i E {l, .oo, 4}: i2 > i 1 x 4 x 9 x 16 = 576

3.3.3. Variables libres y ligadas

Compárese

con la expresión cuantificada

Vi E {l, oo., 29}: ei+l ~ e;

En la primera expresión, i está irrestringida; puede tomar cualquier valor en eldominio que deseamos definir. En este caso, i recibe el nombre de variablelibre. Sin embargo, en el segundo caso, la variable i está restringida por elcuantificador universal a tomar valores en un intervalo específico. En este caso,se dice que i es una variable ligada.

En general, todas las variables cuyos valores están restringidos a un deter­minado dominio, por la aplicación de un cuantificador, son ligadas; variables

Page 85: ComputacionI A

Lógica 77

que no están ligadas son libres. (Veremos que la misma distinción entre varia­bles libres y ligadas existe entre variables globales y locales, respectivamente,cuando definamos procedimientos y funciones en programación.)

Considérese la expresión

Vi E {m, ..., n}: e¡ :::;; K

En esta expresión, i es una variable ligada, mientras que m, n y K son libres.Suele ser habitual la coexistencia de variables libres y ligadas.

3.4. PREDICADOS V PROGRAMAS

En el Capítulo 5, se utilizarán con frecuencia predicados para discutir sobreprogramas y resolución de problemas. La idea de predicado, que define exacta­mente las condiciones bajo las que debe ejecutarse un programa, es fundamen­tal para los objetivos descritos en la frase anterior. Es también fundamental lacorrespondencia entre predicados cuantificados y bucles de un programa. Enla sección siguiente se introducen ambas ideas.

3.4.1. El estado de un cálculo

Supóngase que en un programa de una computadora se tiene una instruccióncomo la siguiente:

; := O

que asigna el valor O a la variable ;. Supóngase también que el programa estan simple que sólo utiliza las variables; y j. Es posible utilizar un predicadopara describir el estado del programa después de la ejecución de la instrucción

; := O

Tal predicado recibe el nombre de poscondición de la instrucción ; : = O.Supóngase que conocemos que, antes de la ejecución de esta instrucción, lasvariables cumplen i > j 1\ j > 10. El predicado anterior recibe el nombre deprecondición, debido a que describe el conjunto de todos los estados que pue­den darse antes de ejecutar la instrucción.

Definición. Una poscondición de una instrucción o grupo de instruccionesde un programa, es un predicado que describe el conjunto de todos losestados en que estas instrucciones pueden terminar, después de que seanejecutadas. Una precondición para esa instrucción o grupo de instrucciones,es un predicado que describe el conjunto de estados en los que pueden estartodas las variables del programa, inmediatamente antes de ejecutarse lainstrucción o grupo de instrucciones.

Pedro Pacheco
Highlight
Page 86: ComputacionI A

78 Computación ,. Lógica, resolución de problemas, algoritmos y programas

Podemos pensar en la poscondición como un predicado que describe elconjunto objetivo o el propósito de nuestro programa. Obsérvese que, si seconsidera una instrucción o conjunto de instrucciones como una función, laprecondición representa su dominio, y la poscondición su recorrido. Más ade­lante, se verá cómo la precondición y la poscondición sirven de ayuda en laconstrucción y verificación de programas.

3.4.2. Cuantificadores y programación: bucles

Existe una estrecha correspondencia entre la utilización de cuantificadores enlógica y la de bucles en programación. Es decir, al igual que los cuantificadoresuniversal y de existencia permiten en la lógica abreviar una serie de tediosassecuencias de operaciones /\ y v, los bucles sirven en programación paraabreviar largas secuencias de instrucciones. Tendremos muchas ocasiones dehacer traducciones entre esas dos formas de expresarse.

Es habitual tener que escribir instrucciones de programas que compruebensi los predicados cuantificados VR(i): P(i) y 3R(i): P(i) son válidos. Cuando elrango de la variable i, expresada en R(i) es finito, esta prueba puede realizarseutilizando un bucle for de Pascal. Supongamos que tenemos la lista A =(el'e2 , ... , e30) Yqueremos conocer si todos los miembros de esta lista son positivos;es decir, se quiere establecer si el predicado siguiente es válido:

V i E {l, ..., 30}: ei > O

Una forma posible de comprobar esto sería escribir una larguísima instruccióncondicional, asignando a la variable booleana vá l ; do el valor verdadero ofalso:

if (e[1]>O and (e[2]>0> and ..• and (e[30]>O>then válido:=trueeLse válido:=false;

De forma alternativa, tras aplicar la ley de Morgan, podríamos escribir:

válido:=true;if e[1] <= Othen válido:=false;

if e[2] <= Othen válido:=false;

if e[30] <= Othen válido:=false;

Es decir, el predicado original no es válido, SI es posible que uno o máselementos de la lista cumplan ei ~ O.

Pedro Pacheco
Highlight
Page 87: ComputacionI A

Lógica 79

Para evitar problemas de escritura, en esta y en similares situaciones, esposible utilizar la instrucción for para expresar la misma idea. Es posiblesustituir la serie de instrucciones «if-then» por el bucle siguiente:

válido:=true;for i :=1 to 30 do

jf e[i] <= Othen vá l i do :=fa lse;

Sencillamente, se ha utilizado un truco bastante común en programación: se hasupuesto que el predicado es válido para todos los valores del rango de i, y seintenta demostrar lo contrario examinando los 30 casos de forma individual.

Puede seguirse una estrategia de programación similar, cuando se imple­menten predicados como instrucciones, que involucren otros cuantificadores.Ejemplos de esto pueden verse en los Ejemplos 3.28 y 3.29:

Ejemplo 3.28. El predicado «Existe un número en la lista A = (e l' e2' ... ,

e30) cuyo valor es cero», puede reescribirse como :Ji E {l, ..., 30}: e¡ = O. Unbucle para probar la validez del predicado sería:

vál ido:=false;for i :=1 to 30 do

ife[i]=Othen válido:=true;

Ejemplo 3.29. La frase «El número de elementos de la lista A = (el' ez' ...,e30) cuyo valor es cero», puede reescribirse como Num i E {l, ..., 30}: e¡ = O.El programa siguiente comienza con la suposición de que no existen en Aelementos que cumplan esta condición. Posteriormente, se corrige metódi­camente la suposición (añadiendo 1 a la variable contador numero), cadavez que se encuentre un cero en la lista.

número:=Ofor i :=1 to 30 do

ife[i]=Othen número:=número+1;

Una discusión más detallada sobre el bucle for, puede encontrarse en elmanual de laboratorio.

Ejercicios

3.18. Evaluar los predicados siguientes, en cada uno de los estados 1 y 11:

(1) i = O1\ j = 1 1\ k = - 1 (JI) i = - 1 1\ j = 1 1\ k = O

Page 88: ComputacionI A

80 Computación l. Lógica, resolución de problemas, algoritmos y programas

a) i< lO/\j< 10b) -1 < j :::; ie) i + j > kd) i 3 = / = p

3.19. Evaluar cada uno de los predicados siguientes. Supóngase, en todos loscasos, que el dominio es N.

a) Vi: i < i + 1b) Vi: i2 < ie) Vi, j : i2 + / > Od) 3i: i2 = 5i - 6e) 3i, j : i2 + j2 :::; 25f) Vi 3j : j = Og) Max i E {l, ..., lOO} : i

h) Vi 3j : i - j = Oi) 3i Vj : i - j = Oj) Mio i E {1, ..., 6} : (i2 - 6i) = 3k) Vi 3j : i x j = Ol) Sum i E {l, , lO} : i - 5

m) Prod i E {l, , n} : i+ 2 = 101

3.20. Supóngase que se define un tablero de ajedrez como {(i, j)ll :::; i :::;:::; 8 /\ 1 :::; j :::; 8}. Supongamos que el par (1, 1) define el cuadrado dela esquina inferior izquierda del tablero, la casilla es negra, y las blancasocupan inicialmente las dos filas inferiores del tablero. Sea p una fun­ción que asigna a cada casilla del tablero el nombre de la pieza que estásobre ella. Así, si la casilla (4, 7) está vacía, escribiremos p(4, 7) = vacía;si la casilla (1, 5) contiene el rey blanco, escribiremos p(l, 5) = RB.Escribir predicados para describir las frases siguientes:

a) La reina blanca ha sido capturada.b) Las negras conservan sus alfiles.e) Una torre blanca está en la misma fila que la reina negra.d) Un peón blanco está atacando al rey blanco.e) Una torre blanca está atacando a la reina negra.f) Un alfil negro está atacando al rey negro.

3.21. Identificar las variables libres y ligadas de las expresiones siguientes:

a) Vi E {O, oo., n} : i3- i2 < 100

b) 3i E N : "In E {1, .oo, i} : n2 = ie) (O:::; m :::; p) /\ (Vw E R : w < m /\ w2 < p)

3.22. Considérese la situación del juego de las tres-en-raya descrita en eldibujo. Supóngase que la notación s(i, j) = v significa que la cuadrículade la fila i y la columna j contienen el valor v (donde v puede ser una X,una O o estar vacía).

a) Escribir un predicado que describa la situación concreta del dibujo.b) Escribir un predicado que describa el mejor movimiento que pue­

dan realizar las O, a continuación.

Page 89: ComputacionI A

Lógica 81

columnafila 1 2 3

2

3

x O

Xe) Escribir un predicado que describa todos los estados en que las X

pueden ganar, en la columna de enmedio; es decir, todos los estados enque las X ocupan dos casillas de la segunda columna y la otra casillaestá vacía.

d) Escribir un predicado cuantificado, que describa la imposibilidad deque las X ganen en la segunda columna.

e) Escribir otro que describa la imposibilidad de las X de ganar en cadacolumna.

f) Escribir un predicado que describa la imposibilidad de que ganen las X.

3.23. Describir las situaciones siguientes, utilizando predicados y cuantificado­res. Supóngase que A = (el' e2, ..., e,,) es una lista de caracteres ASCII.

a) Todos los caracteres de la lista son idénticos.b) La letra x no está en la lista.e) Algún carácter de la lista es la z.d) La lista está ordenada alfabéticamente, de menor a mayor.e) No existen en la lista dos caracteres iguales.f) Algún par de caracteres de la lista son iguales.g) La letra y aparece exactamente dos veces en la lista.h) La lista B = (b l , b2 , •.., b,,) es una sublista de A.i) La variable cont almacena el número de puntos y comas de la lista.j) La lista B es idéntica a la A.k) La lista B es idéntica a la A, excepto que algún cero de la lista ha sido

reemplazado por una letra o.l) El número 3621 no es primo.

3.5. RAZONAMIENTO CON PREDICADOS:PRUEBA POR INDUCCION

El razonamiento con predicados es similar al razonamiento con proposiciones,puesto que existen también reglas de inferencia que gobiernan los pasos a seguir.Frecuentemente, se asignan valores representativos a las variables de un predica­do (convirtiéndolo en una proposición) y se utilizan las reglas de inferencia para

Page 90: ComputacionI A

82 Computación ,. Lógica, resolución de problemas, algoritmos y programas

proposiciones. Sin embargo, el razonamiento con predicados implica algunasreglas adicionales que se resumen en la Tabla 3.4.Como sugiere la Tabla 3.4, las reglas de la 3-introducción y de a 3-elimina­ción recuerdan a las leyes de Morgan (véanse Ecuaciones (3.1) y (3.2)). Las reglasde la V-introducción y de la V-eliminación también son ampliamente utilizadasen las demostraciones. La primera indica que si es posible establecer que R => Pes válida, es posible afirmar, en un paso posterior de la demostración, quetambién es' válido V R(i): P(i). La segunda indica que si V R(i): P(i) es válida,entonces para cada valor particular io de i, también es válida R(io) => P(io)'

Tabla 3.4. Reglas de inferencia para predicados cuantificados

V-introducción

R-=P

V R(i): P(i)

3-introducción

V R(i): P(i)

~3 R(i): ~P(i)

V-eliminación

V R(i): P(i)

R(io) -= P(io)

3-eliminación

3 R(O: P(i)~ V R(i): ~P(i)

Supongamos que se quiere demostrar que todos los enteros pares mayoresque 2 no son primos. En este caso, R es el predicado:

i no un entero /\ (i > 2) /\ i es par

y P es el predicado:

i no es primo

Es necesario ver que R => P es válido. Esto se suele hacer seleccionando un iorepresentativo, que satisfaga R, y demostrando que también satisface P. Así, laprueba podría comenzarse:

Sea io cualquier entero par que verifique io > 2.

De la suposición anterior concluimos que i no es primo (puesto que para que unnúmero sea par, es necesario que sea divisible por 2). Por tanto, concluimos quetodos los enteros pares mayores que 2 no son primos.

Prueba por inducción. La validez de predicados que contienen cuantificadores,puede muchas veces establecerse mediante el método conocido por prueba porinducción (o inducción). Este es un concepto tan importante para la programa­ción como para las matemáticas. Es decir, los métodos de demostración inducti­vos se utilizan en la verificación formal de programas (véase Capítulo 6). La

Page 91: ComputacionI A

Lógica 83

inducción tiene también una relación muy estrecha con el concepto matemáticode funciones recursivas (como se vio en el Capítulo 2) y una gran aplicación en laresolución de problemas y en programación (véase Capítulo 5).

Para demostrar la validez del predicado VR(n): P(n) en el caso especial en queR(n) tiene la forma n E {l, 2, "'}' podemos considerar dos casos por separado.

Oaso base: Demostración de P(l).Paso de inducción: Demostración de P(i) ::::- P(i + 1) para todo i ~ 1.

El caso base, simplemente establece la validez de P para el valor inicial, i = 1. Elpaso de inducción establece que, si podemos demostrar que P(i) ::::- P(i + 1), paracualquier i, entonces se demuestra la validez de P(l) ::::- P(2) ::::- oo•• Puesto queP(l) es válido, también lo será P(2) [puesto que P(l) ::::- P(2)] y también lo seráP(3) [puesto que P(2) ::::- P(3)], y así sucesivamente. .

La idea de la inducción puede ilustrarse mediante una analogía. Suponga­mos que alguien quiere subir una escalinata. Sólo serán necesarias dos fases paradescribir el proceso -la fase de alcanzar el primer peldaño y la de subir desdeun peldaño hasta el siguiente-. Utilizando estas dos instrucciones es posiblesubir cualquier escalinata, sin tener en cuenta cómo tenemos que situarnos en unescalón determinado. Además, estas dos acciones hacen irrelevante, para com­pletar el proceso de inducción, lo larga que sea la escalera. El hecho de alcanzarel primer escalón es equivalente a probar el caso base P(1). El hecho de saltar deli-ésimo escalón al i + 1, es análogo a probar el paso de inducción P(i) ~ P(i ++ 1) para cada i ~ 1. La expresión Vn E {l, 2, oo.}: P(n) establece que P(n) esverdadero para todo n, y es análogo a la posibiliad de saltar de uno a otroescalón de todas las escaleras.

Mientras no podamos utilizar una tabla de verdad para justificar el procesode inducción, podemos justificarlo utilizando el modus ponens y basándonos enalgunas propiedades de los números naturales. Es decir, si sabemos que P(l) esverdadero y que Vi E {l, 2, oo.}: P(i) ::::- P(i + 1) es posible escribir las expresionessiguientes, sin más que sustituir i por diferentes números enteros:

P(l)P(l) ~ P(2)P(2) ::::- P(3)

Combinando las dos primeras líneas es posible concluir, utilizando modus po­nens, que P(2) es válido. Combinando la veracidad de P(2) con la tercera línea, esde nuevo posible concluir que P(3) es verdadero. Es posible continuar de estaforma indefinidamente hasta demostrar que Vi E {l, 2, oo.}: P(n) es válido.

Ejemplo 3.30. Supongamos que St; desea probar por inducción que Vn > o:n n(n + 1)

j~l j = 2 . Consideremos los dos casos:

Page 92: ComputacionI A

84 Computación l. Lógica, resolución de problemas, algoritmos y programas

n

Caso base. Demostrar que L jj= 1

Paso de inducción: Demostrar que

n(n + 1)

2

" i( i + 1) i~1 .¿j= ~ ¿Jj=l 2 j=l

(i + 1)((i + 1) + 1)

2

El caso base es evidente si utilizamos la aritmética. Es decir, 1 = 2/2. El pasode inducción tampoco es muy dificil de probar, si se utilizan las propiedadesde las sumatorias finitas, introducidas en la Sección 2.2.6.

i+ 1 i

¿j L j + (i + 1) Propiedad de Lj= 1 j=l

i(i + 1) i i(i + 1)+ (i + 1) Suponiendo L j =

2 2j= 1

i(i + 1) 2(i + 1)

2 + 2 Aritmética

(i + 1)((i + 1) + 1)Aritmética

2

A primera vista, puede parecer que la inducción matemática es una forma circu­lar de razonamiento. Sin embargo, lo que está realizándose es, en alguna medida,un «razonamiento hipotético». Lo que decimos es «Supongamos que P(n) escierto. ¿Podemos deducir de ello que P(n + 1) también lo es?». Esto no demues­tra la validez de P(n + 1), sino sólo que P(n) implica P(n + 1). Considérese denuevo la analogía con la ascensión de la escalinata. En realidad, lo que estamosdiciendo es «Supongamos que nos encontramos en el n-ésimo escalón, ¿puedodesde aquí ir al siguiente?». Esto no supone afirmar que sepamos llegar aln-ésimo escalón, sino que estando en él somos capaces de alcanzar el n + l-ésimo.Es la combinación de las capacidades de saltar de uno al siguiente, y la dealcanzar el primer escalón (es decir, probar P(I)), lo que permite alcanzar el n­ésimo.

Ejemplo 3.31. Demostrar que si O < 1 r < 1, entonces

n 1 - r n + 1¿ r i = ---i=O 1 - r

Comencemos con n = O. Los lados izquierdo y derecho (LHS y RHS) de laecuación anterior se convierten en:

Page 93: ComputacionI A

LHSi=O

rO = 1, para r =1= O

Lógica 85

1 rRHS = = 1, para r =1= 1

1 - r

E&to completaría la demostración del caso base. Supongamos ahora que

n 1 - r n + 1

I r i = ----i=O 1 - r

Demostraremos que esto implica

n+1 1 _ rn + 2

I ri =

i=O 1 - r

Sumando r n + 1 a ambos lados de la ecuación (3.5), obtenemos

(3.5)

RHS

n+1

LHS = I r i + rn + 1 =i=O

1 - r n + 1+ r n + 1

1 - r

1 - r n + 2

1 - r

n+1

I r i

i=O

Ejemplo 3.32. Supongamos que S es un conjunto finito que tiene n ele­mentos. Demostrar mediante inducción que S tiene 2n subconjuntos.

Solución. Denotemos por P(S) la colección de subconjuntos de S. Supon­gamos que n = O. Entonces, S = <j>. Por tanto, P(S) = {<j>} y S tiene 1 (= 2°)subconjuntos. Este es el caso base para la prueba inductiva.

Supongamos ahora que cualquier conjunto S de n elementos tiene 2n

subconjuntos. Para probar el paso de inducción, sea T un conjunto arbitra­rio con n + 1 elementos.

Los subconjuntos de T pueden dividirse en dos grupos ~aquellos que in­cluyen a tn + 1 Ylos que no-o Cada subconjunto {t 1 , t2 , ••• , tn } es también unsubconjunto de T. Por tanto, por hipótesis de la inducción 2n subconjuntosde T no incluyen a tn + l' Cada subconjunto que incluye tn + 1 puede conside­rarse como la unión de un subconjunto de {t l' t2' ... , tn } con {tn + 1}' Luegoexisten 2n subconjuntos que incluyen tn + l' Por tanto, existen 2n + 2n = 2 xx 2n = 2n + 1 subconjuntos.

Page 94: ComputacionI A

86 Computación ,. Lógica, resolución de problemas, algoritmos y programas

Una forma de visualizar la demostración es escribiendo la lista de subcon­juntos siguiente:

Sin incluir tn+ ¡

4J{td{t 2 }

{ti' .t2 }

{ti' t2 , oo., tn}

Incluyendo tn + ¡

{tn+d{ti' tn + ¡}{t2' tn + ¡}{t l' .t2 , tn + ¡}

{t¡,"t 2 , .•., tn, tn+ ¡}

La lista de la izquierda está construida con todos los subconjuntos de {tl' t 2 ,

..., tn). La lista de la derecha se ha construido haciendo la unión de cada unode los elementos de la lista de la derecha con {tn + ¡}. Luego hay exactamente2n elementos en cada lista.

Obsérvese que, en contradicción con su nombre, la demostración por induc­ción implica razonamiento deductivo, en lugar de inductivo. El razonamientoinductivo hace referencia a una técnica habitual en la ciencia, denominada méto­do científico; este método consiste en inferir principios generales a partir de casosparticulares. Por ejemplo, el astrónomo Kepler utilizó el razonamiento inductivopara inferir las leyes del movimiento planetario a partir de un voluminoso con­junto de datos experimentales que había recogido. Sin embargo, la inducciónmatemática sigue un típico proceso deductivo -partiendo de axiomas, teoremaspreviamente demostrados define nuevos teoremas utilizando reglas de inferencia.

3.6. RESUMEN

En este capítulo hemos estudiado los fundamentos de la lógica, prestando espe­cial atención a su utilización en la informática. La lógica proposicional, la equi­valencia y las demostraciones se han revelado como inestimables herramientasen la resolución de problemas. El cálculo de predicados tiene una utilizacióndirecta en Pascal, en forma de expresiones booleanas. Se han introducido méto­dos deductivos de demostración, incluida la inducción, útiles para el estudio deldiseño de programas y la verificación, que se verán en capítulos posteriores.

Ejercicios

3.24. Demostrar que la suma de los n primeros números impares es n2•

n > 1para

3.25. Supongamos que la función Factorial: N ~ N se define recursivamente dela forma siguiente:

Factorial (1)Factorial (n) = n x Factorial (n - 1)

Page 95: ComputacionI A

Lógica 87

Demostrar por inducción, sobre n, que esta definición es equivalente a ladefinición no recursiva:

Factorial (n) = 1 x 2 x ... x (n - 1) x n

3.26. Supongamos que la función f(n) se define mediante la siguiente regla:

f(O) = 1f(n + 1) = 2f(n) para todo n > O

Demostrar por inducción que f(n) = 2n•

3.27. Demostrar la generalización de la ley de Margan, siguiente:

n

(Nota: U A¡ significa A o u Al U ... U An)

;=0

n

(Nota: n A i significa A o n Al n ... n A n)i=O

3.28. Verificar las relaciones siguientes utilizando la inducción matemática:

n n(n + 1)(n + 2)a) L (i(i + 1»)

3i=O

n n(n + 1)(2n + 1)b) L ¡2

6i=O

n n2(n + 1?c) L ¡3

4i=O

Page 96: ComputacionI A

CAPíTULO 4PROBLEMAS ALGORíTMICOS

V SU SOLUCiÓN

El conjunto de problemas que son resolubles utilizando una computadora es,indudablemente, muy extenso. Muchos de estos problemas son de índole mate­mática, y requieren la utilización de números y la aplicación de principiosmatemáticos. Otros tienen naturaleza gráfica, e implican la manipulación deobjetos gráficos, tales como puntos, líneas, rectángulos y círculos. El otro grangrupo implica la manipulación de textos en lengua castellana y, por tanto,implica la manipulación de caracteres alfabéticos y palabras como unidades deinformación básicas.Muchos de los problemas que debemos resolver con computadoras, autén­ticamenteimportantes, fuerzan a la manipulación conjunta de dos o tres de losdominios anteriores -matemáticas, gráficos y texto--. Por ejemplo, si utiliza­mos una computadora para resolver un problema que simula el juego de lastres en raya, no querremos sólo visualizar la secuencia de movimientos (descri­bible como texto), sino que queremos ver en qué situación se encuentra eltablero en cada momento (descripción gráfica). Un estudio cuidadoso de pro­blemas algoritmicos debe incluir elementos de esos tres dominios, bien porseparado, bien en combinación con otro.Existe una ventaja adicional si se estudian los problemas computacionalesde las matemáticas, los gráficos y los textos de forma conjunta: muchos de losprincipios que se aprenden al estudiar una de estas áreas, por ejemplo lasmatemáticas, son también de aplicación en las demás. Esto sugiere la existenciade una serie subyacente y única de principios, que gobiernan el comportamien­to de computadoras y programas. De hecho, estos principios dirigen nuestraforma de abordar un problema cuando tratamos de resolverlo con una compu­tadora. Este conjunto de principios recibe el nombre de resolución de problemasalgorítmicos. En este capitulo se introducen las ideas1undamentales de la reso­lución de problemas algorítmicos, y se presentan una gran variedad de proble­mas matemáticos, gráficos y de procesamiento de textos, que ilustran estasideas.

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 97: ComputacionI A

90 Computación /. Lógica, resolución de problemas, algoritmos y programas

4.1. ALGORITMOS Y PROBLEMAS

Los conceptos de problemas algorítmicos, algoritmos, lenguajes algorítmicos y

comportamiento algorítmico son fundamentales para la actividad de resolver

problemas con computadoras y, por tanto, para la disciplina de la informática.

f En consecuencia, necesitamos adquirir un conocimiento firme sobre lo que es

un algoritmo (y sobre lo que no es), y lo que es un problema algorítmico, con

objeto de llevar a cabo de forma eficaz la actividad de resolver problemas. La

definición siguiente sirve como punto de partida para esta discusión.

Definición. Un algoritmo es una lista de instrucciones que realizan una

descripción paso a paso y precisa de un proceso que garantiza que resuelve

cualquier problema que pertenezca a un tipo determinado, y que termina

después de que se hayan llevado a cabo un número finito de pasos.

Los algoritmos se escriben o diseñan con el propósito de resolver problemas, o

más exactamente, problemas algorítmicos.

Definición. Un problema algorítmico es cualquier problema, conceptual o

práctico, cúya solución puede expresarse mediante un algoritmo.

En la vida cotidiana encontramos muchos problemas algoritmicos, tanto den­

tro como fuera del campo altamente especializado de la informática. Por ejem­

plo, una determinada receta para preparar pollo a la cazadora constituye un

algoritmo, mientras que el problema general de preparar pollo a la cazadora es

el problema algoiítmico asociado. En la Tabla 4.1 se presentan algunos ejem­

plos comunes de algoritmos y de problemas algorítmicos.

Tabla 4.1. Algunos algoritmos y problemas algorítmicos

Algoritmo Problema algorítmico

Conjunto de instrucciones para tejer un jersey

Un itinerario particular para recorrer el mundo

Un plan de trabajo para cursar una licenciatura

Tejer un jersey.Dar la vuelta al mundo.Cursar una licenciatura.

Para cada problema algorítmico como «cursar una licenciatura», existen

varios algoritmos alternativos que pueden utilizarse como solución. Por ejem­

plo, un alumno que desee cursar una ingeniería en informática, seguirá un

algoritmo muy diferente que en el que desee licenciarse en ciencias medioam­

bientales o en filosofía.En cualquier caso, los algoritmos de la Tabla 4.1 exhiben las principalcs

características señaladas en la definición: exactitud, efectividad y terminación

garantizada. Cuando se ejecutan determinados algoritmos pueden completarse

en un pequeño intervalo de tiempo, mientras que otroS' pueden llevar mucho

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 98: ComputacionI A

Problemas algorítmicos y su solución 91

tiempo. Sin embargo, la ejecución de todos los algoritmos debe terminar. Porello, cualquier descripción paso a paso de un proceso que no termine, no es unalgoritmo. Por ejemplo, el proceso de escribir todos los números enteros posi­tivos, uno a uno, no es un algoritmo, puesto que no terminaría nunca.

En la informática se asocia la noción de algoritmo con la de un procesoque debe ser ejecutado por una computadora, en lugar de por una persona. Enprincjpio, cualquier algoritmo que diseñemos para una computadora puede serrealizado a mano (suponiendo que disponemos del tiempo necesario, una piza­rra o suficiente papel). En realidad, encargamos a la computadora la ejecuciónde los pasos que componen un algoritmo, porque es capaz de completarlo enun tiempo mucho menor del que nosotros emplearíamos, y porque es menosproclive a cometer errores que nosotros.

Sin embargo, no todos los algoritmos pueden ser ejecutados por computa­doras. Las computadoras sólo pueden ejecutar algoritmos que se componen deacciones individuales que pueden entender y realizar. Por ejemplo, la prepara­ción de pollo a la cazadora implica acciones como «encender el horno» o«deshuesar el pollo», tareas para las que una computadora está bastante malpreparada. Por tanto, es necesario conocer bien cuáles son las tareas que puederealizar una computadora, de forma que diseñemos algoritmos que contengansólo ese tipo de tareas.

Como punto de partida, considérese el sencillo modelo computacional de laFigura 4.1.

ENTRADA I----~.I PROCESO ----~.I SALIDA

Figura 4.1. El modelo de computación entrada-procesa-salida.

En este modelo, un proceso de cálculo se compone de tres partes: una entrada,un proceso y una salida. La entrada la constituyen un conjunto de informacio­nes que necesitan los pasos de que se compone el algoritmo para llevar a cabola tarea; el proceso contiene (una descripción de) los pasos del algoritmo; final­mente, la salida la constituye el resultado que se obtiene ejecutando los pasos,con los datos de entrada.

Por ejemplo, el procedimiento para calcular la calificación media (CM) esun algoritmo. En este caso, la entrada puede ser cualquier lista de valoresnuméricos dentro del rango Oa 4. (O = suspenso, 1 = aprobado, 2 = notable,3 = sobresaliente, y 4 = matrícula de honor); la salida será la media de esosvalores (es decir, el cociente entre la suma de todos y el número de valores); yelproceso es (una descripción de) el conjunto de pasos individuales que debenseguirse para obtener el resultado. Ese conjunto de pasos puede resumirse enun lenguaje-castellano descriptor de procesos, en la forma siguiente:

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 99: ComputacionI A

92 Computación l. Lógica, resolución de problemas, algoritmos y programas

Paso 1. Obtener la lista de calificaciones.Paso 2. Calcular n = número de notas de la lista.Paso 3. Calcular Sum = la suma de las calificaciones de la lista.Paso 4. Calcular CM = Sum¡n.Paso 5. Mostrar CM.

Cuando se escriben este tipo de descripciones de procesos, se realizan algu­nas' suposiciones tácitas sobre el comportamiento del modelo entrada-proceso­salida de la Figura 4.1. La primera hipótesis es que el número de calificacioneses indeterminado, aunque nunca infinito. La segunda hipótesis es que parapoder calcular cualquier cosa sobre las calificaciones, el algoritmo necesitaobtenerlas primero ---es decir, trasladarlas fisicamente a la parte proceso delmodelo, desde la parte entrada del mismo.

Cuando se utiliza una computadora en la resolución de este problemaalgorítmico, las instrucciones que contienen los pasos individuales, junto conlos valores numéricos de Sum, n y CM se almacenan fisicamente en un lugarllamado memoria, que se encuentra unido a la unidad central de procesamiento(CPU o procesador) de la computadora. Toda la información de entrada osalida, se encuentra físicamente separada del procesador en dispositivos comoel teclado, el monitor o un archivo en disquete. Un diagrama de las unidadesde una computadora que se corresponde con el modelo entrada-proceso-salidapuede verse en la Figura 4.2.

[ IProcesador/

Teclado/Ratón ---- '--_M_em_o_ri_a_--..JI--- Pantalla de monitor

Figura 4.2. Computadora correspondiente al modelo.

La tercera suposición que realizaremos es que los pasos de la descripcióndel proceso se realizarán en el orden en que están escritos. Por ejemplo, difícil­mente podríamos realizar el Paso 5 sin haber realizado antes los pasos 1 al 4,además de ser improbable que hubiéramos podido calcular la CM.

Nuestra cuarta suposición es que cada uno de los pasos es eficaz ---es decir,que contiene sólo acciones del repertorio de las realizables por la computado­ra-. Por ejemplo, hemos asumido que la orden «Mostrar» (Paso 5) está en elrepertorio de instrucciones de la computadora. Por tanto, siempre que se eje­cute alguna instrucción que contenga la palabra «Mostrar», la información desalida aparecerá en el monitor, independientemente de cuál sea el paso que lacontiene. (En este caso, mostrar aparece muy tarde. No existe ninguna restric­ción del número de veces que mostrar puede estar en un proceso.)

Las cuatro suposiciones son ciertas, de hecho, para todos los algoritmosque construimos para las computadoras. Las computadoras ejecutan las ins­trucciones de una forma obediente, comenzando por la primera y ejecutandosólo aquellas que le son inteligibles; es decir, instrucciones que describen tareasdentro de su propio repertorio.

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 100: ComputacionI A

Problemas algorítmicos y su solución 93

Ejercicio

4.1. Describir un problema algorítmico que nos encontremos en la vida dia­ria, similar a los discutidos en la Sección 4.1. Dar dos algoritmos alterna­tivos para solucionar el problema.

,4.2. DEFINICiÓN DE PROBLEMAS Y DESCRIPCiÓN

DE ALGORITMOS

En la resolución de problemas algorítmicos, el nivel de precisión -tanto en ladescripción del propio problema como en la solución algorítmica al mismo­debe ser detallada y rigurosa. Por ejemplo, nuestra descripción del algoritmode CM, de la Sección 4.1, puede no ser lo suficientemente rigurosa para incor­porarlo a una computadora. Es necesario un mayor nivel de detalle por dosrazones fundamentales:

• El problema, sus limitaciones y su solución deben describirse de formaclara para el lector humano.

• La solución debe resolver completamente el problema -es decir, debeaportar a la computadora toda la información necesaria para que pro­duzca una salida correcta para todas las posibles variaciones de la en­trada.

En el problema CM, la impresión en el proceso de descripción deja sin respon­der la pregunta de cuántas puntuaciones constituirán la entrada. ¿Existe unnúmero máximo de puntuaciones? ¿Es posible suponer que siempre habrá unnúmero de puntuaciones distinto de cero? Si no está permitida una entradaconsistente en cero puntuaciones, esto debería expresarse explícitamente. Sinembargo, si se permite una entrada de cero puntuaciones, es necesario modifi­car la descripción del proceso, de forma que evitemos la división por cero(Paso 4), y que sea posible escribir el mensaje adecuado.

Esta breve discusión enfatiza sobre la necesidad de encontrar una maneramás sintética y formal de describir un problema algorítmico y sus soluciones.En el resto de esta sección se introducen los rudimentos de un lenguaje dedescripción de algoritmos. En la Sección 4.3 se introducirán los rudimentos deun lenguaje de descripción de soluciones a problemas, y se demostrará que estosdos tipos de lenguajes están relacionados mutuamente.

4.2.1. Los estados inicial y final de un algoritmo:entrada y salida

Para formalizar el modelo de cálculo entrada-procesa-salida, introduciremosprimero la noción de estado de un algoritmo. Intuitivamente, podemos enten­der la idea de «estado» de un algoritmo como una especie de instantánea quedescribe cómo están las cosas inmediatamente después (o antes) de que se haya

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 101: ComputacionI A

94 Computación l. Lógica, resolución de problemas, algoritmos y programas

ejecutado un paso de un algoritmo. Por ejemplo, el estado del proceso descritoen la Sección 4.1 podria ser una instantánea de sus entradas, sus salidas y cadauna de sus variables Sum, n y CM en el instante particular en que cada uno delos pasos, del 1 al 5, ha sido ejecutado.

Existen dos pasos de interés especial: el estado inicial y el fina!. El estadoinicial lo constituye una descripción de la entrada, antes de que se ejecute elprimer paso del algoritmo y, por tanto, recibe el nombre de precondieión delalgoritmo (o pre). El estado final es una descripción de las entradas y las salidasdespués de que se haya ejecutado el algoritmo, y reciben el nombre de poseon­dición del algoritmo (o post). Ambas suelen escribirse utilizando la notaciónconvencional de la lógica, introducida en el Capitulo 3:

{pre: ent rada = una expresión que describe todas las posibles entradasdel problema}

{post ent rada =0/\ sa l i da = una descripción de todas las salidas quepueden darse para cada entrada}

Si denotamos por Notas! la primera calificación de la lista, por Notasz lasegunda, y así sucesivamente, la descripción siguiente es una descripción preci­sa del problema de la calificación media, en forma de precondición y poscondi­ción:

{pre: entrada = (Notas" Notas" .. "' Notas,> /\ n> O /\\ti E {1, .•. , n} :Notas, E (O, ... , 4)){pos t: ent rada = 0 /\salida = Sum i E {1, ... , n}:Notas,ln}

Obsérvese cómo se utiliza en la precondición y la poscondición el lenguaje dela lógica de predicados, estudiado en el Capítulo 3. Cuando utilizamos lalógica de predicados de esta forma, se dice que realizamos asertos acerca de losestados inicial y final del proceso.

El lenguaje de la lógica permite, en la expresión del estado de un cálculo,una concisión y precisión que no podemos alcanzar con el lenguaje castellano.En el ejemplo, el estilo de descripción no deja duda sobre la exclusión del casode que existan cero entradas en el problema de la CM. Por tanto, la soluciónalgorítmica a este problema no tiene que ocuparse de este caso.

El haber escríto entrada = 0 en la poscondición significa que, al final delproceso, la entrada estará vacía. Es decir, todas las entradas habrán sido leídaspor el proceso, pero no pueden ser leídas de nuevo. Esta peculiaridad de losestados inícial y final reflejan una forma peculiar de procesar la entrada y lasalida en una ejecución del algoritmo. Es decir, el acto de obtener las entradasconsiste en una serie de pasos discretos, en los cuales: 1) un valor no puede serobtenido de nuevo después de haberse obtenido una vez; y 2) los valoresindividuales de la entrada se obtienen exactamente en el orden en el que seintroducen por el teclado.

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 102: ComputacionI A

Problemas algorítmicos y su solución 95

Con objeto de enfatizar la estrecha relación existente entre la especificaciónde un algoritmo y la descripción del proceso correspondiente, encerramos ladescripción del proceso entre la precondición y la poscondición, como semuestra en la Figura 4.3.

(pre: entrada = <Notas" Notas" .. "' Notas") 1\ n> O1\ \fi,E (1, ... , n) :Notas, E (O, ... ,4))

Paso 1. Obtener La Lista de caLificacionesPaso 2. CaLcuLar n = número de notas de La ListaPaso 3. CaLcuLar Sum= La suma de Las caLificaciones de LaPaso 4. CaLcuLar CM ~ Sum/nPaso 5. Mostrar CM

{post: entrada ~01\

saL ida = Sum i E (1, ... , n} :Notas,ln}

}

\ Descrip­Lista \ ción del

Jproceso

Especificaciones

Figura 4.3. Unificación de la descripción de un proceso y su especificación.

4.2.2. los estados intermedios de un cálculo:introducción de variables

Los estados intermedios resultantes de cada paso intermedio de un cálculopueden describirse también mediante asertos. Contrariamente al caso de laprecondición y la poscondición, en este caso es necesario considerar valoresintermedios que es necesario calcular para obtener los resultados finales, asícomo los cambios que se producen en las propias entradas al incorporar valo­res individuales al proceso de cálculo. Por ejemplo, en el algoritmo de CM, losvalores intermedios se identifican por n (el número de calificaciones); Sum (lasuma de calificaciones individuales, Notas;, donde i = 1, oo., n); y CM (el prome­dio de notas resultante).

Estos valores intermedios se identifican simbólicamente, puesto que es im­posible predecirlos previamente a una ejecución concreta del algoritmo. Porejemplo, una ejecución puede calcular el promedio de tres calificaciones (y portanto, n = 3), Yotra diferente puede calcular el promedio de 24 puntuaciones(n = 24). La misma situación es esperable para las propias puntuaciones opara su suma, para diferentes ejecuciones. Por ello, capturamos esta noción devalor variable de la suma utilizando un nombre apropiado, como Sumo

Definición. Una variable es un nombre simbólico que se asocia con unvalor o serie de valores particulares, durante una ejecución concreta de unalgoritmo, pero cuyo valor no puede predeterminarse en el momento enque se construye el proceso del algoritmo.

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 103: ComputacionI A

96 Computación l. Lógica, resolución de problemas, algoritmos y programas

Por tanto, n, Sum y CM son variables del problema de la CM.Podemos utilizar variables siempre que deseemos describir un estado inter­

medio de un cálculo. Por ejemplo, es posible describir el aserto:

{ent rada ~0/\ Sum = Sum i E {1, .•. , n l :Notas;

Para describir el estado de los cálculos, después de que se hayan completadolos pasos 1, 2 Y 3. Esto es una abreviatura de «Se ha obtenido la entrada, eltamaño de la entrada (n) ha sido determinado, y se ha calculado la suma de losn valores de entrada y se ha identificado este valor con la variable Sum».

Con objeto de localizar con precisión dentro del proceso dónde es cierto elaserto, lo colocamos justo inmediatamente detrás del paso del algoritmo que lohace verdadero. Una versión aumentada de la descripción del algoritmo delproceso CM podria ser la siguiente:

Paso 1. Obtener la lista de cal i fi cacionesPaso 2. Calcular n ~ número de notas de la listaPaso 3. Calcular Sum = la suma de las calificaciones de la lista

{entrada =0/\ Sum = Sum i E {1, ..• , n} :Notas;}

Paso 4. Calcular CM = Sum/nPaso 5. Mostrar CM

En general, se puede colocar un aserto entre dos pasos cualquiera de un cálcu­lo, y éste puede decir mucho o poco sobre el estado de los cálculos en esemomento del cálculo. Lógicamente, si se colocan asertos antes del primer pasoy después del último, ambos deben ser consistentes con la precondición y laposcondición, respectivamente. Por tanto, es posible colocar junto con la pre­condición y la poscondición un conjunto completo de asertos, con objeto declarificar la descripción de los pasos de un algoritmo, tal y como se muestra enla Figura 4.4.

En la práctica, el nivel de detalle que se muestra en la Figura 4.4 en losasertos intermedios es excesivo, puesto que la mayoría de la información puedededucirse de un aserto próximo. Es decir, existe mucha información redundan­te en esta descripción, lo que la hace inútil. Por ejemplo, cada aparición deentrada = 0 en los asertos después de los pasos del 2 al 4, puede eliminarse,puesto que es redundante con la información que aparece en el aserto de detrásdel paso 1. De forma más general, cualquier aserto intermedio puede eliminar­se si su contenido es directamente deducible de un aserto vecino.

Una especificación, descripción de proceso y anotaciones intermedias másútiles se muestran en la Figura 4.5. El propósito para el que se utilizan losasertos intermedios para ilustrar los pasos de un proceso es doble. Primero, losasertos aportan información para cualquiera que necesite comprender el efectode los pasos individuales del proceso de cálculo. Segundo, son un vehículoeficaz en el proceso de verificación de que ese conjunto de pasos resuelveverdaderamente el problema original que se planteó en forma de precondición

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 104: ComputacionI A

Problemas algorítmicos y su solución 97

{pre: entrada = (Notas" Notas., ••. , Notas,) /\ n > O/\ Vi E {1, ... , n} :Notas; E {O, " .. , 4}}

Paso 1. Obtener la lista de calificaciones{entrada = 0} ---------------------------,Paso 2. Calcular n ~ número de notas de la lista{entrada =0/\ n > O}Paso 3. Calcular Sum = la suma de las calificaciones de la lista{entrada =0/\ Sum = Sum i E {1, ... , n} :Notas;}Paso 4. Calcular CM = Sum/n(entrada =0/\ Sum = Sum i E (1, .. "' n) :Notas, /\ CM = Sum/n} _Paso 5. Mostrar CM{post: entrada =0/\sal ida = Sum i E {1, " .. , n} :Notas,!n}

As e r los i n I e rme dio S _--'-----'-.-JL-'

Figura 4.4. Introducción de asertos intermedios en la descripcióndel algoritmo del problema CM.

y poscondición. Obsérvese que existe una estrecha correspondencia entre estaforma de describir los pasos de un algoritmo y el modelo original de entrada­proceso-salida descrito en la Figura 4.1. Es decir, la precondición se correspon­de con la entrada, el paso del algoritmo describe el proceso, y la poscondicióncaracteriza la salida.

Ahora que podemos describir con más precisión las transiciones entre esta­dos en un proceso algorítmico, en la Sección 4.3 y posteriores trataremos deconseguir un nivel de precisión comparable en el proceso de descripción de lospasos de que consta el propio algoritmo.

(pre: entrada = (Notas" Notas., , Notas,) /\ n > O/\ Vi E (1, .. "' n) :Notas, E {O, , 4}}

Paso 1. Obtener la lista de calificacionesPaso 2. Calcular n = número de notas de la lista(entrada =0/\ n > O)Paso 3. Calcular Sum = la suma de las calificaciones de la listaPaso 4. Calcular CM = Sum/n(entrada =0/\ Sum ~ Sum i E (1, ... , n) :Notas; /\ CM = Sum/n}Paso 5. Mostrar CM(pos t: ent rada = 0 /\salida = Su.. i E (1, ... , n) :Notas,!n}

Figura 4.5. Una versión del problema del cálculo del promedioanotada parcialmente.

Ejercicios

4.2. Describir en castellano el conjunto de pasos de un proceso algorítmicoque calcule y muestre el conjunto de calificaciones que están por encima

Page 105: ComputacionI A

98 Computación l. Lógica, resolución de problemas, algoritmos y programas

del promedio para una lista de calificaciones arbitraria. Considérese este

problema como una extensión del problema CM. Ser muy general al

describir los pasos del proceso. ¿Que variable adicional es necesaria?

4.3. ¿Cuáles serían la precondición y poscondición del proceso del Ejercicio

4.2? Definir una lista sencilla y la salida correspondiente que daría el

algoritmo construido.•

4.3. LENGUAJE ALGORíTMICO

El conjunto de pasos individuales que, combinados, forman la descripción

completa de un proceso o algoritmo, deben escribirse con un estilo lingüístico

muy preciso. El castellano, por su propia naturaleza, es un medio inadecuado

para conseguir la precisión adecuada. El algoritmo de cinco pasos, mostrado

en la Sección 4.2 para calcular la calificación media, es demasiado vago para

ser útil.El tipo de lenguajes que tienen la suficiente precisión para ser útiles en la

descripción de algoritmos, reciben el nombre de lenguajes algorítmicos o len­

guajes de programación. Los lenguajes de programación difieren del castellano

en tres puntos esenciales:

1. Los lenguajes de programación tienen un vocabulario y una sintaxis

muy limitados. Por tanto, los programas sólo pueden describir algorit­

mos, y son inadecuados para describir otros tipos (no algorítmicos) de

prosa.2. El vocabulario de un lenguaje de programación contiene sólo aquellos

tipos de acciones básicas que una computadora puede entender y reali­

zar, y no otras. Por ejemplo, un lenguaje de programación soporta las

operaciones aritméticas habituales (suma, resta, multiplicación, divi­

sión, comparación); acciones propias del procesamiento de texto, accio­

nes de procesamiento de gráficos y acciones de entrada/salida. Las

acciones que una computadora no puede realizar son muchas y varia­

das -correr, sacar de banda, recibir, sentir, hacer quiche y crear pintu­

ras al óleo- son algunas de las acciones que no se encuentran dentro

de vocabulario de una computadora.

3. La sintaxis de un lenguaje de programación es muy rígida, y no permite

muchas variaciones de estilo. Por ejemplo, el cálculo del cociente entre

Sum y n se expresa como Sum/n y no existe forma alternativa.

La descripción de un proceso o algoritmo en un lenguaje de programación que

difiere del castellano recibe el nombre de programa. Los programas son ejecu­

tables por las computadoras, mientras que los algoritmos descritos en castella­

no no. (Algunos lenguajes de programación están diseñados para parecerse al

inglés, por lo que los programas escritos en él parecen estarlo en este idioma.

El COBOL es uno de estos lenguajes. Sin embargo, la capacidad de expresión

en inglés no es posible alcanzarla en ningún lenguaje de programación.)

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 106: ComputacionI A

Problemas algorítmicos y su solución 99

Existen varios lenguajes de programación entre los que podemos elegirpara describir algoritmos. Algunos están diseñados especialmente para la ense­ñanza y el aprendizaje de los algoritmos, las computadoras y la resolución deproblemas algorítmicos. Pascal es un lenguaje de este tipo, y lo utilizaremos enlos ejemplos que pondremos a lo largo de este texto. Otros lenguajes de pro­gramación populares son C, Modula-2, Ada, FORTRAN, COBOL, LISP,ScheQ1e y ensambladores a nivel máquina. Introduciremos los lenguajes en­sambladores en el Capítulo 7. Algunos de los lenguajes mencionados antes sonbien conocidos por los programadores profesionales (como FORTRAN y CO­BOL), pero no son adecuados para el aprendizaje y la enseñanza del procesode resolución de problemas algorítmicos.

Hasta el momento, nos hemos familiarizado con la sintaxis del Pascal,gracias al manual de laboratorio adjunto. Por ello, no es difícil comprenderque el programa de la Figura 4.6 es una implementación en este lenguaje delproblema CM, que habiamos descrito informalmente en castellano.

program caLcuLaCM;{Esto es un programa que caLcuLa La CM de una serie de una o máscaLificaciones numéricas, cada una de eLLas en eL rango O.. 4,que se introducirán por eL teclado}usesListas;

val'Notas: Li stas;i,n:integer;Sum, CM: rea L;

begin{pre: entrada = (Notas" Notas" .. "' Notas") 1\ n > O

1\ \1 i E {1, ... , n} : No t a s; E {O, ... , 4} }

(Paso 1. Obtenemos La Lis ta de ca Lif i cac iones}WriteLn ('Introducir La Lista de calificaciones: ');ReadLista (Notas);

{Paso 2. CalcuLar n o número de caLificaciones en La lista)n := LongL i sta(Notas);if n > O thenbegin

{entrada ~01\ n > O}

{Paso 3. CalcuLamos Sum = La suma de Las caLificaciones de la Lista}Sum := O:i := 1 ;whi le i <= n do

beginSum :~ Sum + Notas[i];i :~ i + 1

endend;

{Paso 4. CaLcuLamos CM = Sum/n)CM = Sum/n;

(Sum ~ SUII iE (1, ... , n) :Notas; 1\ CM = Sum/n}

Page 107: ComputacionI A

100 Computación l. Lógica, resolución de problemas, algoritmos y programas

{Paso 5. Se muestra CM}WriteLn( 'La CM de esas calificaciones es =', CM : 5 : 2)

end [if]{post entrada =01\salida ~ SUIl i E {1, ... , n}:Notas,ln}

end. {CalculaCM}

Figurp 4.6. Programa Pascal que se corresponde con la descripciónde proceso de la Figura 4.5.

Los cinco pasos originales de la descripción del proceso se incluyen aquicomo comentarios entre corchetes, de forma que la correspondencia entre estoscasos y el grupo de instrucciones Pascal sea fácilmente identificable. La pre­condición, la poscondición y los asertos intermedios también se ponen derelieve mediante comentarios entre corchetes. Puesto que se han escrito comocomentarios de Pascal, el programa puede ser ejecutado en una computadoradirectamente, sin necesidad de hacer ninguna modificación.

El programa introduce algunos elementos nuevos que no se han tratado enel manual de laboratorio. Los introduciremos en la sección siguiente (para unadescripción más detallada, véase el manual de laboratorio). Para el propósitode la discusión que nos ocupa, pondremos un énfasis especial en la correspon­dencia entre el lenguaje de programación (como vehiculo para describir deforma precisa el proceso algorítmico) y la especificación (como vehiculo paradescribir de forma precisa el problema lingüístico a resolver).

4.3.1. Sintaxis y semántica

El conjunto de instrucciones Pascal de la Figura 4.6 representa una implemen­tación del problema CM, en un lenguaje de programación concreto. El signifi­cado de cada instrucción está definido de forma estricta, y trata de expresar deuna forma más rigurosa el conjunto de pasos que componen el algoritmo,originalmente expresado en castellano. Por ejemplo, la frase

Obtenemos la lista de calificaciones

que constituye el primer paso de la descripción de la Figura 4.3, se convierte endos instrucciones de Pascal:

WriteLn ('Introducir la lista de calificaciones:');ReadLista (Notas);

La instrucción Wr; te Ln indica al usuario qué tipo de entrada se pretendeobtener, y la instrucción ReadL; sta cumple la tarea de conseguir la lista deenteros.

Listas. Este programa hace us\> del tipo L; s ta y sus operaciones relaciona­das, que se resumen en la Figura 4.7. Los programadores pueden utilizar el

Pedro Pacheco
Highlight
Page 108: ComputacionI A

Problemas algorítmicos y su solución 101

B~ ;::1:7.: :~"g3lEntrada

RadLi sta

,,----..@e List0 InserListaDeleteLista

) oo.b.."", ["di ,,]

¡salida I GVFigura 4.7. Resumen de las operaciones de Lista.

tipo Lis ta y sus operaciones, sin más que hacer la declaración uses Lis ta;después de la cabecera del programa. (Las definiciones están ocultas al progra­ma, aunque su utilización se ha descrito cuidadosamente en el manual delaboratorio.)

Un programa Pascal que incluye la unidad Lista está capacitado paraobtener, procesar y escribir listas completas de enteros, en lugar de trabajar conun número cada vez. Esto supone una ayuda inestimable para la resolución demuchos problemas algorítmicos, y la utilizaremos extensivamente en este texto.Una variable que se declare como de tipo Lista, contendrá una lista devalores completa, como ocurre con la variable Notas declarada en el proble­ma CM, con el objetivo de almacenar una lista de calificaciones completa:

var Notas: Li sta;

El procedimiento ReadL i sta (Notas) obtiene del dispositivo de entra­da una lista de enteros, suponiendo que la lista está encerrada entre paréntesis,y se asigna su valor a la variable Notas. Así, por ejemplo, si se teclea laentrada:

(3 2 1 3)

El procedimiento ReadL i st (Notas) dejará la variable Notas en el estado

Notas = (3 213)

La función LenghtLista (Notas) devuelve el número de elementosque componen la lista, mientras que la expresión Nota s [i ] devuelve el valordel i-ésimo elemento de la lista Notas. El entero i recibe el nombre de índice

Page 109: ComputacionI A

102 Computación l. Lógica, resolución de problemas, algoritmos y programas

del elemento devuelto. Así, por ejemplo, un caso posible podría ser que Leng­

htLista (Notas) devuelva el valor integer 4, y Notas[3] devuelva el

valor real 1. Una díscusión más completa de las operacíones sobre Lis ta

mostradas en la Fígura 4.7, puede encontrarse en el manual de laboratorio. Es

conveniente repasar esta discusión antes de construir programas que utilicen

listas.

Limitaciones del conjunto de caracteres ASCn. Cuando se incorporan asertos

y otros comentarios dentro del texto de un programa, es necesario recordar las

limitaciones del conjunto de caracteres ASCn, que es el estándar de los carac­

teres que se pueden codificar y que utilizan la mayoría de los constructores de

computadoras. (ASCII es un acrónimo de American Standard Code for Infor­

mation lnterchange)*. Utilizando un conjunto de caracteres estándar, es posi­

ble la transferencia de información entre computadoras diferentes. (Como entre

Macintosh y PCs de IBM, por ejemplo). La lista completa de caracteres ASCII

y su. codifícación se incluye en el Apéndice A.Los científicos suelen utilizar letras gríegas y otros símbolos especiales,

subíndices, superíndices, al escribir expresiones lógicas y matemáticas o al

escribir asertos. En el problema de CM se utilizaron, por ejemplo, No t a Si' 0y ~ estilo matemático, continuando con la notación convencional de los Capí­

tulos 2 y 3. Desgraciadamente, esos caracteres no pueden aparecer dentro de

un programa Pascal, por no estar incluidos dentro del conjunto de caracteres

ASCII. Por ello, cuando convertimos un algoritmo en un programa Pascal,

utilizamos un convenio de sustitución ASCn para la sustitución de los símbolos

más comunes, como el de la Tabla 4.2.

Tabla 4.2. Sustitutos ASCII para los símbolos matemáticos

Símbolomatemátíco

Nota Si

oLO Sum~

V3Á

V

E

Significado

Selección del i-ésimo elemento de la lista

Conjunto vacíoSumatoriaMenor o igualCuantificador universalCuantificador existencialConjunciónDisyunciónPertenencia a conjunto

SustitutoASCII

Notas[;]vacíoSum~

para todoexísteÁ

orín

• N. del T.: Estándar Americano de Codificación para el Intercambio de Información.

Pedro Pacheco
Highlight
Page 110: ComputacionI A

Problemas algorítmicos y su solución 103

Utilizando las equivalencia de la tabla anterior, algunas de las expresionesmatemáticas de la Figura 4.6, podrían escribirse utilizando sustitutos ASCIIaceptables de la forma siguiente:

entrada =01\ n > O8u.; E (1, ... , n): Notas,

entrada = vac;o 1\ n > O8um; ;n {1, .. "' n}: Notas[i]

4.3.2. Repetición y bucles: inicialización, invarianzay terminación

Un nuevo e importante concepto que encontramos en la solución al problemaCM es el de bucle.

Definición. Un bucle es una secuencia de instrucciones que pueden ejecu­tarse O, I ó un número finito de veces n.

El concepto de bucle es uno de los más importantes de todos los que se utilizanen el diseño de algoritmos. ¿Por qué necesitan bucles los programas? Existendos razones fundamentales:

1. Economía de las expresiones.2. Impredecibilidad del tamaño de la entrada.

Ambas razones para la existencia de bucles se pueden comprender si analiza­mos la situación siguiente: Supongamos que es necesario diseñar un algoritmoque calcule S como la suma de seis calificaciones, dadas por las variables 91 a96. Una forma de calcularlo sería realizando la declaración y secuencia deinstrucciones Pascal siguiente:

val" 91,92,93,94,95,96: real;

S := O;8:=8+91;8 := 8 + 92;8 := 8 + 93;8:=8+94;8:=8+95;8 := 8 + 96;

Esta alternativa es absolutamente torpe. Si tuviéramos que extender el proble­ma mínimamente, y necesitásemos sumar 100 calificaciones, la elección realiza­da sería bastante poco brillante.

Bastante más dificil, e incluso bordeando lo imposible, sería extender elalgoritmo para el caso en que el número de calificaciones fuera impredecible(aunque finito); por ejemplo, n. Naturalmente, el valor de n no puede predecirse

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 111: ComputacionI A

104 Computación l. Lógica, resolución de problemas, algoritmos y programas

en el momento en que se escribe el programa, de forma que el programa pueda

calcular el valor de Sum para cada valor particular de n, en el momento en que

el programa es ejecutado o, como dicen algunos, corrido. Es decir, en una

ejecución del programa, n puede valer 6, y en la siguiente ejecución del mismo

programa 100, en otra quizá 1000.Lo que ,necesitaremos es que el lenguaje aporte facilidades que permitan

generalizaciones de dos tipos:

1. La posibilidad de asignar un único nombre a una lista de números

arbitrariamente larga.2. La posibilidad de escribir instrucciones o grupos de instrucciones que

puedan ser ejecutados reiteradas veces, pero que sean susceptibles de

ser interpretados de una forma diferente en cada repetición.

La primera posibilidad la aporta el tipo Lis ta, tal y como se describió en la

sección anterior. La segunda capacidad la aporta la instrucción de Pascal

wh i l e, que permite ejecutar reiteradas veces una instrucción, o grupo de

instrucciones, pero con interpretaciones diferentes en cada repetición. Esto es

lo que necesitamos para simplificar la torpe construcción que nos calculaba la

suma de n valores.Ilustremos estas capacidades por separado. Supongamos que se declara

sólo una variable 9, del tipo Lis ta, en lugar de las seis variables de 91 a 96.

Entonces, es posible cambiar el programa original en la forma siguiente, sin

cambiar su significado:

varg: Lista;

5 := O;5 :=5+g[1];5 := 5 + g[2];5 := 5 + g[3];5:=5+g[4];5 := 5 + g[5];5 :=5+g[6];

Es decir, la poscondición de la secuencia anterior seguirá siendo:

5 = Sum i E {1, ... , 6}: g[ i]

haciendo una única declaración, en lugar de seis.Pero las seis instrucciones últimas son idénticas, a excepción del valor del

índice de la referencia a la lista 9 [i ]; es decir, i varia entre 1 y 6 a lo largo de

las instrucciones. Con objeto de generalizar esas instrucciones de forma que

sean idénticas, necesitaremos introducir una variable, por ejemplo i, que reco­

rra la secuencia de valores que se muestra en la Figura 4.8:

Pedro Pacheco
Highlight
Page 112: ComputacionI A

Problemas algorítmicos y su solucíón 105

8 := O;i := 1;8:=8+g[i];i :=i+1;8:=8+g[i];i := i + 1 ;8:=8+g[i];i:=i+1;

'8 := 8 + g[i];i:=i+1;8:=8+g[i];i:=i+1;8 ;= 8 + 9 [i];i:=i+1;

Figura 4.8. Suma de seis elementos: un paso hacia la generalización.

Parece como si estuviéramos retrocediendo, puesto que ahora tenemos queescribir el doble de instrucciones, por lo que el nuevo método parece unalocura. Sin embargo, cada pareja de instrucciones a partir de las dos primerases idéntica:

whi le b dobegin

5; s; ... ; send

Figura 4.9. Forma general de la instrucción wh i le: b es una expresión boo­leana; s; s; •.• ; s es cualquier secuencia de instrucciones en Pascal.8:=8+g[i];i:=i+1;

y la secuencia entera sigue satisfaciendo la poscondición.La instrucción whi l e permite repetir el par de instrucciones seis veces. Suforma general se presenta en la Figura 4.9, y una descripción más detalladapuede encontrarse en el manual de laboratorio.Cuando se ejecuta una instrucción wh i l e, primero se evalúa la condición b.Si el resultado de la evaluación es verdadero, se ejecuta la secuencia s; s;.•. ; s una vez. La condición b se vuelve a evaluar, y si el resultado esde nuevo verdadero, se vuelve a ejecutar la sentencia. Esta pareja de accionesse ejecutan reiteradamente, hasta que la condición resulta evaluada a falso,momento en que se concluye la repetición de las instrucciones y se terminala ejecución del wh ; le.Sin embargo, cuando utilizamos un bucle wh ; l e, debemos tomar una seriede precauciones inicia/espara que éste se ejecute bajo control. Es decir, la ejecu­ción del bucle debe terminar después de un número finito de repeticiones, yuna vez terminado, debe satisfacerse la poscondición. Por esta razón, a losbucles suele denominárse!es bucles controlados. La estructura de un bucle con­trolado, que incluye tanto la inicialización como la instrucción wh i l e, semuestra en la Figura 4.10:

Pedro Pacheco
Highlight
Page 113: ComputacionI A

106 Computación l. Lógica, resolución de problemas, algoritmos y programas

Instrucciones de inicializaciónwhile b do

begins;s; ... ;5

end;

Figura 4.10. Estructura general de un bucle controlado en Pascal.

Por tanto, los requisitos para que un bucle sea controlado son que las instruc­ciones de inicialización, la expresión booleana b y las instrucciones s; Si... i s estén escritas de tal forma que: 1) se garantice la terminación del bucle;y 2) se satisfaga la poscondición del bucle.

En nuestro ejemplo, las instrucciones de inicialización S : = O e ; : = 1, laexpresión booleana ; <= 6, Ylas instrucciones S : = S + 9 [ i] e ; : = ; + 1,combinan y satisfacen estos requisitos. Es decir, nuestro ejemplo puede reescri­birse como el bucle controlado de la Figura 4.11.

5 := O;i := 1;while i <~ 6 do

begin5:=5+g[i];i := i + 1

end¡

Figura 4.11. Suma de los seis elementos de una lista. Generalización.

Obsérvese que en la Figura 4.11 la condición; <= 6 describe con exactitud lacondición bajo la cual el bucle debe seguir repitiéndose, con objeto de conse·guir el equivalente a los seis pares de instrucciones como las que aparecen en laversión original de la Figura 4.8.

Utilizando el método de los bucles controlados, se ha conseguido unageneralidad y economia en las expresiones, que en otro caso habría sido dificilde conseguir. Obsérvese que el paso 3 de la solución al problema CM ( el buclewhi le de la Figura 4.6) es prácticamente idéntico al bucle whi le de la Figura4.11. Los dos bucles difieren sólo en la forma de las expresiones booleanas quegobiernan el número de repeticiones del bucle, y en el nombre de las variables.En la Figura 4.11, el bucle se repetirá exactamente seis veces; mientras que enel bucle original, el número de iteraciones viene determinado por n, o númerode calificaciones en la lista Notas. Gracias a la generalidad que nos aporta laintroducción de la variable n, es posible resolver el problema CM. Sin n, lasolución estaría limitada a la que calcula el promedio de un número predeter­minado de calificaciones. La permanencia de esta restrícción supondría unasituación bastante insatisfactoria no sólo para este problema, sino que nosatisfaría los requisitos de generalidad exigidos a las soluciones algorítmicas.

Invarianza de bucles. Un aspecto importante en el diseño de soluciones aproblemas mediante la utilización de bucles, es el poder garantizar que el bucle

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 114: ComputacionI A

Problemas algorítmicos y su solución 107

termina, y que después de esto se satisface exactamente la poscondición para laque fue diseñado. Para conseguir este propósito se utiliza un tipo especial deaserto, llamado invariante del bucle (o simplemente invariante).Informalmente, podemos pensar en el bucle como en un aserto sobre elestado de los cálculos, que vale verdadero (es decir, que no varía) antes ydespués de cada iteración del bucle, mientras se esté ejecutando. Es habitualdiferenciar los invariantes de otro tipo de asertos de los programas, porqueguardan una relación especial con los fragmentos de programas en los queestán incluidos. El aserto siguiente es un invariante del bucle del progra­maCM.

(inv: Sum = Su. j in (1, """' i - 1}: Notas[j] /\ 1 <= i <= n + 1}

Para demostrar que esto es, sin duda, el invariante del bucle, debemoscomprobar que cada valor de ; durante la ejecución del bucle:

1. Sum es la suma de las i - 1 primeras calificaciones en la lista Not as; y2. El valor de ; está comprendido siempre entre 1 y el valor que causa laterminación del bucle.

Considérese el ejemplo en el que Notas = (3 2 1 3), por lo que n = 4. Elestado antes de cada iteración del bucle, y la comprobación correspondientedel valor del invariante, puede sintetizarse de la forma siguiente:

Antesde la Estado

iteración

1 S=O/\;=1J\n=4

2 S=3/\;=2J\n=4

3 S=5J\;=3/\n=4

4 S=6/\i=4J\n=4

5 S=9J\i=5J\n=4

Comprobación del invariante

Sum = Sum j ; n {1, ""., O}: No t a s [j]J\1<=1<=5Sum= Sum j in {1, •.. , 1}: Notas[j]/\1<=2<=5Sum= Sum j in {1, •.• , 2}: Notas[j]J\1<=3<=5Sum = Sum j ; n {1, ..• , 3}: No t a s [j]J\1<=4<=5Sum = Sum j in {1, •.. , 4}: Notas [j]J\1<=5<=5

Puesto que la quinta iteración no tiene lugar (se produce la salida del wh i Le,puesto que; <= n cambia a falso), el invariante conduce al cumplimiento de laposcondición al salir del bucle. Esto es,

Sum = Su.. j in (1, "."' i - 1}: Notas [j] /\ 1 <= i <~ n + 1

Pedro Pacheco
Highlight
Page 115: ComputacionI A

108 Computación ,. Lógica, resolución de problemas, algoritmos y programas

que por sí mismo acaba siendo:

Suro = Sum j ; n {1, ... , n}: Nota s [j]

Cuando el valor de ; alcanza n + 1.

¿Cuill es la relación entre el invariante del bucle y la secuencia de instruc­

ciones s; s; ... ; s que constituyen el cuerpo del bucle? Es necesario que

estudiemos en nuestro ejemplo la relación entre las instrucciones

Suro := Suro + Notas[;]i

; := ; + 1

y el invariante

Suro = SUII j ; n {1, ... , ; - 1 }: Notas [j] 1\ 1 <= ; <= n + 1

El cuerpo del bucle se ha diseñado de forma intencionada con dos objetívos en

mente:

1. El cuerpo preserve el invariante (valga verdadero).

2. El cuerpo produzca una progresión hacia la terminación del bucle.

En general, los bucles no tienen que hacer ni más ní menos que esto -todo lo

demás es irrelevante.

4.3.3. Tres vision~s de la misma solución al problema",.

El programa de la Figura 4.6 resulta de la composición de tres niveles de

lenguaje distintos: el código en Pascal; la descripción del proceso, que describe

en castellano qué ocurre en cada paso del proceso que describe el programa; y

la especificación formal que aparece antes y después de cada paso del proceso.

Los tres niveles juntos suponen un nivel elevado de redundancia; es decir,

expresan los mismos conceptos en tres estilos diferentes -algorítmico formal

(Pascal), algorítmico informal (castellano) y declarativo formal (especificacio­

nes).Esta redundancia enfatiza el hecho de que una solución programada a un

algoritmo se escribe simultáneamente para tres tipos de audiencias:

1. La computadora.2. La gente que diseña y lee el programa.

3. La gente que verifica la corrección del programa.

La computadora sólo tiene en cuenta el código en Pascal: la computadora

seguirá con exactitud el código al realizar el proceso. Los programadores hu­

manos se interesarán por el código en Pascal, los comentarios escritos en

castellano, y las pre y poscondiciones si quieren entender y desarrollar correc-

Pedro Pacheco
Highlight
Page 116: ComputacionI A

Problemas algorítmicos y su solución 109

tamente el código y, posteriormente, ampliar o mejorar el programa. Los veri­ficadores humanos del programa estarán interesados en el código de Pascal, laprecondición, la poscondición y en los asertos intermedios mediante los cualesobtendrán una demostración rigurosa de la corrección del programa.En la Figura 4.12 se muestra lo que consideraría la computadora de laparte en Pascal del programa que soluciona el problema CM.

prograll ca l cu laCM;usesListas;

varNotas: Listas;i, n : integer;Sum, CM: real;

beginWriteLn ('Introducir la lista de calificaciones:');ReadLista (Notas);n := LongLista(Notas);if n > O thenbegin

Sum := O;i := 1 ;while i <= n dobegin

Sum :=Sum+Notas[i];i := i + 1

end;CM := Sum/n;WriteLn( 'La CM de esas cal ificaciones es = " CM : 5 2)end

end. (CalculaCM}

Figura 4.12. El programa CM, desde el punto de vista de la computadora.

Los programadores noveles suelen confundir el punto de vista de la com­putadora con el del lector. Es decir, suelen presentar sólo el programa comosolución a un problema algorítmico. Sin embargo, esta representación, por simisma, no es suficiente para la construcción y presentación de programasfiables.Cuando nos comprometemos en el proceso de resolver problemas algorít­micos, nuestra intención debe ser la de desarrollar programas comentadoscompletamente, de forma que estas anotaciones nos muestren la definición delproblema original, y los sucesivos pasos que hemos seguido en su solución.Para el problema de CM, el programa completo es, más o menos, como laversión mostrada en la Figura 4.13.

program calculaCM;{esto es un programa que calcula la CM de una serie de una o más

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 117: ComputacionI A

110 Computación l. Lógica, resolución de problemas, algoritmos y programas

calificaciones numéricas, cada una de ellas en el rango O.. 4, quese introducirán por el teclado}usesListas;

varNotas: Listas;i, n : integer;Sum, CM : real;

begin '{pre: entrada = (Notas" Notas" ••• , Notasn ) /\ n > O

/\ Vi E {1, ... , n}:Notas; E {O, ... , 4}}

{Paso 1. Obtenemos la lista de calificaciones}WriteLn('Introducir la lista de calificaciones');ReadLista(Notas);

{Paso 2. Calcular n o número de calificaciones en la lista}n := LongLista(Notas);if n > O thenbegin

{Paso 3. Calculamos Sum= la suma de las calificaciones de la lista}Sum := O;i := 1;while i <= n dobegin

Sum := Sum + Notas[i J;i := i + 1

end;

{Paso 4. Calculamos CM = Sum/n}CM = Sum/n;

{Paso 5. Se muestra CM}WriteLn('La CMde esas calificaciones es= " CM 5 2)

end {if}{post: entrada =0/\salida = Su.. i E {1, ... , n}: Notas;!n}

end. {CalculaCM}

Figura 4.13. El mismo programa, desde el punto de vista del lectory del desarrollador.

La versión de la Figura 4.13 difiere de la versión de la Figura 4.6, en queexcluye los asertos intermedios. Estos asertos son útiles cuando el programa esprobado y verificado. La prueba y verificación de programas se introduceseparadamente en el Capítulo 6.

Page 118: ComputacionI A

Problemas algorítmicos y su solución 111

Ejercicios

4.4. La lista siguiente contiene la lectura de las temperaturas diarias de unasemana de verano.

Temps = (78 62 71 73748584) *

a) ¿Cuál es el índice de la lista Tems, de la temperatura máxima de lasemana?

b) ¿Cuál es el valor de la temperatura máxima?e) ¿Cuántas temperaturas estuvieron por debajo del promedio sema­

nal?

4.5. Supongamos que necesitamos escribir un programa que calcule, parauna lista de siete temperaturas como la del ejemplo anterior, todas lasrespuestas a las cuestiones de dicho ejemplo.a) Escribir una precondición que describa el conjunto de todas las

listas de entrada válidas para el programa.b) Dar una poscondición que describa, para las entradas válidas, las

salidas que debe mostrar el programa.e) ¿Cuál de todas las cuestiones precisa la utilización de un bucle para

que el programa pueda contestarla?

4.6. Debajo, se muestra un bucle controlado que calcula la temperaturamáxima de una semana, y la deja en la variable Max.

Max := Temps[1]¡i := 2;while i <= LenghtLi sta (Temps) do

if Temps [i] > Max thenMax := Temps[i]¡

a) Trazar una ejecución de los pasos de bucle, utilizando los valores deTemp s del Ejercicio 4.4. Trazar significa escribir los valores quetoman las variables ; y Max, en relación a los valores deTemps [; ], al comienzo de cada iteración.

b) Después de examinar esos valores y examinar el comportamientodel bucle para cualquier lista de valores, escribir un invariante parael bucle.

4.7. Escribir un bucle controlado que satisfaga las especificaciones siguien­tes:

{pre: L ~ (e" e" ••. , en) /\ n > O)

• N. del T.: Expresadas en grados Farenheith.

Page 119: ComputacionI A

112 Computación ,. Lógica, resolución de problemas, algoritmos y programas

{post: SumPares = La suma de todos Los eLementos de L con índíce par 1\

Sumlmpar = La suma de todos Los eLementos de L con subíndice ímpar}

4.8. Escribir las instrucciones de Pascal que calculen el promedio de las sietetemperaturas de la lista del Ejercicio 4.4, asignando el valor a la varia­ble TemProm. Dar las precondiciones y postcondiciones de esas instruc­ciones, así como el invariante del bucle controlado que contienen.

4.9. Escribir las instrucciones en Pascal que cuenten el número de tempera­turas de la lista del Ejercicio 4.4, que estén por debajo de valor medio(TemProm) y dejen este valor en la variable entera ndebajo. Escribirla precondición y la poscondición para esas instrucciones, asi como elinvariante del bucle que contienen. ¿Están esas precondiciones relacio­nadas con las poscondiciones del Ejercicio 4.8? ¿Qué sugiere esto sobreel orden en que esos dos grupos de instrucciones deberían escribirse silas usásemos para resolver el Ejercicio 4.4c?

4.10. ¿Qué mostraria el siguiente fragmento de programa?:

var x, y: reaL;m, n, p: ínteger;

beginreadln (x, m);read (y);read (n, p);wríte (n, x);wríteln (p);wríteln (y, m);

end.

si se le suministrase la entrada siguiente:

13.21523.7236575354679

4.4. MÁS PROBLEMAS ALGORíTMICOS

En esta sección nos alejamos del ya familiar problema de CM, e introducimosotros problemas algorítmicos junto con sus soluciones. Estos nuevos ejemplosilustran el conjunto de problemas que son susceptibles de solucionarse utili­zando una computadora. También nos servirán para ilustrar cómo los tresestilos diferentes (descripción en castellano de los pasos individuales, especifi­caciones y otras aserciones, y codificación en lenguaje Pascal) se utilizan pararealizar una descripción y resolución completa del problema.

Page 120: ComputacionI A

Problemas algorítmicos y su solución 113

4.4.1. Cálculo de el

Desarrollemos un programa llamado Pot en c i a que calcule la b-ésima poten­cia de a, o ab

, donde a y b son enteros y el resultado un número real. Porejemplo, escrito como una función de Pascal Potencia(2,3) calcularia elvalor 23 = 8.

El\ la construcción de una solución, debemos precisar previamente no sóloel resultado esperado, sino también el rango de enteros para los que el progra­ma está bien definido; es decir, sus precondiciones. En particular, debemosespecificar que ciertas parejas de valores de a y b, tales como a = OYb = - 1,deben ser excluidas, puesto que podrian conducirnos a errores computaciona­les. (En este caso, Potenci a (0,1) representaría 0- 1 ó 1/0, que representauna división con resultado indefinido). También debemos tener en cuenta laslimitaciones del lenguaje de programación en el que expresamos el algoritmo.Por ejemplo, muchas versiones de Pascal restringen el rango de valores de losenteros al rango - 215

... 215- 1. Si identificamos estos valores con Mi nlnt y

Maxlnt, respectivamente, entonces las precondiciones de Potencia puedendescartar todos aquellos valores de a o b que conduzcan un resultado queexceda a Minlnt o Maxlnt. Por ejemplo, a = 2 Y b = 16 darían comoresultado 216

, que sería un valor mayor que Maxlnt para muchas versionesPascal.

Teniendo presentes estas condiciones, las precondiciones y poscondicionessiguiente podrían ser apropiadas para diseñar el programa de la potencia.

{pre: a y b son enteros A (a", O v a = O A b '" O)A Minlnt '" a b

'" Maxlnt}{Pos t: resu l t = ab

}

Para los valores de a y b que satisfagan esta precondición, el resultado ab

podría definirse como:

Definición ab = 1 if b O

: ':/~av'~ ~'.:~ Iif b > O

if b < O

Lb-a es

En la construcción de una solución al problema, debemos tener en cuenta queel valor de b, que gobierna el número de veces que se calcula a por a, es unavariable. Por tanto, cualquíer solución que calcule el producto de las basesdebe contener un bucle.

El diseño del bucle se ve facilitado si analizamos el caso en que b espequeño, y la varíable P = ab resultante se calcula en la forma de la Tabla 4.3.De los casos de esta tabla podemos hacer las observaciones siguientes:

1. El número de iteraciones del bucle es b - 1.

Page 121: ComputacionI A

114 Computación ,. Lógica, resolución de problemas, algoritmos y programas

2. La inicialización del bucle se realiza mediante la asignación P : = a.3. La instrucción que debe repetirse b -1 veces es la asignación P := P * a.

Este ejemplo nos sugiere nuevas ideas sobre la naturaleza del invariante delbucle. Esto es, de la i -ésima iteración del bucle, donde 1 ~ i ~ b, el valor de Pviene dado por

,{; nv: P = a i A 1 <= ; <= b}

La salida del bucle se producirá inmediatamente antes de la b-ésima iteración(que nunca tendrá lugar). Ahora i = b Yel invariante se convierte por sí mismoen P = ab, que está bastante próximo de la poscondición del problema.

Tabla 4.3. Resultados intermedios para el problema de la potencia

VaLor de b CáLcuLo de ab

1 P := a2 P := a;

P := P * a3 P := B;

P := P * a;P := P * a

4 P := B;P := P * a;P :=P*a;P := P * a

Poscond;c;ón

{P = a}

{P=a*a}

{P=a*a*a}

{P=a*a*a*a}

Entonces, si utilizamos la variable i para controlar el número de iteracio­nes del bucle, tomará todos los valores del rango de enteros comprendidosentre 1 y b ~ 1, para que el cálculo de P sea correcto. Estas consideracionesnos conducen al programa Pascal comentado, que se muestra en la Figura 4.14.

¿Quién comprueba las precondiciones? Cuando observamos la solución a al­gún problema algoritmico, tales como el de la Potencia o el de la CM,es normal preguntarse: ¿de quién es responsabilidad comprobar el cumpli­miento de las precondiciones?, ¿del programa o del usuario del programa?Nos gustaría tener algún tipo de garantía operativa de que ninguna entradadiferente de aquellas para las que fue diseñado el programa se producirá ytendremos así garantizado que no se nos contaminará ni peligrará la inte­gridad del programa.

Consideremos el programa Potencia, para el que la precondición esta­blece que, para algunos valores de a y b, el resultado a b puede estar fuera delconjunto de valores enteros que la computadora puede reconocer. Desgracia­damente, esta precondición del programa Potenc i a no puede ser comproba­da explicitamente por el propio programa, puesto que la acción de calcular ab

Pedro Pacheco
Highlight
Page 122: ComputacionI A

Problemas algorítmicos y su solución 115

para valores inadecuados provoca un error en tiempo de ejecución; un mensajesimilar a ; nteger overf Low aparecerá en el monitor, y la ejecución con­cluirá repentinamente.

progra. Potencia;{Este programa calcula la b-ésima potencia de a)varP: real;

1I, b, i: i nteger;begin{Pre : ent rada = a b A (a <> O or a ~ O A b <> O)

A Mi nlnt <= a b <= Maxlnt}WriteLn( 'lntroduci r dos enteros a y b: ');ReadLn(a,b);if b = O then

P := 1else

beginP := a;i := 1;while i <= abs(b) - 1 do

{i nv: P = a; A 1 <= i <= b)begin

P := P * a;i := i + 1

end;if b < O then

P := 1/Pend;

WriteLn('Potencia(a,b) =',P);{post: entrada = vacio A salida = a b

)

end. {Potencia)

Figura 4.14. Un programa que calcula abo

La precondición (a <> O v a = O Á b <> O) podría haberla comproba­do explícitamente el programa Potenc; a, y emitido un mensaje de erroren el caso de ser violada. Sin embargo, esto no es así en el programa de laFigura 4.14.

En general, debemos elegir entre dos extremos cuando tenemos que decidirquién debe comprobar las precondiciones:

• Estrategia 1. Diseñar el programa sin comprobar ninguna de las precon­diciones; construir el programa conforme a las precondiciones y poscon­diciones, pero de forma que resuelva un problema más general (es decir,de forma que haga algo incluso si alguien introduce entradas fuera delrango de las precondiciones), en este caso, el usuario no se ofenderá si elprograma se utiliza para los propósitos especificados por las precondicio­nes.

• Estrategia 2. Diseñar el programa de forma que compruebe todas aque­llas precondiciones que sea posible comprobar, sin provocar una termi-

Pedro Pacheco
Highlight
Page 123: ComputacionI A

116 Computación l. Lógica, resolución de problemas, algoritmos y programas

nación anómala del mismo. Adoptar un convenio para devolver estainformación al usuario, si las entradas están en desacuerdo con las pre­condiciones.

La estrategia 1 podria denominarse programación pasiva, mientras que la se­gunda podría denominarse programación defensiva. En un curso de programa­ción ¡lVanzado o de desarrollo profesional de software, siempre se prefiere laestrategia 2 sobre la 1. Sin embargo, en un curso introductorio, donde se estu­dian por primera vez otros conceptos fundamentales, suele aceptarse temporal­mente la estrategia 1. Este punto es importante y trascendente. Lo analizare­mos de nuevo en el Capítulo 6, cuando discutamos las diferencias entre lanoción de corrección de un programa, robustez y facilidad de uso.

No importa cuál de las dos estrategias decidamos seguir, siempre debemosintroducir las precondiciones y poscondiciones como comentarios al principioy al final del programa, respectivamente. Es decir, el lector humano no debetener nunca dudas de lo que hace el programa, aunque la propia computadorano esté totalmente informada de él.

4.4.2. Contar palabras de un texto

Los tipos numéricos integer y real se utilizan en casi todos los problemasalgorítmicos. Sin embargo, un gran número de problemas no se resolveríaadecuadamente con sólo esos dos tipos. Muchos problemas involucran a cade­nas de caracteres ASCII, como datos, y su solución precisa la utilización de unconjunto de operaciones características de este tipo de datos. La noción decadena en Pascal puede definirse de la forma siguiente:

Definición. Una cadena es una secuencia finita de cero o más caracteresASCII. Cuando se escribe una cadena en un programa Pascal, se encierraentre comillas simples ( , ) para distinguirla de las instrucciones del progra­ma que la rodean.

En la Figura 4.1 hemos visto ejemplos de cadenas. Por ejemplo, todos losmensajes como:

'Introducir la lista de calificaciones'

son cadenas. Extendiendo el concepto, podemos declarar variables del tipocadena (s tri ng) * cuando queramos manipular valores de tipo cadena, enlugar de valores numéricos. Acompañando a la idea de cadena de caracteres,están una serie de funciones y procedimientos que sirven para manipularlas ytransformarlas. Esas funciones se resumen en la Figura 4.15.

• N. del T.: Algunas implementaciones de Pascal incluyen entre los tipos incorporados eltipo string. Por ello, cuando nos refiramos al concepto seguiremos hablando de «cadenas" decaracteres y utilizaremos la palabra «slring" cuando hablemos del tipo.

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 124: ComputacionI A

Problemas algorítmicos y su solución 117

Figura 4.15. Resumen de las operaciones sobre cadenasy tipos involucrados*.

En el manual de laboratorio se realiza una discusión completa de estasoperaciones. Aquí sólo daremos unos pocos ejemplos que sirvan de ayuda paracomprender cómo se utilizan las cadenas de caracteres en la resolución dealgunos problemas algorítmicos de manipulación de textos.

Para declarar una variable cadena, por ejemplo s, basta con escribir ladeclaración siguiente:

va .. s: st .. ing;

Ahora podemos asignar valores a la variable utilizando la asignación o losprocedimientos Read o ReadLn, de la misma forma en que lo hacíamos conlos enteros o los reales. Por tanto, podemos escribir instrucciones como:

5:= 'Hello World!'; o Read(s);

Para conseguir el efecto que se muestra en el centro de la Figura 4.16.La Figura 4.16 muestra el efecto de la utilizacíón de varias de las operacio­

nes de las cadenas, tales como Lenght, Pos, Copy, Insert, Delete yWri te. Obsérvese que sus nombres son similares a los de las funciones quemanipulaban listas (véase Fig. 4.7). Más detalles pueden encontrarse en elmanual de laboratorio.

La longitud de una cadena (valor de la función Lengh t) es, simplemente,el número de caracteres de que se compone, incluidos los blancos, signos depuntuación y otros caracteres especiales del conjunto ASCII.

• N. del T.: En las Figuras 4.15 y 4.16 na se han traducido los nombres de las funciones.pues son los mismos que suelen tener esas funciones en las implementaciones de Pascal. queincluyen el tipo «string».

Page 125: ComputacionI A

118 Computación ,. Lógica, resolución de problemas, algoritmos y programas

¡Input I'Hello World!'

'Hello World!'

1Output 1

12

va.. s: St,;ng;

(s := 'Hello World! ';

lnsert(', Ciao', s, 12)

"'Hello World, Ciao!'

7

Figura 4.16. Utilización de algunas operaciones de cadenas de caracteres.

La función Pos realiza una búsqueda en la cadena, de izquierda a derecha,tratando de encontrar la primera ocurrencia de otra cadena. Así, si escribimosPos (s, I W' ) preguntamos por el índice o posición de la primera ocurrenciaempezando por la izquierda, de la cadena 'W'. Si la cadena no estuviera dentrode s, la {unción devolverá el valor O.

La función Copy selecciona una subcadena de la cadena argumento, defini­da por el valor de la posición inicial y la longitud. Así, Copy( s,1,1) selec­ciona la subcadena de s que comienza en la posición 1 y que tiene una longi­tud 1. Como se trata de una función, Copy devuelve un resultado de tipostring, aunque no altera para nada la cadena original s. La única forma en ques podría quedar modificada, sería mediante una subsiguiente asignación a s,del resultado de la función Copy, como ocurre en la instrucción siguiente:

s := Copy(', adiós' ,12);

Finalmente, la función Insert crea una cadena más larga mediante lainserción o incrustración, de una cadena dentro de otra, a partir de una deter­minada posición. Así, Inserte I , adi ós ,s,12), literalmente indica que sedebe crear un valor nuevo de tipo string para la variable s incrustrando elvalor " adiós' en la cadena I Hello world! " que es el antiguo valor de s.

Para ilustrar estas ideas, considérese el problema de construir un programaque tenga como entrada una cadena s, y que cuente el número de palabras dela entrada.

Por simplicidad, supongamos que una palabra es una secuencia de caracte­res distintos del blanco, tengan o no significado dentro de la lengua castel1anacomún. Los signos de puntuación, tales como puntos y comas, y así sucesiva-

Page 126: ComputacionI A

Problemas algorítmicos y su solución 119

mente, se consideran elementos de la palabra a la que se añaden. Por ello, cadauna de las cadenas siguientes son palabras:

esosconocer.IMundo! I

Podemo$ escribir las precondiciones y poscondiciones que describen el proble­ma, como sIgue:

{pre: entrada ~ 'c[1J c[2J .,. c[nJ' /\ n >= O 1-. cada c[iJ esun carácter ASCII}{post: entrada ~ vacia /\ sal ida = número de palabras de la entrada}

Un programa que resuelve este problema, utilizando la mayoria de las funcio­nes de la Figura 4.16, se muestra en la Figura 4.17.

program ContadorPalabras;(El programa cuenta el número de palabras de una linea de texto, ymuestra el cómputo resul tanteo Se entiende por palabra cualquiersecuencia de caracteres distintos del blanco, que está precedido porel comienzo del texto o un blanco, y que termina con el final del textoo un blanco)var s: string;

i, npalabras: integer;begin{pre: entrada = 'c[1J c[2J ... c[nJ' 1-. n >= O 1-. cada c[iJ esun carácter ASCII}

{Paso 1. Obtenemos el texto de entrada}writln(' introduci runa linea de texto seguida de <RET>'}Read(s);Writeln;Insert(" ,s,Lenght<s) + 1);

(s = 'c[1J c[2J '" c[nJ c[n + 1J' 1-. c[n + 1J = " /\ n >~ O){Paso 2. Contamos las palabras del texto}

npalabras := O;i := 1;while i <+ Lengh(s) - 1 do

{inv: npalabras~palabrascontadasparas[1... i-1JI-.1<=i<=n+1)beginif (Copy(s, i, 1) <>' ') and (Copy(s, i + 1,1) =' ') then

npalabras :~ npalabras + 1;i:=i+1;

end;(npalabras = palabras contadas en s[1 ... n + 1J)(Paso 3. Se muestra el resultado de la cuenta)

writeln('el número de palabras es', npalabras){post: entrada = vacia 1-. sal ida = número de palabras de la entrada}end. (ContadorPalabras)

Figura 4.17. Programa que cuenta el número de palabrasde una cadena de texto.

Page 127: ComputacionI A

120 Computación l. Lógica, resolución de problemas, algoritmos y programas

En el programa anterior, la variable npa Lab r as indica el número de palabrasen el texto de entrada, mientras que n simboliza su longitud.

El corazón del programa es el bucle whi Le, donde se realiza una compro­bación sobre el final del texto de s. Es decir, el final del texto será sólo cuandoel carácter i -ésimo sea un blanco, y el i + 1-ésimo también. Este convenio severifica para la palabra más a la derecha de s; es decir, la instrucción:

1

Insert<' " s, Length<s) + 1);

Introduce un carácter adicional a la derecha de s. Los casos en los que el valorde entrada de s termine con un carácter distinto del blanco, son eliminadospreviamente a la entrada del bucle que cuenta.

Consideremos la cadena de entrada:

'Whose woods these are 1 thi nk 1 know .•

Tras completarse el paso 1 del programa ContadorPa Labras, la variable squeda con el valor:

5= 'Whose woods these are 1 think 1 know. '

Obsérvese que el blanco adicional se ha insertado dentro de la palabra I know I

de s. Ahora, el bucle de búsqueda del paso 2 comienza con la variable índicei = 1:

s IWhose woods these are 1 thi nk 1 know.1

i

Utilizamos la expresión Copy(s, i, 1) para seleccionar el ;-ésimo ca­rácter de s y Copy(s, i + 1, 1) para seleccionar el i + 1-ésimo. Así, laexpresión combinada:

<CoPY<s, i, 1) <>' ') and <copy<s, i + 1,1) =' ')

que busca si dentro de s el i -ésimo carácter es distinto de blanco, a la vez queel i + 1-ésimo sí lo es. Obsérvese que esta condición es exactamente verdaderacuando se alcanza el final de una palabra, como en el caso en que i = 5:

s IWhose woods these are 1 think 1 know.1

i

Puesto que el contador npaLabras se incrementa sólo al final de cada pala­bra, registra apropiadamente el número de palabras de s en el devenir de idesde la primera posición del texto hasta el siguiente carácter al final del tex­to s. Esta posición se establece utilizando la expresión Lenght (s) - 1.

Page 128: ComputacionI A

Problemas algorítmicos y su solución 121

Así, el ínvaríante del bucle se preserva. A la salida del bucle, el invariante seconvíerte en una expresíón sobre el valor final de npa labras, necesaría paraque se satisfaga la poscondicíón. ¡Níngún otro valor nos satisfaría!

Fínalmente, obsérvese la similitud entre las operaciones de las cadenas y lascorrespondientes de las listas, viendo las Figuras 4.15 y 4.17, respectivamente.Por ejemplo, la función de cadenas Lenght devuelve el número de caracteresde Uljla cadena, mientras que la LenghtL; sta devuelve el número de elemen­tos de una lista. Esta similitud es de gran ayuda cuando queremos recordar elnombre de las funciones, cuando queremos resolver otros problemas algorítmi­cos que utilizan listas y cadenas de caracteres.

4.4.3. Representación del problema de Las Tres-en-Raya

Aunque los tipos numéricos y cadena de caracteres son la base de gran canti­dad de problemas algorítmicos, no sirven para caracterizar aquellos problemasque implican la representación de información gráfica. Este tipo de problemasincluye la visualización y análisis de imágenes de rayos X, fotografías desdesatélites, tableros de ajedrez y otros tipos de tableros de juego, y otros tipos degráficos utilizados habitualmente en gestión comercial y en el cálculo científico.

Para ilustrar este tipo de problemas, consideremos el conocido juego de lastres-en-raya. Supongamos que se nos pide que construyamos un algoritmo quemuestre los movimientos individuales del juego de las tres en raya, reflejandocada movimiento (X o O) en un entramado rectangular de la pantalla de lacomputadora.

Para poder resolver este tipo de problemas necesitamos un nuevo tipo dedatos y el correspondiente conjunto de operaciones asociadas, que permitan aun programa dibujar y realizar transformaciones sobre un array* rectangular,denominado ent ramado de celdas individuales. Cada celda puede rellenarsede una de las cuatro formas siguientes: No (sin rellenar); Sí (rellena en gris); XoO. En la Figura 4.18 se muestra un entramado de 3 x 3 celdas, las cualestienen valores particulares en la que las filas y columnas del entramado se hannumerado de la forma convencional. La celda de la fila 1, columna 2 es una X;la celda en la fila 2, columna 1 es Sí; la celda de la fila 3, columna 3 es O; y lasseis celdas restantes son No.

El número de filas y columnas, así como el tamaño de cada celda, seestablece en el momento en que el programa lo crea. El tamaño de la celda semide en pixels, que son unidades gráficas de la pantalla de la computadora yque no son divisibles en unidades más pequeñas. Cada celda del entramado dela Figura 4.18 es de 20 pixels de ancha y otros 20 de larga. El anclaje de unentramado es la posición en la pantalla de su esquina superior izquierda,cuando se visualiza el entramado. La localización viene dada por un par de

• N. del T.: Aparece aqui por primera vez la palabra inglesa ARRAY. Como ocurriera constring, esta palabra se ha traducido de muchas formas, en mi opinión todas ellas insatisfactorias.Por ello prefiero, tanto en este punto como en ocurrencias posteriores, respetar el término inglés.

Page 129: ComputacionI A

122 Computación l. Lógica, resolución de problemas, algoritmos y programas

Anclaje3

} Tamaño de la celda ~ 20 pixels

~~--i

oFigura 4.18. Un entramado de 3 x 3 celdas y las situaciones de las mismas.

coordenadas xy, teniendo la esquina superior izquierda dc la pantalla las coor­denadas (O, O).

La Figura 4.19 muestra las distintas operaciones que pueden utilizarse paracrcar entramados de varios tamaños y para modificar cl estado de sus celdas.Si declaramos una-variable dc tipo Grid*, podemos utilizar esas opcracionespara realizar transformaciones sobre la variable.

CellOn ~ole~CellOffCellXCe llO

TurnCellOnTurnCellOffTurnCellXTurnCellO

Figura 4.19. Resumen de las operaciones más importantes.

• N. del T.: Seguiremos aquí el mísmo convenio entre tipo y objeto que utilizamos entrecadena y slring.

Page 130: ComputacionI A

Problemas algorítmicos y su solución 123

Sin embargo, al contrario de las listas y cadenas, necesitamos comenzar losprogramas que utilizan estas facilidades gráficas con la instrucción

StartGrids;

y finalizar el programa con la instrucción

StopGrids;

La primera de ellas borra la pantalla y crea dos ventanas, una ventana gráfica ala izquierda y una de texto a la derecha. Todos los entramados que se creen enel programa aparecerán en la ventana gráfica, mientras que los textos, entradasy salidas lo harán en la ventana de texto. Los detalles sobre esas y otrasoperaciones gráficas se explican extensivamente en el manual de laboratorio.Al contrario que las variables de tipo Lista o string, las variables del tipoGr ; d se deben crear y dibujarse en la ventana gráfica antes de asignar valoresa las celdas. Por ejemplo, si queremos crear el entramado d para que tenga 3filas y columnas, con celdas de 20 pixels y anclado en la posición (10, 10) de laventana gráfica, escribiremos:

MakeGrid(d, 3,10,10,20);

Esta instrucción crea el entramado d con la forma y tamaño idénticos alentramado de la Figura 4.18, pero teniendo todas sus celdas en blanco. Elresultado se muestra en la Figura 4.20.Si queremos cambiar de aspecto alguna celda de d, utilizaremos las opera­ciones TurnCeLLOn, TurnCellX o TurnCeL LO. Por ejemplo,

TurnCellX(d, 1, 2)

coloca una X en la celda de la fila 1, columna 2. El resultado de esta acciónaparecerá inmediatamente en la ventana gráfica. Si queremos extender lo ante-

(O, O)

(10, ro;

Ventana gráfica Ventana de texto

(200,2~

Figura 4.20. Aspecto de la pantalla para salida gráfica.

Page 131: ComputacionI A

124 Computación l. Lógica, resolución de problemas, algoritmos y programas

rior de forma que todas las celdas de la columna 2 contengan X, podemosescribir el bucle siguiente:

for i := 1 to GridSize(d) doTurnCeLLX(d, i, 2);

Donde se ha utilizado la variable integer i para recorrer todas las filas delentrainado d, y se ha utilizado la función GridSize para obtener el númerototal de filas y columnas del entramado d.

Finalmente, el grupo de operaciones CeLLOnCd, i, j), CeLLOffCd,i, j), Ce LLX Cd, i, j) y Ce LLO Cd, i, j) pueden utilizarse para cono­cer el estado de la celda de la fila i, columna j del entramado d. Por ejemplo,si nuestro entramado d tuviera el aspecto del de la Figura 4.18, la funciónCeLLOnCd, 1, 3) devolvería el valor faLse míentras que la operacíónCe LLX Cd, 1, 2) devolvería el valor t rue.

Con estas operaciones presentes podemos resolver el problema propuestoal princípio de la sección. El programa de la Figura 4.21 controla el juego deLas Tres-en-Raya, solicitando una alternancia de movímientos a dos jugado­res, y redibuja la situación del juego en la parte gráfica de la pantalla.

program TresEnRaya;uses Grids;

const ancLajex = 20; {coordenadas x e y}ancLajey = 20; {deL tabLero en La pantaLLa}

var tabLero: Grid;movimiento: integer; {movimiento que se debe mostrar}i, j: integer; {fila y columna del movimiento}

begin{pre: una serie de movimientos de las Tres en Raya}

{Paso 1. Inicializamos eL tabLero y eL juego}StartGrids;MakeGrid(tablero, 3, ancLajex, anclajey, 40)movimiento :~ 1;

{Paso 2. Alternancia de movimientos entre x e y}repeat

writeLn(' introduci r fila y columna del siguiente movimiento');writeLn('(O O significa eL finaL deL juego): ');read(i); read(j);i f i > j then

beginif movi mi ento mod 2 ~ 1 then

TurnCeLLX(tabLero, i, j) {Los movimientos impares son de X}else

TurnCe LLO( tabLero, i, j) {Los movimi entos pares son de O}end;movimiento := movimiento + 1;

unti l i = O;

Page 132: ComputacionI A

Problemas algorítmicos V su solución 125

{post: entrada ~ vacía /\sa l í da = una representaci 6n grá f i ca de estos movi mi entos sobreun tablero de las Tres-en-Raya}end. {TresEnRaya}

Figura 4.21. Programa que controla Las Tres-en-Raya.

En el programa, dos jugadores alternan sus movimientos. Cada movimien­to viene dado por un número de fila ;, y uno en columna j, donde losjugadores desean colocar una X o un O. La primera persona que juega es X. Elcontrol del juego y la determinación del ganador se encuentra totalmente enmanos de los jugadores. Cuando un jugador introduce O O (dos ceros), elprograma terminará el juego. Un ejemplo de una secuencia de movimientos yde los tableros resultantes se muestra en la Figura 4.22.

La variable mov; mi ento juega un papel trascendental en la simulación.Almacena el número de jugada que está a punto de realizarse, en cada repeti­ción del bucle del paso 2. Movimientos de números impares (siempre quemov; mi ento mod 2 = 1) el programa coloca una X en la posición (;, j)del tablero. Un número impar de movimiento coloca un O en la posición deltablero.

Introducir fi la y columna del siguiente movimiento(O O significa el final del juego):1 2Introducir fi la y columna del siguiente movimiento(O O significa el final del juego):1 3Introducir fila y columna del siguiente movimiento(O O significa el final del juego):3 2

Figura 4.22. Serie de tres movimientos de Las Tres-en-Raya.

Aunque el programa anterior no sea una implementación excesivamentesatisfactoria del juego de las tres-en-raya, sirve para ilustrar alguna de lasoperaciones gráficas básicas que acompañan al tipo Gr; d, Y su utilizacióncomo ayuda en la visualización de la salida de cierto tipo de problemas algorit­micos.

Existen varias razones por las que este programa no representa una simula­ción totalmente satisfactoria del juego de las tres-en-raya. En primer lugar,obsérvese que el programa permite a un jugador borrar el movimiento delotro, sin más que especificar la misma casilla. Segundo, el programa no analizasi un jugador accidentalmente introduce un número de fila o de columnaerróneo, tal como 4 ó 7. Tercero, el programa no tiene ningún conocimiento dela situación del juego. Es decir, no puede reconocer un movimiento tras el que

Page 133: ComputacionI A

126 Computación l. Lógica, resolución de problemas, algoritmos y programas

gane X o gane Y, o queden empatados (lo que es bastante habitual en estejuego). Cuarto, el programa no está preparado para ser uno de los dos jugado­res, realizando movimientos inteligentes en respuesta a los que realice unapersona jugando con la pieza opuesta.

La primera y segunda de las carencias son fáciles de solucionar. Sin embar­go, la tercera y la cuarta requieren la introducción de fragmentos de algoritmosmás sofisticados, que corresponderían al área de la informática conocida comointeligencia artificial. Es decir, código que permitiera a la computadora simularla inteligencia humana, aunque fuera de forma muy limitada.

Hemos investigado un pequeño número de algoritmos, y las herramientasdel lenguaje Pascal que sirven para su realización en una computadora. Hemosutilizado varios tipos de datos, tales como el integer, real, string, lista y grids; yvarios tipos de instrucciones que incluyen la asignación, la selección condicio­nal, los bucles y la E/S. Tras estudiar estas herramientas y ejemplos, y trashaber trabajado con el manual de laboratorio, el lector habrá conseguidodesarrollar una cierta facilidad en el diseño y escritura de programas pequeñosen Pascal. Con los Ejemplos 4.11 a 4.27 conseguirá algo más de práctica.Recuerde que el aprendizaje del diseño de programas, como el aprender a tocarun instrumento, requiere no sólo estudio teórico, sino mucha práctica. Cuandoejecute sus programas en una computadora, sea paciente e inténtelo de nuevo;recuerde que pocos programas funcionan bien la primera vez. ¡Conseguirámayores éxitos si lo tiene en cuenta!

Ejercicios

4.11. Escribir un programa en Pascal que escriba S1, si la variable K es unentero positivo impar (como 1, 3, 5, ...) Y NO en caso contrario.

4.12. Escribir un programa que asigne a mel valor absoluto de n, sin utilizarla función de Pascal que da el valor absoluto.

4.13. Escribir un programa Pascal que escriba la secuencia de n números, enla que cada término se obtiene de doblar el valor del anterior, siendo nla entrada. (Es decir, cada número en la secuencia es el doble del ante­rior.)

4.14. Repetir el Ejercicio 4.13, pero cambiando el programa para que escribalos n números en orden inverso. (Es decir, cada número es la mitad delanterior.)

4.15. Escribir un programa que lea 25 enteros y que cuente cuántos de ellosson negativos.

4.16. Escribir un programa que lea 100 enteros y que determine y escribacuántos de ellos son divisibles por 5.

Page 134: ComputacionI A

Problemas algorítmicos V su solución 127

4.17. Escribir un fragmento de programa que realice lo siguiente:Poner x a x + A si x es negativo;Poner x a x + A + B si x es cero; oPoner x a x + A + B + e si x es positivo.

¡Cuidado!,4.18. ¿Qué hacen los fragmentos de programa siguientes? Es decir, ¿si in­

trodujera y ejecutase en la computadora este programa, cuál seria lasalida?

a) vark, j, m: integer;n: real;

begink := 4;j := 8;m := 9;n := m div j + k * 1.0 - m div j;writeln ('n= " n)

end;

b) varm, j: integer;

beginm :~ 4;j := 1;whi le (j < m) do

beginj:=j+2;m := m+ 1

end;writeln ('m= ',m, Ij= " j)

end;

e) vark, j: integer;

beginfor k : = 1 to 10 do

beginj := 10 - k;if (j <= 4) then

j := j - 1end;

writeln ('j = " j, 'k= " k)end;

ti) varn, m: integer;

beginn := O;m := 1;

Page 135: ComputacionI A

128 Computación l. Lógica, resolución de problemas, algoritmos y programas

whi le (m <= 101) dobegin

n := n + 1;m := m+ 5

end;writeln ('n= " n)

end;

e) varj, k, m: integer;

begink := O;for j : = 1 to 3 do

for m := 1 to 4 dok :=k+1;

writeln ('k= " k)end;

f) usesLista;

vark: Lista;j: integer;

begink[1] :~ 1;for j := 2 to 4 do

k[j] :~k[j-1]+j;

wri teL i sta (k)end;

g) usesLista;

varm: Lista;j: integer;

beginj := 1;while (j <= 2) do

beginm[j + 2] :~ j;m[3-j] :=j;j :~j+1;

endWriteL i sta (m)

end;

4.19. Trazar la ejecución del programa Po t ene i a para las entradas 5 y - 4,escribiendo los valores de las variables a, b, P e i, antes de que seejecute cada iteración.

4.20. Escribir un programa que cambie a cero todos los valores de una listaque ocupen una posición impar y que sean impares. Es decir, si llama­mos L a la lista, el programa debe examinar L[1 J, y si contiene un

Page 136: ComputacionI A

Problemas algoritmicos y su solución 129

valor impar, poner L [1] a O. Lo mismo debe hacer para L [3] ,L[S], , mientras que deben descartarse los elementos L[2],L[4], .

4.21. Escribir un programa que escriba los 11 primeros números de Fibonac­ci. Los números de Fibonacci son 1, 1, 2, 3, 5, 8, 13, ...

4.22. Escribir un programa que calcule el factorial de un entero n (denotadopor ni). Recuérdese que la definición de n! es:

O! 1n! n x (n - 1)1

4.23. Diseñar y escribir un programa en Pascal que lea un determinado texto,y calcule y escriba el número de ocurrencias de la subcadena I and' .

4.24. Trazar la ejecución del programa ContadorPa Labras de la Figura4.17, mostrando los valores de las variables i y npa Labras durante suejecución, con el texto de entrada siguiente:

'Able was 1 ere 1 saw Elba .•

4.25. Comprobar que el invariante del bucle del programa ContadorPa La­bras es válido para la entrada del Ejercicio 4.24, analizándolo paracada valor de i que provoca un cambio en npa Labras. Por ejemplo,la primera interpretación del bucle ocurrirá cuando i = 6, Yse leería dela forma siguiente:

{npalabras = 1 para 'Able' /\ 1 <= 6 <~ 26)

4.26. Escribir un programa en Pascal que lea un texto y lo invierta y escriba.Es decir, si la entrada del programa es:

'mayo 1992'

la salida del programa debe ser:

'2991 oyam'

4.27. Refinar el programa de las Tres-en-Raya, de forma que prevea elque un jugador coloque una X o una O en una casilla ya ocupada.Cuando esto ocurra, el programa debe avisar al jugador, de forma cor­tés, que debe hacer un movimiento alternativo y registrar un nuevomovimiento.

Page 137: ComputacionI A

130 Computación l. Lógica, resolución de problemas, algoritmos y programas

4.28. Escribir un programa que calcule el coste total del franqueo postal deuna serie de envíos. Debe contener un bucle que lea la cantidad y preciode cada envío y lo acumule al total. Después de que se haya introducidoel último elemento, el programa mostrará el coste total de la operacióny el número total de envíos realizados. El coste total deberá reflejar un5 por 100 de impuestos. Asegúrese de incluir en el propio programa laspre y. poscondiciones.

4.5. RESUMEN

En este capítulo se han introducido las ideas de problema algoritmico y de susolución correspondiente. Se ha hecho especial hincapié en la importancia deespecificar con precisión el problema en forma de precondición y poscondi­ción. También se ha introducido la idea de invariante de un bucle y su utiliza­ción en un programa. Se comenzó con algunos sencillos problemas matemáti­cos, para seguir con problemas de procesamiento de textos y manipulación degráficos, proponiendo y discutiendo su solución en Pascal.

Este capítulo es una base importante para los Capítulos 5 y 6. En el Capí­tulo 5 se introduce la metodología MAPS, que es una metodología sistemáticapara la resolución de problemas algorítmicos, y que puede utilizarse en laresolución de una amplia gama de problemas dentro de esas tres áreas. Lametodología MAPS incide especialmente en la utilización de las ideas funda­mentales introducidas en el Capítulo 4 -precondiciones, poscondiciones, bu­cles, invariantes, listas, cadenas, entramados y sus operaciones asociadas. En elCapítulo 6 se introduce una técnica que permite asegurar la corrección de losprogramas en Pascal que construimos al solucionar problemas algorítmicos.

Pedro Pacheco
Highlight
Page 138: ComputacionI A

CAPíTULO 5RESOLUCiÓN

DE PROBLEMAS ALGORíTMICOS

El conocimiento puede ser de dos tipos. Conocemos algo por nosotros mismos,o conocemos dónde podemos encontrar información sobre ello.

SAMUEL JOHNSON, 1775

En el Capítulo 4 nos concentramos en la construcción de programas relativa­mente cortos, que resolvían problemas bastante sencillos. Enfatizamos en lanecesidad de realizar especificaciones claras, estableciendo los principales pa­sos del algoritmo y trasladando esos pasos a instrucciones Pascal ejecutables.En este proceso nos familiarizamos con los tipos de datos básicos (i nteger,reaL y booLean) y con otros algo más complejos (Listas, strings ygri ds), junto con sus operaciones asociadas. También desarrollamos algunosprogramas sencillos para ilustrar el gran número de problemas con una solu­ción algoritmica. Estos programas son una muestra de la denominada «pro­gramación en pequeña escala».

Sin embargo, para poder resolver problemas algoritmicos más extensos ycomplejos, necesitamos proveernos de un conjunto de técnicas de resolución deproblemas más robustas. Es decir, «la programación en gran escala» requierela utilización de una metodología unificada y robusta que pueda utilizarse demanera fiable en una variada área de aplicaciones. Una Metodología de Reso­lución de Problemas Algorítmicos *, MAPS, se desarrollará e ilustrará en estecapitulo.

5.1. NECESITAMOS UNA METODOLOGíA

Los problemas de la programacíón en gran escala difieren de los de la pequeñaescala en tres aspectos. Primero, un programa que representa una solución a

* N. del T.: En el texto se respelará el acrónimo inglés MAPS (Methodology for Algorith­mic Problem Solvíng), debido a que el autor pretende enfatizar la semejanza de la metodología conel término Map o Mapping, que podría traducirse por correspondencia y que se utiliza amplia­mente en la terminologia informática. Debido a que al traducirlo es imposible capturar esteconcepto, respetamos el acrónimo original.

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 139: ComputacionI A

132 Computación l. Lógica, resolución de problemas, algoritmos V programas

problemas grandes ocupa generalmente más de una página de código en Pas­cal. Segundo, los programas largos tienen, además de su longitud, alguna otracaracterística que los hace más complejos. Tercero, las soluciones para proble­mas más complicados se expresa mejor si se utiliza una sistemática que si seescribe directamente el código que se nos ocurre. Es necesario que los primerospasos describan el problema y que el algoritmo resultante sea fruto de undiseño, fruto de una sistemática paso a paso. De hecho, en muchos casos, lasolución a un problema grande es el resultado del trabajo de un grupo detrabajo numeroso más que de una sola persona.

Las soluciones a los problemas grandes comparten con las de los pequeñostres caracteristicas: legibilidad, eficiencia y corrección. Legibilidad significa quecualquiera que conozca el lenguaje Pascal y el dominio al que pertenece elproblema, es capaz de entender el problema y el programa sin más que leercuidadosamente el programa y los comentarios que le acompañan, indepen­dientemente de lo largo que sea el programa o lo complejo que sea el pro­blema. La eficiencia es deseable porque los recursos informáticos son rela­tivamente costosos, y las aplicaciones deben intentar minimizarlos. Lacorrección significa que todas las ejecuciones del programa deben conducira resultados válidos para cualquier entrada permitida por las especificacionesdel programa.

Estas tres características de los problemas complejos tienden a dotarlos deuna identidad dual. En un extremo, la legibilidad de los programas permiteque éstos constituyan una explicación de la solución a problemas algorítmicospara un lector interesado. En el otro extremo, la eficiencia y fiabilidad de losprogramas les permite ser un mecanismo a través del cual la computadorapuede ser utilizada para resolver problemas. En la construcción de programasutilizando la metodología MAPS, siempre tendremos en mente esta dobleidentidad de los programas. iEl proceso de codificación de un programa enPascal es sólo una parte de la complicada tarea de resolver un problemaalgoritmico!

5.1.1. Generalidades sobre el método MAPS

¿En qué consiste esta metodología de resolución de problemas algorítmicos?La metodología MAPS puede resumírse como la sucesíón de las etapas si­guientes:

• Etapa 1: El diálogo. Comprender el problema. Leer el enunciado delproblema. Hacer preguntas sobre las características de la entrada y lasalida y sus limitaciones, hasta tener completamente claro el problema.

• Etapa 2: Las especificaciones. Construir las especificaciones a partir denuestro conocimiento del enunciado del problema. Escribir pre y poscon­diciones que sean completas y consistentes. Es decir, asegurarse de quelas precondiciones cubren todas (y sólo esas) las posibles entradas, quelas poscondiciones definen la salida para todas las posibles entradas, y

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 140: ComputacionI A

Resolución de problemas algorítmícos 133

que tanto las precondiciones como las poscondiciones son interna y mu­tuamente consistentes.

• Etapa 3: La división. Subdividir, de forma sistemática, el proceso en unacolección de pasos diferentes. Repetir este proceso para cada paso hastaque la subdivisión no tenga sentido. Identificar las relaciones de controlentre los distintos pasos. Es decir, ¿qué paso debe preceder a cuál?, ¿quépasos son parte de otro más complejo?, ¿qué pasos deben repetirse den­tro de un bucle?, y asi sucesivamente. Documentar cada paso escribiendouna breve descripción de sus objetivos. Asignar un nombre apropiado acada nueva variable que incorporemos en cada paso, en función de cuáles su cometido.

• Etapa 4: Definición de abstracciones. Determinar cuáles de los pasos quehemos utilizado habian sido, a su vez, usados en otra situación, recolectarlas rutinas que se utilizaron en esa situación y adaptarlas para reutilizar­las en la situación presente. En muchos casos, esta tarea implica la cons­trucción de una rutina nueva a partir de otras dos, o incluso construiruna nueva para una utilización más especializada.

• Etapa 5: Codificación. Trasladar a Pascal cada paso individual de nuestrasolución, identificando rutinas nuevas y reutilizando aquellas que resul­ten apropiadas para realizar cada paso individual. Conectar cada pasoutilizando la estructura de control apropiada (bucles, invocaciones a pro­cedimientos, secuencias de instrucciones, selecciones condicionales, etc.)de una forma compatible con lo diseñado en el paso 3. Respetar comocomentarios toda la información generada durante el paso 3 para cadapaso individual y las variables correspondientes.

• Etapa 6: Prueba y verificación. Probar o validar de forma sistemática elprograma Pascal, haciéndolo ejecutarse para un conjunto de valores deentradas, que permita explorar todo el rango de valores permitido por lasprecondiciones. Para cada ejecución, comprobar que las salidas satisfacenlas poscondiciones. De forma alternativa, verificar cuando sea apropiadoalguno o todos los pasos del programa, utilizando técnicas de demostra­ción formal.

• Etapa 7: Presentación. Añadir un comentario al comienzo del programapara clarificar su propósito, escribir el nombre de los autores y la fecha, eidentificar la utilización de rutinas que fueron desarrolladas con otropropósito (e incluso por otros programadores). Preparar un listado delprograma, junto con un listado de algunas ejecuciones de prueba.

En este capítulo se ilustran cada una de las etapas de la metodología MAPS.Definamos previamente la idea de rutina, tal y como se considera en la resolu­ción de problemas algorítmicos, junto con el método de Pascal para empaque­tarlas, de forma que éstas sean reutilizables convenientemente.

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 141: ComputacionI A

134 Computación l. Lógica, resolución de problemas, algoritmos y programas

5.2. CONSTRUCCiÓN DE SOFTWARE PARASU REUTILIZACiÓN: LA RUTINA

En el Capítulo 4, y en el manual de laboratorio, se han presentado algunosprocedimientos y programas cortos que realizan tareas especificas. Por ejem­plo, un programa calcula el valor promedio de una lista de enteros, otrocalcula una potencia entera de un número, un tercero localiza el máximo deuna lista, y otros cuentan las palabras de un texto o visualizan una secuenciade jugadas del juego de Las Tres-en-Raya.

Tuvimos que realizar un gran esfuerzo, porque desarrollamos esos proble­mas partiendo de la nada. Es evidente que, para problemas más complejos,tendremos que hacer un esfuerzo mayor si los resolvemos también partiendode la nada. ¿Existe alguna alternativa? Seguramente no queremos seguir resol­viendo problemas si no podemos beneficiarnos de la experiencia adquirida alresolver otros problemas.

Si encontramos un problema que para solucionarlo podemos utilizar partesde otros previamente resueltos, el no hacerlo y desarrollar una solución desdeel principio seria un gran despilfarro de tiempo. Nuestro tiempo y energíaestarán utilizados de una forma más eficaz si somos capaces de reutilizar solu­ciones ya conocidas cuando sean necesarias. La corrección de la solución nuc­va será más fácil de establecer, puesto que la de uno de sus componentes ya lofue anteriormente.

Un algoritmo o parte de él, que parcialmente puede ser rcutilizado, recibeel nombre de rutina. Una buena parte del tiempo empleado en resolver proble­mas se utiliza en identificar rutinas y en reutilizarlas en forma apropiada.

Definición. Una rutina es una parte de un algoritmo que puede reutilizarseen otros contextos de resolución de problemas algorítmicos.

Algunas rutinas son tan comunes que están incluidas en el lenguaje de progra­mación Pascal para utilizarlas en los programas. Estas rutinas incluyen losoperadores numéricos (+, -, *, /, di v y mod); las expresiones aritméticas,las estructuras de control (i f, wh i Le y f o r); los operadores de entrada,salida y asignación (read, wri te y :=) y los operadores de cadenas (copy,pos y Length). Se pucden añadir al lenguaje otras rutinas para manipularlistas (ReadL i s t a, Wri teL i s tal y entramados (Ma keGr i d, Gr i dS i ze yTurnCeLLOn).

Existe una gran variedad de rutinas para diferentes dominios de la resolu­ción de problemas. Varios de ellos se introducirán en este capitulo.

5.2.1. Encapsulamiento de rutinas para la reutilización.Abstracción procedimental

¿Cómo podemos almacenar o encapsular rutinas de forma que puedan serreutilizadas con posterioridad en la resolución de otros problemas? Un método

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 142: ComputacionI A

Resolución de problemas algoritmicos 135

fundamental para construir rutinas en Pascal es la denominada abstracciónprocedimental. Siempre que hacemos que una parte de un programa ya existen­te se convierta en una rutina, primero encontramos (y definimos) su generaliza­ción más apropiada, y después la convertimos, de forma sistemática, en unprocedimiento o función de Pascal. Estúdiese en el manual de laboratorio losdetalles de cómo utilizar y crear los procedimientos y funciones de Pascal antesde continuar con el capítulo.La 'abstracción procedimental es un proceso que consta de tres etapas:1. Nombrar la abstracción. Asignar un nombre que identifique claramen­te el algoritmo que representará el algoritmo resultante.2. Redefinir las precondiciones y poscondiciones del problema, de formaque su solución pueda implementarse como un procedimiento o función.

a) Parametrizar la entrada y la salida. Reemplazar (partes de) «entra­da =» y «salida =» en las especificaciones por el o los parámetrosapropiados, que jueguen el mismo papel que las especificaciones alas que sustituyen en el problema original.

b) Generalizar los tipos. Examinar las entradas, las salidas y los pa­rámetros para determinar si es posible extenderlos o generalizarlos,de forma que la solución construida pueda servir para un conjuntomás amplio de problemas.

3. Implementar la abstracción como un procedimiento o función, bienpartiendo de cero, bien convirtiendo un programa existente para elproblema original.Los pasos 1 y 2 reciben el nombre de especificación de la rutina. Su resultado semuestra en la forma encapsulada siguiente:

Nombre(parámetros>(pre: expresión con las precondiciones de la rutina)(post: expresión con las poscondiciones de la rutina)

El paso 3 unifica las especificaciones con el propio procedimiento o función dePascal, convirtiéndola en una unidad de programa reutilizable.Para ilustrar lo anterior, considérese el problema de la CM que se resolvióen el Capítulo 4. Sus especificaciones se definieron, originalmente, en la Figu­ra 4.3 de la forma siguiente:

(pre: entrada = (Notas" Notas" "."' Notasn > 1\ n > O 1\'Vi E {1, .""' n} :Notas¡ E (O, "."' 4})

(post: entrada =0/\ salida = Sum i E (1, •.. , n):NotasJn}

Supongamos ahora que este programa es lo suficientemente importante paraasignarle la categoría de rutina. Quizá porque estemos trabajando en un pro­blema más complejo que tiene por objetivo calcular qué mes del año tiene elmayor promedio de lluvia caída por día. La entrada de este problema podríaser una serie de listas, una por cada uno de los 12 meses del año, que conten­gan la cantidad de lluvia caída cada día. Cuando nos ponemos a resolver el

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 143: ComputacionI A

136 Computación l. Lógica, resolución de problemas, algoritmos y programas

problema observamos que parte de nuestro viejo programa CM puede utilizar­se para encontrar la solución. ¡Nuestra solución de promediado acaba dealcanzar el rango de rutina!

Pero, antes de reutilizar nuestro programa debemos convertirlo en un pro­cedimiento o función equivalente; es decir, debemos aplicar los tres pasos de laabstracción procedimental a su definición. Para el paso 1, la elección del nom­bre Promed; al,; sta es una buena elección, pues indica con claridad lo quehará la rutina. Para el paso 2a, parametrización de la entrada y la salida,incluimos el parámetro l, en lugar de la entrada, para simbolizar la lista devalores de la que deseamos calcular el promedio, y el parámetro resuL tadoen lugar de la salida, indicando así que el promedio resultante se devolverá alcontexto del programa en que se utilice, en lugar de visualizarse por la panta­lla. Para el paso 3, generalización del tipo, cambiamos nuestra rutina de pro­mediado para que trabaje sobre números en un intervalo apropiado, y no sóloen el rango de O a 4 original.

Por tanto, los pasos 1 y 2 de la abstracción procedimental del problemaCM conducen a las especificaciones revisadas siguientes:

PromedioLista(L):{pre: L= (e" e" """' en) 1\ n:i'a 1\ Vi E {1, """' n}:: e, es un número}{post: n > a 1\ resultado = Sum i E {1, .""' n}: eJn

v n ~ a 1\ resul tado = a}

En el paso 3, en la abstracción procedimental, convertimos el programa CMoriginal en un procedimiento o función de Pascal que satisfaga las especifica­ciones revisadas. La elección entre un procedimiento y una función dependeráde la forma en que se vaya a utilizar la rutina, asi como de ciertas restriccionesque plantea el lenguaje Pascal en la codificación de procedimientos y funcio­nes. Por ejemplo, ¿debe devolver la rutina un único resultado o debe devolvervarios? Si sólo tiene que devolver un resultado se suele preferir una función; silos resultados a devolver son varios, entonces se utilizará un procedimiento. Enotras palabras, ¿invocaremos a la abstracción resultante como si de una ins­trucción separada se tratase (lo que sugiere la codificación de un procedimien­to) o, por el contrario, la invocaremos como una función utilizándola dentrode una expresión aritmética más larga (lo que requiere la codificación de unafunción)?

Consideremos la abstracción Promed; al; s ta que estamos construyen­do. Si la vamos a invocar como una instrucción, debemos codificarla como unprocedimiento Pascal, con todos los parámetros de salida de la cabecera iden­tificados con el prefijo varo (Para más detalles sobre la sintaxis de los procedi­mientos de Pascal, y sobre los parámetros var, consúltese el manual de labora­torio.) Por el contrario, si se va a invocar como una función Promed; ol; sta,debe implementarse como una función de Pascal. En este caso, todos los pará­metros deben incluirse en la cabecera de la definición, excepto el resultado, quese identifica con el propio nombre de la función. En las Figuras 5.1 y 5.2 semuestran ambas alternativas.

Page 144: ComputacionI A

Resolución de problemas algorítmicos 137

p..ocedu..e P..omediolista (l: Lista; va .. resultado: reaL);usesListas;

va ..i, n: integer;sum: rea l;

begin(pre: l= (e" e" o •• , eo ) A n;'O A Vi E (1, ... , ni:: e i es un núme ..o}n :~ lengh\;l i sta(L);if n > O thenbegin

Sum :~ O;i := 1;while i <= n dobegin

Sum := Sum + l[i];i := i + 1

end;..esul tado := Sum/n;

end {if}else

..esul tado := O(post: n>OA resultado~Sum; E {1, "0' nI: eJnv n = O /\ resu l tado = O}

end; (P..omediolista)

Figura 5.1. Abstracción de Promedi ol; sta como un procedimiento.

En ambas abstracciones hay que destacar algunas caracteristicas. Si con­frontamos ambas con el programa original (véase Figura 4.6), a partir del cualhan sido construidas, podemos ver que todas las instrucciones de entrada ysalida han sido sustituidas por referencias a los parámetros l y resultado. Esdecir, la abstracción procedimental delega la tarea de hacer la entrada y lasalida al programa que utiliza la abstracción resultante. De hecho, el programadebe suministrar los argumentos apropiados para que sirvan de entrada alprocedimiento o función, y debe interpretar de forma apropiada la informaciónde salida que éste le proporcione.

Podemos observar también que el fundamento lógico del programa origi­nal se ha preservado. En el procedimiento Promediolista (Figura 5.1), elresultado se asocia con un parámetro varo En el caso de la función Prome­di ol i st a (Figura 5.2), el resultado se asocia con el propio nombre de lafunción. Otras variables declaradas en el programa original (Sum, i y n)adquieren la categoria de variables locales dentro de la abstracción, puesto queahora sólo tienen un interés local exclusivo para el cálculo del promedio.

En la Figura 5.2 se puede observar que el parámetro de salida resultado seha reemplazado por la asignación del promedio resultante al propio nombrede la función. Esta es la forma en que Pascal permite especificar el resultadoque debe devolver una función. En otras palabras, el procedimiento Prome­diolista de la Figura 5.1 y la función Promediolista de la Figura 5.2son idénticos.

Page 145: ComputacionI A

138 Computación l. Lógica, resolución de problemas, algoritmos y programas

function PromedioLista (L: Lista): real;usesListas;

vari, n: integer;sum: rea l;

begin• {pre: L ~ (e" e" •.. , en) /\ n '" O /\ Vi E {1, ••. , n}: /\ n '" 0/\

Vi E {1, ... , ni:: e, es un número}n := LenghtLista(L);if n > O thenbegin

Sum := O;i := 1;while i <= n do

beginSum:=Sum+L[i];i := i + 1

end;PromedioLista := Sum/n;

end {if}else

PromedioLista := O{post: n > O /\ resultado = SUII i E {1, .•. , ni: eJnv n = O /\ resultado = O}

end; {PromediLista}

Figura 5.2. Abstracción de Promedi ol i sta como una función.

Comprobación de la integridad de una abstracción. Antes de utilizar una rutinaque ha sido abstraída en forma de procedimiento o función, debemos asegurar­nos de que hemos realizado correctamente el proceso de abstracción. Comomínimo, esto requiere reestructurar el programa original del que hemos parti­do para realizar la abstracción, y comprobar que el programa sigue satisfacien­do las especificaciones originales con la abstracción realizada. Para el programade la calificación media, esto puede realizarse como se muestra en la Figura 5.3.

prograll calculacM;{esto es un programa que ca lcu la la CM de una seri e de una o máscalificaciones numéricas, cada una de ellas en el rango O.. 4,que se introducirán por el teclado}usesListas;

varNotas: Listas;CM: real;

function PromedioLista (L: Lista): real;{Esta función calcula la media de los valores de una lista)usesListas;

vari, n: integer;sum: real;

Pedro Pacheco
Highlight
Page 146: ComputacionI A

Resolución de problemas algorítmicos 139

begin{pre: L = (e" e" ... , en) /\ n :;" O /\ Vi E {1, ••• , n}: /\ n :;" O /\

Vi E {1, ... , n}:: e; es un número}n := LenghtL ista(L};i1 n > O thenbegin

Sum := O;i := 1;ilhile i <= n do

beginSum :~ Sum + L[i];i := i + 1

end;PromedioLista := Sum/n;

end {;t}else

PromedioLista := O{post: n > O /\ resu l tado = Su. i E {1, ... , n}: e;!n

v n = O /\ resu l tado = O}end; {PromediLista}

beginpre: entrada = (Notas" Notas" ..• , Notasn) /\ n > O /\Vi E {1, ... , n} :Notas; E {O, ... , 4}}

{Paso 1 . Obtenemos la lista de ca l ;ti cac iones}WriteLn ('Introducir la lista de calificaciones:');ReadLista (Notas);

{Nota: Los pasos del 2 al 4 del programa CM original se realizan ahorainvocando a la función PromedioLista}

CM :~ PromedioLista (Notas);

{Paso 5. Se muestra CM}WriteLn ('La CM de esas cal ificaciones es =', CM : 5 : 2)

end{if}{post: entrada ~01\ salida ~ Sum i E {1, .. "' n}: Notas;!n}end. {CalculaCM}

Figura 5.3. Revisión del programa CM utilizando la función Promedi ol i sta.

La revisión de la Figura 5.3 podrá perfectamente haber utilizado el proce­dimiento en lugar de la función. En este caso, la instrucción

CM := PromedioLista (Notas);

debe sustituirse por la invocación equivalente al procedimiento

PromedioLista (Notas, CM)

Lo importante aqui no es si se utiliza un procedimiento o una función, sino laestructura del programa resultante. En concreto, obsérvese que el programa hareducido su responsabilidad a la de obtener la lista de entrada Notas, y avisualizar el promedio de notas (pasos 1 y 5, respectivamente, del diseño origi-

Page 147: ComputacionI A

140 Computación ,. Lógica, resolución de problemas, algoritmos y programas

nal de la Sección 4.1). A su vez, el programa ha transferido la responsabilidadde calcular el promedio a la rutina Promedi oL i s ta recién creada. Parapoder hacer esto, el programa necesita suministrar a la rutina una lista denúmeros (en este caso la variable Notas). El programa tiene que asignar elresultado devuelto por Promedi oLi sta a la variable CM, de forma que suresponsabilidad frente a la salida esté cubierta. El proceso completo puedeobservarse "en la Figura 4.5, donde se ha supuesto que la lista de entrada es<32 1 3).

5.2.2. Identificación de rutinas nuevas y definiciónde sus abstracciones

Una destreza importante que se debe adquirir al resolver problemas algoritmi­cos es la de reconocer rutinas cuando aparecen en contextos de resolución deproblemas diferentes. Una vez identificada la rutina, puede ser abstraída confacilidad en forma de procedimiento o función -¡lo ímportante es reconocer larutina, no su abstracción!

En el Capítulo 4 introdujimos algoritmos para resolver el problema CM,para calcular ab

, y para contar el número de palabras de una cadena de texto.Trate de identificar las rutinas que incluyen. Algunas de ellas saltan a la vista.Por ejemplo, consideremos el cálculo de la suma de los elementos de una listade enteros arbitraria, que está incluido dentro del programa CaLcuLaCM (ytambién dentro de Promedi oL i sta). Calcular la suma de los elementos deuna lista es seguramente una rutina, puesto que puede ser útil en una granvariedad de problemas, tales como el de calcular el balance de un libro decontabilidad o totalizar la recaudación obtenida en un evento deportivo.

¿Cómo sería el aspecto de una rutina que realice este proceso? Podríamos

Entrada(32 1 3)

Salida

2.25

Figura 5.4. Utilización de la función Pramedi al i staen el programa CaLcuLaCM.

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 148: ComputacionI A

Resolución de problemas algorítmicos 141

llamarla Suma Lis t a y escribir sus especificaciones para una lista arbitraria L,como las siguientes:

Suma Lis t a CLl :{pre: L= Ce" e" ... , e,) /\ n;:,O /\ Vi E {1, ... , n):: e, es un número){post: result = Sum i E {1, ... , n): ed

Figuré 5.5. Especificación de la abstracción que suma los elementosde una lista.

El programa Pot ene i a es otro candidato a convertirse en rutina, y pode­mos convertirlo de programa a función con facilidad. De las especificacionesde la Sección 4.4.1, la abstracción procedimental de Potene i a puede definirsecomo en la Figura 5.6:

PotenciaCa, b):{Pre: a y b son enteros /\ Ca '1' O v a = 0/\ b '1' O) /\ Minlnt '" ab

'" Maxlnt){Post: resultado = a b)

Figura 5.6. Especificación de la abstracción de la función Potencia.

Considérese también la posibilidad de encapsular como una rutina el progra­ma CuentaPalabras. De las especificaciones del Capitulo 4, la abstracciónde la Figura 5.7 resulta evidente:

CuentaPalabrasCs):{pre: s ~ 'c[1] c[2] •.. c[n]' /\ n >= O /\ cada c[i] es un carácter ASCII){post: resultado = número de palabras en s)

Figura 5.7. Especificaciones de la abstracción CuentaPaLabras.

Existen otros muchos fragmentos de programas que tienen gran utilidad yque pueden ser convertidos con facilidad en rutinas. Otras cuatro abstraccio­nes simples pueden ser de utilidad en una gran variedad de problemas algorit­micos que procesan listas. Los dos primeros (Figura 5.8) encuentran el lugarque ocupa (índice) el mayor y el menor elemento de los m primeros elementosde una lista L.

MaxListaCL, m):{pre: L = Ce" e" ... , e,) n;:' O /\ cada e i es un número){pos t: n > O /\ Vi E {1, ... , n): e j ;:, e, /\ resu l tado = j v n = O /\resul tado = O)

MinListaCL, m):{pre: L = (e 1 , el' .. _, en) n ~ O 1\ cada e, es un número}{pos t: n > O /\ Vi E {1, ..• , n}: e j '" e i /\ resu l t ado = j v n ~ O /\resul tado = O)

Figura 5.8. Especificación para las abstracciones de MaxL i sta y Mi nL i sta.

Page 149: ComputacionI A

142 Computación ,. Lógica, resolución de problemas, algoritmos y programas

La tercera abstracción intercambia o permuta dos elementos de una lista L Lacuarta busca en una lista L y determina si un determinado valor x está o nodentro de la lista, devolviendo su posición (si es Hue existe). Las especificacio­nes para ambos se pueden ver en la Figura 5.9:

Intercambiar<L, j, k):{pre: L = fe" e 2 , •• _, e j , •• _, e k, •• _, en) 1\ 1 ~ j, k ~ n}{post: L = (e" e" ""., e., "."' e j , ••• , en)}

PosLista(x, Ll:{pre: L = (e" e" ... , en) 1\ X es un número 1\ n ~ O}{post: 3i E {1, .""' n}: X = e, 1\ resultado = i v Vi E {1, ... , n}:

X"" e, 1\ resul tado = O}

Figura 5.9. Especificación de las abstracciones Intercambi a r y PostL i sta.

Estas abstracciones precisan algunos comentarios. Consideremos la lista dela Figura 5.10. Aquí podemos ver que L contiene 12 números, representandocada uno un valor pluviométrico mensual expresado en litros por m 2

• Porejemplo, L[1] representa 2,5 litros por m2 en el mes de enero. L[2] represen­ta 4,4 litros por m2 en el mes de febrero, y así sucesivamente.

Así, la rutina Mi nLis t a ( L, 7) busca el valor pluviométrico mínímo delos siete primeros meses del año, y devuelve el índíce 3. La rutina MaxL i s­ta (L, 12) busca el valor máxímo de los doce de la lista L, devolviendo elvalor 9. PostLista(O.O, L) busca la existencia en L del valor específico0.0, y devuelve el valor 10, que indica su posición en la lista. Finalmente, larutina Intercambiar(L, 2, 9) intercambia o permuta los elementos se­gundo y noveno de la lista L, como se indica mediante los valores subrayadosen la parte baja de la Figura 5.10.

9

~Ci"'''' 12l

~10

( PosLista(O.O,Ll

~'".b;'''''2, 9l

L = (2.5 6.00.3 5.7 2.1 1.3 1.0 5.9 4.40.0 0.3 2.2)

Figura 5.10. Ilustración de las rutinas MaxL i sta, Mi nL i sta,Intercambiar y PosLista.

Page 150: ComputacionI A

Resolución de problemas algorítmicos 143

Veamos la implementación de una de esas rutinas, Ma xLi s t a ( L, m)como un ejercicio adicional de la abstracción procedimental. La Figura 5.11contiene algunas observaciones adicionales sobre una lista arbitraria:

al ir incrementando los valores del indice k entre 1 y m. Para una lista delongitud 1, su valor máximo sólo puede ser el valor e,. Para k = 2, MaxL is­ta (L, 2) es el índice del mayor de los valores e, o e 2, Ysi k = 3, MaxL i s­ta(L, 3) es el índice del mayor entre e 3 Y eM.xList.(L, 2) --es decir, el índicedel mayor de e3 Y(el mayor de e, Ye2). Este razonamiento puede continuarsehasta llegar finalmente a que Ma xLi s t a (L, m) es el índice del mayor de em,

e m -" ••• , e" Y por tanto de toda la lista e m, e m _" ••• , e 2 Y e,. (Loslectores observadores se habrán percatado de que esta expresión es un ejemplode relación de recurrencia, como las que se introdujeron en el Capítulo 2.)

MaxLista(L, k) =1 si k = 1

~k si k> 1 y e k > eMaxListaCL, k - 1)

= MaxL i sta(L, k - 1) si k> 1 y e k ::::;: eJIIIUListaCL, k - 1)

Figura 5.11. Valores de MaxLi sta (L, k) al variar el índice k.

Las consideraciones anteriores sugieren la estrategia de implementacióniterativa siguiente, para calcular el índice j del valor máximo de la sublista deL que contiene m elementos:

j := 1;fOI" k := 2 to m do{invVi E {1, """' k-1}: e[j] >=e[i] /\2<=k<~m+1}

if L[k] > L[j] thenj := k;

Max :=j;

Obsérvese que el invariante refleja nuestro razonamiento informal sobre cómodebe calcularse el valor de MaxLista(L, i) para cada valor de i en elintervalo i, ... , m. Cuando finaliza el bucle, el índice j señalará el elementomayor de la sublista L[1, ... , m]. Esto se deduce de la interpretación delvalor final del invariante

{inv: Vi E {1, ... , m}: e[j] >= e[i]}

puesto que k = m+ 1 al terminar.Hemos terminado prácticamente la codificación del cuerpo de la función

MaxL i sta, si exceptuamos la instrucción condicional, o guarda, que debe

Page 151: ComputacionI A

144 Computación l. Lógica, resolución de problemas, algoritmos y programas

añadirse para comprobar que se satisfacen las precondiciones. Esto se muestraen la Figura 5.12, donde se presenta una abstracción procedimental completade la función MaxL i s tao Obsérvese que la implementación elegida devuelve elvalor O siempre que no se satisface la precondición. Para esta función, estevalor es el equivalente a resultado <<indefinido».

5.2.3. Funciones recursivas: Una alternativa a la repetición

En el Capítulo 2 vimos que las funciones matemáticas pueden definirse utili­zando una relación de recurrencia, o recursivamente. Esta idea ha sido trasla­dada al lenguaje Pascal, de forma que éste nos permite definir funciones recur­sivas. El hecho de que la función MaxL i sta fuera originalmente concebida deforma recursiva no es, por tanto, ninguna traba para su traslación a unafunción de Pascal. Es decir, podemos escribir una función Pascal que incluya larelación de recurrencia original. Este tipo de funciones de Pascal reciben elnombre de funciones recursivas. En la Figura 5.13 puede verse una implementa­ción recursiva de la función MaxLista. La función refleja directamente larelación de recurrencia de la Figura 5.11.

Podemos ver que la relación de recurrencia original se ha codificado enPascal utilizando una serie de instrucciones i f anidadas. El efecto de la itera­ción se consigue en la tercera instrucción i f de la serie, donde los aspectosrecursivos de la función han sido subrayados. La función Ma xLi s ta se invocaa sí misma de forma recurrente, con los argumentos L y m - 1. Así se activanuna serie completa de invocaciones a Ma xLi s t a, para poder determinar:

function MaxLista(L: Lista; m: integer): integer;var j, k: integer;

begin{pre: L = (e" ez, .. _, e lll , •• _, en) 1\ n ~ O /\ cada e i es un número}if (O < n) and (m <= LengthLista(L» then

beginj :~ 1;for k := 2 to m do

{i nv: \li E {1, ... , k - 1 }: e [j] >= e [i] 1\ 2 <= k <~ m+ 1 }if L[k] > L[j] then

j := k;endelse

j := O;MaxLi sta := j;

{pos t: n > O 1\ \1 i E {1, ... , n}: e j ? e, 1\ resu l tado = j vn = O 1\ resul tado = O}

end;

Figura 5.12. Abstracción procedimental de MaxLi sta (L, m).

Page 152: ComputacionI A

Resolución de problemas algorítmicos 145

el índice del elemento mayor de la sublista de L.

function MaxLista(L: Lista; m: integer): integer;begin{pre: L ~ (e" e" ... , e., ""., e o ) /\ n;¡, O /\ cada e, es un número}

if (O<n) and (m<=LengthLista(L» thenif m = 1 then

MaxLi sta := 1else if L[m] > L[MaxLista(L, m- 1 )] then

MaxL i sta := melse

MaxL i sta :~ MaxLi sta (L, m- 1)else

MaxL i sta :~ O;{post: n > O /\ Vi E {1, .""' n}: e j ;¡, e, /\ resul tado = j v

n = O /\ resul tado = O)end;

Figura 5.13. Implementación recursiva de la función MaxLista(L, m).

Para ilustrar la semántica (el signífícado) de las funciones recursivas, su­pongamos que se ínvoca a la funcíón con Ma xLi S t a ( L, 4), siendo L = (2 54 3 8 6). La secuencia de eventos que se producen en el proceso de cálculopara calcular el resultado (que es el índíce 2), se muestra en la Tabla 5.1.

Tabla 5.1. Cálculo de MaxLista(L, 4)

Invocación Sublista Invocación Comparación Devuelvede de L activa em > MaxLista(L, m- 1) el re-

MaxL i sta m sultado

1 4 (2 5 4 3) 2 3>MaxLista(L,3) 22 3 (2 5 4) 3 4> MaxL ista(L, 2) 23 2 (2 5) 4 5>MaxLista(L,1) 24 1 (2) ninguno ninguno 1

Cada ínvocación sucesiva a MaxL i sta, comenzando por la primera, reali­za una comparación entre e m y el valor máxímo de la sublista que contiene unelemento menos, hasta que se realíza una invocación para la que la longitud dela lista es 1. (En este caso, esto ocurre en la cuarta invocación). En ese momen­to se devuelve el resultado, que confirma que e, es siempre el máximo valor dela lista de longitud 1. El resultado se pasa a la invocación 3, por lo queMaxL i s ta compara los valores de e, Yez. Puesto que e z es mayor, la invoca­ción 3 devuelve el índíce 2 a la llamada 2. La invocación 2 compara los valoresde e z Ye 3, determinando que e z es mayor, por lo que pasa a la ínvocación 1 elíndíce 2. Aquí se realiza finalmente la comparación e 4 > ez' devolviéndose elvalor 2 al programa que ínvocó la función.

Una forma gráfica de ver el proceso de recursíón es dibujando una estruc-

Page 153: ComputacionI A

146 Computación l. Lógica, resolución de problemas, algoritmos y programas

tura arborescente que muestre los caminos de invocación, argumentos pasadosy resultados devueltos. En la Figura 5.14 se muestra una estructura de estetipo.

5.2.4. Aprendizaje de rutinas ya existentes: Bibliotecasy características de los lenguajes

Muchas de las rutinas que nos sirven de ayuda en el proceso de resolución deproblemas, o están incluidas en el lenguaje de programación, o han sido desa­rrolladas por otros programadores y son suministradas en forma de bibliotecasy rutinas utilizables. Por ejemplo, hemos utilizado los tipos elementales; n t e­ger y rea L de Pascal, junto con sus operaciones aritméticas y booleanas,como +, -, <, =, y así sucesivamente. También hemos utilizado el tipostring y algunas de las rutinas de utilidad (Length, Pos, Insert, De­Lete, y así sucesivamente). Otras características del lenguaje, como Read oReadLn, tienen una utilidad más general, puesto que pueden aplicarse a ungran variedad de tipos como el integer, reaL y string.

También hemos aprendido cosas sobre los tipos Li s ta y Gr id, conteni­dos en bibliotecas, junto con algunas de sus operaciones (ReadLista,L[i], MakeGrid, y así sucesivamente). Si no se nos hubieran suministradoesas rutinas, tendríamos que haberlas construido de la nada, antes de ponernosa resolver muchos problemas algorítmicos interesantes.

Figura 5.14. Estructura de la invocación recursiva de MaxLista(L, 4>­El número de la invocación está dentro de un círculo; las flechas

descendentes simbolizan argumentos y las ascendentes resultados.

Pedro Pacheco
Highlight
Page 154: ComputacionI A

Resolución de problemas algorítmicos 147

En el manual de laboratorio puede encontrarse una discusión más detalla­da sobre esos tipos y otros de Pascal igualmente útiles, junto con sus rutinasrelacionadas. Las definiciones siguientes de algunas de estas rutinas están escri­tas en el ya familiar estilo de definición procedimental que se introdujo en laSección 5.2.1.

ReadLista(L):{pre: entrada = (e" eu ..• , en) cualquier secuencia A n;. D}{post: ent rada = cua lqui er secuenci a A L = (e" eu ... , en)}

L[ i] :{pre: L= (e" eu •.. , en) A 1 ~i ~n}

{post: e, es un número A resul tado = e i v e, no es un número A

resul tado = D}

Writeln(s" Su •.• , sn):{pre: entrada = cualquier secuencia A Vi E {1, .•• , ni: Si es un número

o una cadena}{post: salida = cualquier secuencia s" s" .... , sn}

poses, t):{pre: t = 't1, t z, • __ , t n

l A S = '$" 52' •• _, Srw l/\ n ~ O}

{post: 5= t,t<+, ... t' ...._1 (1 ~ i ~ i + m- 1 ~ n) es la ocurrencia más a laizquierda de s en t A resultado = i v s no está en t A resultado = D}

Aquí, la noción cua lqui er secuenci a asociada a las rutinas Read­Lis t a y Wr i te l n significan, literalmente, cualquier secuencia de valores deentrada o salida existentes en el momento en que las rutinas son ejecutadas. Enel caso de ReadL i sta, la notación entrada = (e" el' ••. , en) cua l­quier secuencia, significa que existe una lista al principio de la secuenciade entrada, seguida de una secuencia arbitraria de otros posibles valores (quepuede no incluir ninguno). La utilización de cualquier secuencia en la especifi­cación de wr i te l n, significa que coloca la salida a la cola de todas las salidasque se hayan generado antes de la ejecución de la instrucción wr i te l n.

5.2.5. Selección y reutilización de tipos de datos y estructuras

Sabemos ya que es importante para su reutilización la identificación y encap­sulamiento de rutinas. También debemos ejercitarnos en ser cuidadosos cuan­do seleccionamos tipos de datos y estructuras para diferentes problemas conlos que estamos familiarizados.

Hemos trabajado ya con los tipos numéricos básicos (rea le i nteger), eltipo string y con los tipos Lista y Array, que se utilizan para definirestructuras lineales simples. Sabemos, por la experiencia adquirida, que lasoperaciones para el tipo rea l también pueden aplicarse, aunque con algunasrestricciones, al i nteger. Sabemos también que rutinas con nombre similarespara los tipos Lis ta y s tri ng, tienen significados similares. Por ejemplo, larutina Pos (s, t), que devuelve la posición donde aparece por primera vez la

Pedro Pacheco
Highlight
Page 155: ComputacionI A

148 Computación l. Lógica, resolución de problemas, algoritmos V programas

cadena t en la s, es totalmente análoga PosL;sta(x, U, que localiza elelemento x en L. De forma similar, la referencia L[; J, que selecciona el ele­mento ; -ésimo de la lista L, se utiliza en la misma forma para seleccionar el;-ésimo elemento de un array.

Sin embargo, existen sutiles diferencias entre esas alternativas. Por ejemplo,no podemos aplicar operadores aritméticos a valores tipo s t r; ng, aunqueéstos teng;m connotaciones numéricas; instrucciones tales como:

5:=5+'1.5'

(donde s simboliza una variable cadena) son incorrectas. Del mismo modo,podemos leer y almacenar en una lista una colección completa de númerosreales, tanto de un archivo externo como desde el teclado, utilizando la opera­ción ReadL; sta. Sin embargo, no podemos hacer lo mismo si queremos leery almacenar una colección de cadenas. Podemos utilizar un a r rayen lugar deuna lista para almacenar una colección de cadenas, pero carecemos de laflexibilidad para leerlas y almacenarlas si no inventamos y construimos lasrutinas que tengan la capacidad funcional de ReadL; sta. Estas diferenciasestán resumidas en la Figura 5.15, que muestra, en una especie de diagrama deVenn, el solapamiento funcional que existe entre a r rays y Listas. El men­saje básico de estos párrafos es que ninguna estructura de datos ofrece todaslas ventajas de otra sin acarrear algunas desventajas. Esta situación es típica enla informática; los profesionales de la informática se refieren a ella como «elcompromiso y las consecuencias» de tomar una decisión.

Figura 5.15. Diferencias entre l; stas, arrays, cadenas y números.

Pedro Pacheco
Highlight
Page 156: ComputacionI A

Resolución de problemas algoritmicos 149

El tipo cadena es el más básico de los tipos construidos con valores elemen­tales, puesto que puede contener cualquier número de caracteres separados porblancos u otros caracteres ASCII no imprimibles (caracteres de control, talescomo saltos de línea y tabuladores). Así, cualquier carácter es una cadena, perono cualquier cadena es un carácter; por ejemplo, el carácter a es una cadena,pero la cadena Pepe no es un carácter. Continuando con esta línea de razona­miento, c'lda dígito numérico es un carácter, pero un carácter individual notiene por qué ser un dígito numérico. Por ejemplo, el dígito 3 es un carácter,pero el carácter x no es dígito numérico. Igualmente, si colocamos un númeroentre comillas simples tendremos una cadena, pero no toda cadena es unnúmero. Así, I 3 . 5 I es una cadena, pero I 1vá n I no es un número.

5.2.6. Arrays de cadenas de caracteres

Nos gustaría extender la potencia y utilidad del tipo st r; ng incorporándolodentro de la idea de l; sta. Esto nos permitiría aplicar todas las rutinas del; s ta s, que nos son tan familiares, a listas de cadena s de caracteres en lamisma forma en que lo hicimos en el Capítulo 4 con las listas de rea les.Puesto que el tipo string es más general que el de integer o real, esesperable que el tipo lista de s tri ng sea de utilidad en una gama de proble­mas algorítmicos más amplia que el de las listas de rea les.

Desgraciadamente, no podemos extender la idea de lis ta de esta forma.Tenemos que implementar las listas de cadenas utilizando arrays. El tipode elementos de un array puede ser establecido arbitrariamente por el pro­gramador. Supongamos que escribimos una frase como una lista de palabras,separadas entre sí por saltos de línea. La frase:

Iván caminó 3 ki Lómetros hasta eL coLegio a una veLocidad de2,5 ki Lómetros por hora

Podría introducirse por el teclado en la forma siguiente:

Iván RETcami nó RET3 RETki Lómetros REThasta RETeL RETcoLegio RETa RETuna RETveLocidad RETde RET2,5 RETki Lómetros RETpor REThora RETRET

Page 157: ComputacionI A

150 Computación l. Lógica, resolución de problemas, algoritmos y programas

Es posible declarar el tipo de array siguiente, y una variable del mismo quepermite almacenar cada palabra del texto:

type palabra = string[16];ListaStrings = a ....ay[1 .. 100] of palab ..a;

va.. Frase: ListaSt .. ings;LongitudFrase: integer;Apala~ra: palab ..a;

La definición anterior permite manipular frases de 100 palabras o menos,conteniendo cada palabra 16 caracteres o menos (lo que es una suposiciónbastante razonable para el lenguaje cotidiano). La terminación de la frase seseñaliza con dos saltos de línea sucesivos (RET RET).

Si queremos leer una serie de cadenas en la variable f rase e identificar elnúmero de palabras con la variable Long; tudPa labra, debemos diseñar elcódigo que realice esta operación. Es decir, el código siguiente podría ser labase de una abstracción procedimental:

LongitudFrase := o;ReadLn(APalabra)whi le APa lab ..a <> ' , do

beginLongitudFrase := LongitudFrase + 1;Frase[LongitudFrase] := APalabra;ReadLn(APalabra)

end

De forma análoga, es posible implementar inserciones, eliminaciones y búsque­das de palabras aisladas utilízando abstracciones procedurales. De esta forma,podemos manipular listas de palabras de la misma forma que manipulamosl; s tas de rea l es, posibilidad que es de gran utilidad en gran cantidad deaplícaciones.

5.2.7. Tipificación fuerte y coerción

Es complícado cambiar de tipos dentro del lenguaje Pascal, porque el lenguajeobliga a los programadores a hacer distinciones explícitas entre los valores deltipo string, char, real e integer, dependiendo de la rutina concreta(procedimiento o función) utilizada y del contexto sintáctico en el que se utili­za. Esta característica de los lenguajes de programación recibe el nombre detipificación fuerte.

Definición. Un lenguaje de programaclOn es fuertemente-tipificado si eltipo de cada variable y constante que interviene en cada instrucción indivi­dual está restringida explícitamente al tipo de cálculo en el que se utiliza.

Los ejemplos de tipificación fuerte pueden encontrarse en los programas delCapítulo 4:

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 158: ComputacionI A

Resolución de problemas algorítmicos 151

1. La instrucción i := i + 1, del programa Po t en c i a de la Figura 4.14,necesita que i sea una variable numérica --es decir, rea lo i nteger.Si i hubiera sido declarada como un string, la idea de utilizar suvalor en una operación aritmética, como una suma, sería incorrecta,incluso si su valor pudiera ser interpretable como un número (porejemplo, la cadena '2.2 ').

2. La expresión Copy(s, i, 1) <> ", del programa ContarPaLa­bra s de la Figura 4.17, precisa que s sea una cadena y que i sea unentero. La propia Copy debe devolver un valor de tipo s t ri ng, pues­to que el resultado debe ser comparado (utilizando el operador <» conla cadena ' '.

3. La instrucción Tu r n Ce LL( t a b Le ro, i, j), del programa delas Tres-en-Raya de la Figura 4.21, necesita que sus argumentossean de los tipos grid, integer e integer, respectivamente.

Supongamos que queremos reinterpretar un valor de un tipo como valorde otro diferente -por ejemplo, interpretar la cadena '2.5 I como el númeroreal 2,5--. Para hacer esto en un lenguaje fuertemente tipificado como Pascal,necesitamos utilizar una rutina especifica que convierta el valor de tipo stringen uno de tipo real. Este es el papel de la rutina de Pascal Val (véase Sección5.2.6). La utilización de una rutina de este tipo recibe el nombre de coerción. Lacoerción en la dirección opuesta le permite la función s t r. Las rutinas siguien­tes están definidas en Turbo Pascal para permitir la coerción entre reales ycadenas:

valCs, r, código){pre: s es una cadena){post: r = valor real equivalente a s 1\ código = O si la coerciónse rea liza con éx ito

strCr, s);{pre: r es un número real J{post: s es la cadena equivalente a r)

Pascal realiza la coerción directa entre reales y enteros. Los enteros nonecesitan ser convertidos explícitamente a los reales equivalentes, puesto que sepueden considerar un subconjunto de ellos. Por ejemplo, el entero 1 se inter­preta siempre que sea necesario como el real 1 • O. Las rutinas siguientes con­vierten un número real en entero, bien redondeándolo al entero más próximo,bien truncándolo, respectivamente.

roundCx);{pre: x es un número rea l ){post: resultado=lx+O.5J}

trunc(x) :{pre: x es un número rea l)(post: resultado = lxJ}

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 159: ComputacionI A

152 Computación l. Lógica, resolución de problemas, algoritmos y programas

Por tanto, si queremos tratar el i-ésimo elemento de una lista L como un entero,debemos convertirlo explícitamente utilizando una de las rutinas round otrunco Por ejemplo, la instrucción siguiente asigna la parte entera (ignorandola parte decimal) del i -ésimo elemento de L a la variable in t ege r j.

j :~ truncCL[i]);,

¿Por qué son tan necesarias y útiles la tipificación fuerte y la coerción?Existen varias razones. Primero, los lenguajes fuertemente tipificados suelen sermás efectivos que los débilmente tipificados como vehículos de enseñanza delos principios de la programación, por el simple hecho de que sus compiladoresdetectan un rango de errores más amplio, y sugieren la forma de corregirlosantes de que se produzca la ejecución del programa. En algunas ocasiones, laslistas incluyen elementos de distintos tipos, por lo que el programa debe identi­ficar tanto los tipos como los valores de cada elemento. La lista siguienteincluye algunos datos en los que cadenas y reales se alternan en una serie noordenada cronológicamente de valores pluviométricos de los meses del año.Las listas como esta, en que cada valor numérico está precedido inmediata­mente por un nombre descriptivo, reciben el nombre de listas con atributos.

L = (Enero 2,5Septi embre 6,0Febrero 4,4Mayo 2,1Junio 1,3Novi embre 0,3Diciembre 2,2Julio 5,9Marzo 0,3Abril 5,7Agosto 1,0Octubre 0,0)

Ejercicios

5.1. Describir qué es lo que hacen los programas siguientes:

a) function nooz (L: lista) : integer;val'

i: i nteger;beginnooz := O;for i := 1 to LengthLista(L) do

if L[i] =0,0 thennooz := nooz + 1;

end;

Pedro Pacheco
Highlight
Page 160: ComputacionI A

Resolución de problemas algorítmicos 153

b) program fn;var

k: integer;function nd (m: integer>: integer;

varn: integer;

beginnd := O;n := m;while n >= 1 do

beginn := n div 10;nd := nd + 1

endend;

beginwhi le not eof do

beginreadln (k>;writeln ('ans = " nd(k»

endend.

5.2. Implementar la rutina SumL; s ta, definida en la Figura 5.5, como unafunción de Pascal. Probar que la función puede reutilizarse para conse­guir una implementación alternativa del procedimiento Promed i 0­

Lis t a, diferente a la de la Figura 5.1.

5.3. Construir una función, a la que llamaremos MaxFactor, que calculeel máximo factor de un entero n, que sea menor que el propio n (porejemplo, MaxFactor(100) = 50, MaxFactor(15) = 5, Y Max­Factor(13) = 1).

5.4. Supongamos que A, B Y C representan la longitud de los lados de untriángulo. Construir una función que devuelva t rue si A, B YC son loslados de un triángulo rectángulo.

5.5. ¿En qué condiciones puede convertirse un procedimiento en una fun­ción equivalente? ¿En qué condiciones puede realizarse la operacióninversa? Razonar la respuesta.

5.6. Convertir el programa factorial del Ejercicio 4.22 en una función.

5.7. Implementar como un procedimiento de Pascal la abstracción Con­tarPalabraCs) de la Figura 5.7. Comprobar su integridad reutili­zándola para resolver el programa original que contaba palabras delCapítulo 4 (véase Figura 4.17).

Page 161: ComputacionI A

154 Computación ,. Lógica, resolución de problemas, algoritmos y programas

5.8. Ilustrar el comportamiento de la implementación recursiva de Max­Lista(L, m) (Figura 5.8), mostrando la secuencia de invocaciones yresultados devueltos, cuando L = (6 5 4 3 2 1) Y m = 6. ¿Existealguna reducción en el número de invocaciones que son precisas cuandoel máximo valor ocupar el primer lugar de la lista? Razonarlo.

5.9. Reesdribir la función siguiente, pero reemplazando el bucle far poruno whi Le equivalente; es decir, quc conduzca al mismo resultado.Escribir pre y poscondiciones que describan el resultado. ¿En qué medi­da es esta función similar a la operación Mi nL i sta (Figura 5.8)?

type ArrayLista = array[1 .. 255] of real;function IndiceDelMenor<UnArray: ArrayLista; n: integer):integer;

(devuelve el indice del menor de los elementos de un array delongi tud n}var IndiceDelMenorPorAhora: integer;

beginIndi ceDelMenorPorAhora := 1;for i ;= 2 to n do

i f UnArray[i] < UnArray[Indi ceDelMenorPorAhora] thenIndi ceDe lMenorPorAhora :~ i;

Indi ceDe lMenor := Indi ceDe lMenorPorAhora;end;

5.10. Escribir una función recursiva SumL i sta (L, n) que devuelva la sumade los n primeros elementos de la lista L.

5.11. a) Escribir la función recursiva Fib(n) que calcule para el entero n eln-ésimo número de Fibonacci, que se define de la forma siguiente:

Fib(n) o1

Fib(n - 1) + Fib(n

parapara

2) para

n On 1

n > 1

b) Dibujar la representación gráfica de la cadena de invocacionescuando se invoca con F i b (4).

e) Reescribir la función, pero sin utilizar recurrencias; es decir, utili­zando un bucle en lugar de llamadas recursivas.

5.12. a) Describir en castellano qué hace la función siguiente.

function MyFun (n: integer): integer;begin

i f n ~ O thenMyFun := O

else if n mod 2 = O then

Page 162: ComputacionI A

Resolución de problemas algorítmicos 155

MyFun := n + MyFun<n - 1)else

MyFun :~ MyFun<n - 1)end;

b) Escribir las pre y poscondiciones de la función My Fun.

5.13. Utillzando una linea de razonamiento similar a la utilizada para imple­mentar MaxL i sta (L, m), desarrollar una implementación de la fun­ción Mi n Lis t a definida en la Sección 5.2.2. Si la implementación con­tiene un bucle, incluir la descripción del invariante del bucle.

5.14. Realizar la abstracción procedimental de la rutina PosLista(x, U,definida en la Sección 5.2.2, y escribir en Pascal una función no recursi­va de la abstracción.

5.15. La rutina PosL i sta (x, U es muy útil cuando queremos determinarsi una lista tiene elementos repetidos. Escribir un programa en Pascalque, para una lista arbitraria de númcros L, utilice PosL i s ta paraayudarnos a descubrir y escribir los números que aparezcan más de unavez. Por ejemplo, la lista L = (1 2 3 5 4 1 5 1 ) hará que el programaescriba las duplicidades siguientes:

15

Describir un problema algorítmico de la vida cotidiana en que sea deutilidad una rutina que localice duplicidades.

5.16. Escribir una implementación recursiva de la función PosL i sta.

5.17. Escribir la función Primos Re La t i vos que tenga dos enteros n y mcomo argumentos, y devuelva el valor booleano t rue, si y sólo si m y nno tienen ningún divisor común más que 1. Por ejemplo,

PrimosRelativos<B, 9) = truePrimosRelativos<B, 10) ~ false

puesto que 8 y 10 tiene un divisor común que es 2.

5.18. Escribir una función que devuelva el valor t r ue si el primer elementode una Lis ta es mayor que el resto de elementos. La función se llama­rá EsMayor y tendrá un solo parámetro, que designará a la lista. Escri­bir un programa de prueba que invoque a la función para establecer sitrabaja correctamente.

Page 163: ComputacionI A

156 Computación l. Lógica, resolución de problemas, algoritmos y programas

5.19. Diseñar y escribir en Pascal una función que examine los n elementosde una lista y devuelva t rue si los elementos están ordenados en ordendecreciente, y fa l se en caso contrario. La función se llamará Pruebay tiene que tener un parámetro para el nombre de la lis ta, y otrospara el número de elementos n que deben examinarse. Escribir un pro­grama de prueba que invoque a la función para establecer si trabajacorrectamente.

5.3. RESOLUCIÓN DE UN PROBLEMA UTILIZANDOLA METODOLOGíA MAPS

Ya estamos en condiciones de utilizar nuestro método de resolución de proble­mas (MAPS) y utilizarlo en un caso concreto, desde el principio hasta el final.Durante todo el proceso enfatizaremos la importacia de identificar y reutilizarrutinas en una forma creativa. Una de las características destacables de MAPSes que no sólo sirve como guía en la resolución de problemas particulares, sinoque en este proceso se van creando rutinas que el programador podrá reutili­zar en la resolución de otros problemas más complejos.

5.3.1. El diálogo

El problema que vamos a resolver es el de construír un algoritmo que tengacomo entrada una lista de valores pluviométricos, y escriba los meses cuyosvalores pluviométricos estén por debajo de la media, el valor pluviométricomás alto y más bajo de cada mes, y el mes que dio el valor pluviométrico másalto.

Nuestra primera reacción ante la explicación anterior es que es muy vaga.Es decir, se han omitido muchos detalles. Necesitamos mucha más informaciónantes de pasar a la etapa siguiente en la resolución del problema. Esto es muytípico en la resolución de problemas; no es buen proceder el admitir especifica­ciones ambiguas y realizar preguntas que dejen sin clarificar algunos detalles.Los resolutores de problemas inteligentes preguntan primero sobre las cuestio­nes que necesiten ser clarificadas, antes de proceder a la búsqueda de unasolución. Asi, debemos tener un diálogo con la persona que nos presenta elproblema, hasta que consigamos tener un conocimiento preciso del mismo.Para el problema que nos ocupa, algunas cosas que deberíamos preguntarpodrían ser las siguientes:

1. ¿Cómo se nos presentará la entrada? ¿Cronológicamente por meses?¿Por valores pluviométricos? ¿Consistirá la entrada en una o dos lis­tas? ¿Estarán los meses explícitamente representados en la entrada, o sepresentará las lecturas únicamente organizadas en orden cronológico?

2. ¿Cuál es un valor válido de pluviometría? Es decir, un valor pluviomé­trico ¿puede ser cualquier número real no negativo?, ¿existe un valormáximo para las lecturas?

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 164: ComputacionI A

Resolución de problemas algorítmicos 157

3. En la salida, ¿deben aparecer los meses con pluviometria inferior alpromedio, en orden cronológico, en orden de indices pluviométricosrelativos o, simplemente, en el mismo orden en que aparecieron laslecturas en la entrada? ¿Es necesario escribir el valor medio del indicepluviométrico?

4. ¿Puede ocurrir que más de un mes tengan el valor pluviométrico másalto? En ese caso, ¿debe mostrar el algoritmo el nombre de todos esosrbeses?

Tratando de clarificar lo anterior, suele ser conveniente dar una muestra de laentrada y de la salida correspondiente del problema; ¡una imagen vale más quemil palabras! Los ejemplos sirven para resolver de forma visual muchas de laspreguntas anteriores, e incluso nos proporcionan pistas sobre cómo debemosresolver el problema. En la Figura 5.16, la entrada se presenta en una listasencilla, y el programa debe distinguir entre nombre de meses (entradas de lalista con índices impares 1, 3, 5, ...) Yvalores pluviométricos (entradas de la listacon índices pares 2, 4, 6, ...).

ENTRADA

(Enero 2,5Febrero 4,4Marzo 0,3Abril 5,7Mayo 2,1Junio 1,3Julio 5,9Agosto 1,0Septiembre 6,0Octubre 0,0Novi embre 0,3Di c i embre 2,2)

SALIDA

ESTADISTICAS PLUVIOMETRICASmedi a = 2,64máxima = 6,0minima = 0,0

Meses por debajo de la media:EneroMarzoMayoJunioAgostoOctubreNoviembreDiciembre

Mes(es) máxima:Septiembre

Figura 5.16. Ejemplo de entrada y salida para el problemade la pluviometría.

Sin embargo, la entrada y salida para este problema pueden presentarseperfectamente de otras maneras. Dos alternativas razonables se muestran en laFigura 5.17. En una de las alternativas, la entrada se suministra en dos listas enlugar de en una; en la otra, la entrada se presenta sin los nombres de los meses.En este caso, el programa debe generar los nombres de los doce meses ysuponer que los valores de pluviometría están suministrados en orden cronoló­gico --es decir, la primera entrada es el valor de enero, la segunda el defebrero, y así sucesivamente.

Pedro Pacheco
Highlight
Page 165: ComputacionI A

158 Computación ,. Lógica, resolución de problemas, algoritmos y programas

CEnero, FebreroMarzo, Abri LMayo, JunioJuL i o, AgostoSeptiembre, OctubreNoviembre, Diciembre)

2.5 ~.4

0.3 5.72.1 1.35.9 1.06.0 0.00.3 2.2)

a)

C2.5 4.40.3 5.72.1 1.35.9 1.06.0 0.00.3 2.2)

b)

Figura 5.17. Dos representaciones alternativas de la entrada para el problemade la pluviometría. al Dos listas de entrada. b) La lista de los valores pluviomé­

tricos como única entrada.

5.3.2. Las especificaciones

Supongamos que la Figura 5.17b muestra la organización de la entrada queespera el programa, y la Figura 5.16 la de la salida. Podemos entonces cons­truir de una forma más precisa las especificaciones del programa, es decir, lasprecondiciones y postcondiciones. Estas especificaciones servirán para clarifi­car los detalles de la solución al problema, que desarrollaremos en pasos si­guientes. La precondición para el problema de la pluviometría puede expresar­se de la forma siguíente:

{pre: entrada = Ce" e" .•. , e,2 ) /\ Vi E {1, ... ,12) e i es eL vaLorpLuviométrico deL i-ésimo mes deL año)

Así, si se suministrase al programa la entrada particular de la Figura 5.l7b, sesatisfaría esta precondición; el programa asignaría a e z el valor 4.4 Its/m 2 (elvalor pluviométríco de febrero), y así sucesivamente. Sin embargo, el lector sepercatará de que, si la entrada se suministrase en una de las otras formasalternativas, no se satisfaria la precondición.

La poscondición para este problema puede definirse de la forma siguiente:

{post: entrada =0/\ saLida = ESTADIsnCAS PLUVIOMETRICASmedia = Sum i E {1, ,12): e i /12má xi ma ~ Max i E {1, , 12): e i

minima = Min i E {1, ,12): e iMeses por debajo de La media:

{m;: e; < Su.i E {1, ... ,12): e,l12)MesCes) ma><ima:

[mi: e j = Max iE (1, ... ,12): e i /\ 1o;;jo;;12))

Pedro Pacheco
Highlight
Page 166: ComputacionI A

Resolución de problemas algoritmicos 159

En este caso, la especificación de entrada describe la forma general y la esenciade la misma, y la especificación de salida la relación que deben guardar entra­da y salida. Por ejemplo, podemos ver que son necesarias dos listas -una lista(mi' ml' ..., miz) con los doce meses del año y una lista con los doce valorespluviométricos. A la vista de esto, debe existir algún tipo de paralelismo entreambas listas. (Obsérvese que, aunque la lista de meses no se suministra comoentrada, deb~ ser generada de alguna forma por el programa en forma de unarray de doce posiciones). Es decir, el hecho de que m2 = Febrero y que e 2 =

4,4 significa que el valor pluviométrico de febrero es 4,4 lts/m2.

Por tanto, la solución al problema puede describirse en términos de aque­llos meses cuyo valor pluviométrico guarda alguna relación con el máximo,mínimo y valor pluviométrico medio. En este caso, la notación de la lógica esespecialmente útil, pues permite expresar las especificaciones de forma breve yprecisa. Una descripción en castellano de las mismas entradas y salidas podriano estar escrita con la misma precisión y brevedad.

5.3.3. La partición

Muchos objetivos o pasos de este problema son evidentes, si nos ponemosa pensar sobre el problema y sus especificaciones. Inicialmente, nuestra so­lución debe generar la lista con los nombres de los meses y obtener de laentrada la lista de valores pluviométricos. También nuestra solución necesitacalcular el valor medio, el máximo y mínimo de los valores pluviométricos.Necesitará escribir Jos nombres de aquellos meses cuyo valor pluviométricoesté por debajo de la media, así como el(los) mes(es) que tengan el máximode valor pluviométrico.

La solución a este problema puede ser dividida, inicialmente, en las cuatrorutinas y cinco elementos de datos que se muestran en la Figura 5.18. Hemoshecho dos cosas importantes en esta etapa inicial del proceso de partición;hemos identificado las principales rutinas que serán necesarias, y hemos asig­nado nombre a las listas principales (meses y pLuv;ometr;as) y a lasvariables principales PLuv;ometr;aProm, MaxPLuv;ometr;a y M;n­PLuv;ometria) que precisa la solución.

Recapacitemos ahora acerca de dos nuevos elementos del proceso de reso­lución de problemas -la relación secuencial entre rutinas y la posibilidad deutilizar rutinas ya conocidas como ayuda para la construcción de la solución alproblema que nos ocupa-o Podemos determinar informalmente el secuencia­miento de los eventos descritos en la Figura 5.18 (simplemente pensando enqué debe ocurrir primero, qué segundo, etc.), o formalmente (escribiendo prey poscondiciones para cada rutina que hayamos identificado, u ordenarlaslógicamente según el contexto que imponen las especificaciones del proble­ma principal). Un análisis informal conduce al orden inicial descrito en laFigura 5.19, junto con las especificaciones del programa original, ocupando sulugar.

Pedro Pacheco
Highlight
Page 167: ComputacionI A

160 Computación l. Lógica, resolución de problemas, algoritmos y programas

Rutinas

Inicializarlista de meses

y pluviometrías

Mostrar pluviometríapromedio. máxima

y mínima

Elementos de datos

Mostrar mesespor debajo

del promedio

Mostrar mes(es)con pluviometría

más alta

MesesPluviometriasPluviometriaPormMaxPluviometriaMinPluviometria

Un array de doce nombre de meses.Una lista de doce lecturas de valores pluviométricos.El valor medio de las lecturas.El valor máximo de pluviometría de los doce meses.El valor mínimo de pluviometría de los doce meses.

Figura 5.18. Partición en rutinas y elementos de datos para el problemade la pluviometría.

{pre: entrada = (e" e" " .. , e,.) /\ Vi E {1, """' 12) e, es el valorpluviométrico del i-ésimo mes del año}

Paso 1. Inicializar lista de meses y pluviometrías

Paso 2. Mostrar pluviometría promedio, máxima y mínima

Paso 3. Mostrar meses por debajo del promedio

Paso 4. Mostrar el(los) mes(es) con pluviometría más alta

{post: entrada =0/\ salida = ESTAOfSnCAS PLUVIOMIOTRICASmedia = Sum i E {1, , 12): e;l12máxima = Max i E {1, , 12): e,minima = Min i E {1, , 12): e,

Meses por debajo de la media:{m j : e j < SUII i E {1, ... , 12): e ;l12}

Mes(es) máxima:(m;: e; ~ Sum i E (1, """' 12): e;l12}

Figura 5.19. Orden inicial y especificaciones para el problemade los valores pluviométricos.

Page 168: ComputacionI A

Resolución de problemas algorítmicos 161

Podemos observar que las cuatro rutinas deben colocarse en este ordenpara que la poscondición quede satisfecha. En concreto, la lectura de los valo­res pluviométricos debe preceder a todos los demás pasos. Por si mismo, elprimer paso provoca la satisfacción de la especificación entrada = 0 de laposcondición. Del mismo modo, a continuación debe calcularse y escribirse elvalor promedio por dos razones: Primero, el promedio es necesario comoentrada (calilla precondición) del paso 3, donde necesitamos calcular y visuali­zar los meses cuya pluviométria está por debajo del promedio, y del paso 4,donde encontramos y visualizamos el(los) mes(es) con máximo valor pluviomé­trico. Segundo, la poscondición del problema exige que los valores promedio,máximo y mínimo de pluviometría deben mostrarse antes de que se produzcanlas salidas de los pasos 3 y 4. Finalmente, el paso 3 debe preceder al 4, puestoque sus salidas respectivas deben realizarse en este orden según las poscondi­ciones del problema.

Ejercicios

5.20. Supóngase que se utiliza la metodología MAPS para diseñar un progra­ma que lea un número expresado en cifras romanas, y que muestre suvalor en números arábigos. En las etapas de diálogo y especificación, seha establecido que la entrada será una cadena de letras mayúsculas delconjunto (1, V, X, L, C, D, M). Recuerde que los valores de esos digitosromanos son 1, S, 10, SO, 100, SOO, 1000, respectivamente. Se ha decididotambién que los digitos en la entrada estarán en orden no creciente devalores; es decir, el número arábigo 4 se escribirá como el numeral UU(en lugar de IV). Con estas hipótesis, escribir detalladamente las especifi­caciones y realizar la fase de partición de la metodología MAPS.

5.21. Escribir la salida que aparecería si mezclamos los dos bucles for de lospasos 3 y 4, del problema de la pluviometría, en un solo bucle for quecontenga las dos selecciones ; f, ante la entrada ejemplo de la Figu­ra S.17. Es decir, suponer que se mezclan los pasos 3 y 4 de la formasiguiente:

WriteLn('Meses por debajo de La media');WriteLn( 'Mes(es) máxima:');for i := 1 to LenghtLista(Pluviometrías) then

beginif Pluviometrias[i] < PLuvíometriaProm then

WriteLn(' " Meses[i]);if Pluvíometrías[i] = PluviometríaProm then

WriteLn(' " Meses[i]);end;

5.22. Escribir un invariante para el bucle del paso 3 del problema de lapluviometría.

Page 169: ComputacionI A

162 Computación ,. Lógica, resolución de problemas, algoritmos y programas

5.4. DEFINICiÓN DE ABSTRACCIONES: UNIFICACiÓNDE RUTINAS VIEJAS CON IDEAS NUEVAS

Hemos definido y desarrollado la solución al problema de la pluviometría,hasta un punto en que es posible evaluar el esfuerzo necesario para solucionarcada una de sus partes. Es decir, debemos decidir qué pasos deben ser subdivi­didos en subpasQs. En nuestro ejemplo, los pasos 1 y 2 pueden ser subdivididosnuevamente para clarificar sus objetivos individuales.

Estas nuevas subdivisiones pueden verse en la Figura 5.20. En la figurapodemos ver que se ha subdividido el paso 1 en dos subpasos 1.1 y 1.2, queasignan la lista de nombre de meses y leen la lista de pluviometrías, respectiva­mente. El paso 3 tiene tres componentes: el paso 2.1 calcula y escribe el valorpluviométrico medio; el paso 2.2 calcula y escribe el valor pluviométrico máxi­mo; y el paso 2.3 calcula y escribe el valor pluviométrico mínimo. Obsérveseque los subpasos diseñados se han secuenciado apropiadamente, con objeto desatisfacer el orden de las dos listas, y el que especifica la poscondición para lassalidas. Este cuidado, que puede parecer excesivo para un problema tan simple,se hace más importante cuanto más complejo es el problema a resolver.

Paso 1. Inicializar lista de meses y pluviometría

I Paso 1.1. Asignar lista de meses IL

Paso 1.2. Leer lista de valores pluviométricos

Paso 2. Mostrar pluviometría promedio, máxima y minima

Paso 2.1. Calcular y mostrar pluviometria media

Paso 2.2. Calcular y mostrar pluviometría máxima

Paso 2.3. Calcular y mostrar pluviometría mínima

Figura 5.20. Partición adicional de los pasos 1 y 2 del problemade la pluviometría.

Hemos de continuar subdividiendo y secuenciando los pasos individualeshasta que cada subpaso sea reconocible con claridad como una rutina, searesoluble mediante la combinación de otras existentes (conocidas), o pueda serresuelto directamente creando una rutina nueva. Podemos ver que es necesariodesarrollar una rutina nueva para el paso 1.1. Podemos utilizar la rutina

Pedro Pacheco
Highlight
Page 170: ComputacionI A

Resolución de problemas algorítmicos 163

ReadLista para el paso 1.2. Podemos combinar dos rutinas, Promed;o­Lista y WriteLn para resolver el paso 2.1 (el cálculo del promedio y lavisualización del resultado son dos acciones separadas, y por tanto debenrealizarlas rutinas diferentes). De forma similar, podemos combinar las rutinasMaxL; sta y Wri teLn para el paso 2.2, y las rutinas Mi nL i sta y Wr; teLnpara el paso 2.3.

Ni el paso 3 ni el 4 parecen resolubles mediante la aplicación directa ni lacombinación de rutinas. No hemos visto hasta ahora ninguna rutina que re­suelva directamente problemas como éste, y tenemos que crear una soluciónnueva para cada uno de los casos. Sin embargo, en la mayoría de las situacionesde resolución de problemas algoritmicos, los diseñadores de software empleanmás tiempo combinando o reutilizando rutinas que creándolas nuevas desde elprincipio. Es decir, el proceso de resolución de problemas algorítmicos tiende acumplir la regla «90 por 100 de transpiración y 10 por 100 de inspiración».Apliquemos la <<transpiración» (Sección 5.4.1) y la inspiración (Sección 5.4.2).

5.4.1. Reutilización de rutinas

Como hemos dividido suficientemente el problema original, de forma que po­demos tratar cada parte de forma independiente, debemos explorar la presen­cia de rutinas conocidas o «viejas» entre los pasos individuales. Por cierto,algunas rutinas que son conocidas para unos resolutores de problemas, sondesconocidas para otros. Por ello, no debe descorazonarse si desconoce algu­nas rutinas con las que otros parecen estar muy familiarizados. Estamos apren­diendo un lenguaje nuevo, y nuestro vocabulario crecerá con la experiencia.

Existen cuatro mecanismos que podemos utilizar para adaptar o reutilizarrutinas ya existentes para propósitos nuevos: empalmándolas, anidándolas,adaptándolas y mezclándolas *.

Empalmado. Es el método más sencillo de crear rutinas nuevas. Si Rl Y R2son dos rutinas ya existentes, el empalmado de ambas crea una rutina nueva R,que se compone de R1 seguida secuencialmente de R2. Por ejemplo, en elproblema de la pluviometría. Las cuatro rutinas (pasos del 1 al 4) son empal­madas para formar una rutina nueva como es la solución al problema. De lamisma forma, las rutinas PromedioLista y WriteLn se empalman paraconstruir la solución al paso 2.1, como se ilustra en la Figura 5.21.

Anidamiento. También se puede construir una rutina nueva anidando unarutina R1 ya existente de otra R2. El anidamiento se produce cuando utiliza­mos una rutina como argumento de la invocación a un procedimiento, ocuando la colocamos dentro de una instrucción condicional o dentro de unbucle. Esto sc ilustra en la figura 5.22, donde el cálculo del promedio depluviometría, ha sido anidado dentro del propio proceso de visualización del

* E. SOLOWA v: {<Lcarning to program: Learning to construct rncchanisms and cxplana­tions". Curnrnunicatians al the ACM (septiembre 1986), 29(9): 850.

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 171: ComputacionI A

164 Computación ,. Lógica, resolución de problemas, algoritmos y programas

mismo. Obsérvese que se pierde la asignación del valor promedio a la variablePluviometríaProm, que se realizó en el empalmamiento mostrado en la figu­ra 2.21.

Rl PluviometriaProm:= PromedioLista(Pluviometrias>R

R2 WriteLn( 'media = " PluviometriaProm>

Figura 5.21. Creación de una rutina nueva R empalmandolas rutinas R1 y R2.

RR2 WriteLn( 'media = "

R11 PromedioLista(Pluviometrias>!

Figura 5.22. Creación de una rutina nueva R por anidamientode R1 y R2.

Adaptación. Es posible crear una rutina nueva R adaptando otra R1 ya exis­tente. Es decir, el propósito original de Rl puede ser ligeramente modificado,generalizado o particularizado de forma que realice la función requerida por R.Supongamos que adaptamos la rutina MaxL i s ta (que encuentra la posiciónque ocupa el elemento máximo de una lista) para utilizarla como una rutinaMi nLis t a (que encuentra la posición que ocupa el elemento mínimo de unalista). ¿Qué necesitamos modificar en rutina MaxL i sta de forma que cumplalas especificaciones de Mi nL i sta? Es casi evidente que es necesario realizarunas modíficaciones mínimas, y el resultado se obtiene mucho más rápída yfácilmente que si la construyéramos de cero. Las modificacíones se resumen enla Figura 5.23.

Mezcla. Se puede construir una rutina nueva R mediante la mezcla o entrela­zamiento de los pasos individuales de otras Rl y R2 ya exístentes. Esto semuestra de forma ablitracta en la Figura 5.24, donde se han mezclado los pasosde la rutina MaxL i sta con los de la Mi nL i sta, para obtener una nueva queobtiene el valor máximo y mínimo en una única pasada (bucle f o r) por lalista, en lugar de dos.Obsérvese que, en la Figura 5.24, hemos alterado la sintaxís y renombradoalgunas de las variables de las rutinas MaxL i sta y Mi nL i sta originales, conobjeto de que la nueva rutina MaxM i nL i s ta devuelva dos valores en lugar deuno. En una implementación completa, la cabecera podría ser:

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 172: ComputacionI A

Resolución de problemas algorítmicos 165

pl"ocedul"e MaxMinLista(L: Lista; val" Max, Min: reaL);

R

Rl if <O < m) and (m <= LengthL i sta(L» thenbegin

j := 1fOI" k := 2 to m do

if L[k](2:)L[j] thenj := k;

endelse

j := O;

~Lista :y~nLista ::J>

Figura 5.23. Creación de una rutina R por la adaptación de otra R1.

Donde los parámetros por referencia Max y Mi n se utilizan directamente en laobtención de los resultados; la variable j utilizada para este propósito en laFigura 5.23 no es necesaria en esta versión.

R Rl

if (O < m) and (m <= LengthLi sta( L» thenbegin

Max := 1 ; R2

IMin:=1;

for k :~ 2 to m dobeginif L[k] > L[Max] then

Max := k;

Iif L~~~ ~~L~Min] then

endend

elsebeginMax:=O;

I Min :=0

end; I

Figura 5.24. Creación de una rutina nueva R por mezcla de otras dos R1 y R2.

Page 173: ComputacionI A

166 Computación l. Lógica, resolución de problemas, algoritmos y programas

Obsérvese, en la Figura 5.24, que las instrucciones fa r e i f sirven tantopara el caso de la función MaxL i sta que para el de Mi nL i sta. Esto es asiporque la forma lógica de implementar ambas rutinas es la misma. En laFigura 5.24 se han marcado esas instrucciones como originarias de la rutinaR l (en lugar de por R2), pero esto es indiferente en la ilustración de la mezcla.

5.4.2. Utilización de la creatividad para diseñar nuevas rutinas

En los casos en los que no existe ninguna rutina disponible, debemos emplearnuestra creatividad para construir las abstracciones procedimentales apropia­das. En el problema de la pluviometría tenemos que utilizar nuestra creativi­dad para encontrar una solución a los pasos 3, que debe escribir los mesescuya pluviometria está por debajo de la media, y el 4, que debe mostrar el(los)mes(es) cuya pluviometria es la máxima.

Aparentemente, ambos pasos requieren utilizar el mismo tipo de estrategia-una búsqueda dentro de la lista de pluviometrias para encontrar los valoresque cumplen una determinada propiedad-. El índice de la lista PLuv i ome­tri a puede utilizarse para encontrar el nombre del mes correspondiente, en elarray Meses. Considerando el ejemplo de entrada de la Figura 5.17b, el pro­medio de lecturas pluviométricas de esta entrada es de 2,64 lts/m2

. El valorpluviométrico para PLuviometria[1] es 2,5, que se encuentra por debajode la media. Por tanto, el paso 3 debe mostrar el valor de Me ses [1] o Ene rocomo una de las salidas. Para encontrar todos los meses que satisfacen lamisma condición, es necesario explorar los doce valores pluviométricos. Estose consigue con el bucle siguiente:

{Paso 3. Mostrar meses que están por debajo deL promedio}WriteLn('Meses por debajo de La media: '};for i := 1 to LengthLista(PLuviometrias) do

if PLuviometrias[i] < PLuviometriaProm thenWriteLn(' " Meses[i]);

Obsérvese que, a pesar de haber utilizado la creatividad, la solución al paso 3combina algunas rutinas ya familiares mediante el empalmado y el anidamien­to. Por ejemplo, una referencia a un elemento del array Meses se ha anidadodentro de una rutina Wri teLn que, a su vez, está anidada dentro de unarutina que incluye un bucle foro La propia rutina del for está, a su vez,empalmada con otra rutina Wr i te Ln, para completar el paso 3.

Tras haber completado el paso 3, podemos intentar utilizar la misma estra­tegia para resolver el 4, del que sospechamos que se puede resolver en la mismaforma. Obsérvese que el valor máximo de pluviometría puede darse para másde un mes. En el caso peor, ¡los 12 meses pueden tener el mismo valor pluvio­métrico, por lo que la salida debe mostrarlos todos como salida del paso 4!

{Paso 4. Muestra eL(Los) mes(es) con vaLor máximo de PLuviometria)WriteLn( 'Mes(es) Máxima:'};

Pedro Pacheco
Highlight
Page 174: ComputacionI A

Resolución de problemas algorítmicos 167

for i := 1 to LengthListaCPluviometrias) doif PLuviometrias[i] = Maxpluviometria then

WriteLnC' " MesCes)[i]);

Obsérvese que la solución se ha conseguido adaptando la solución del paso 3.Esta práctica es habitual en la resolución de problemas algorítmicos, y debeutilizarse siempre que parezca, intuitivamente, que dos pasos necesiten el mis­mo tipo de 'proceso. ¿Pueden mezclarse los pasos 3 y 4 en un bucle for únicoque resuelva el problema? No es el caso. Piense sobre lo que ocurriría si unúnico bucle f or tuviera las dos instrucciones ; f de los pasos 3 y 4 dentrode él.

5.4.3. Utilización del conocimiento de dominio en el diseñode rutinas nuevas

A lo largo de nuestra discusión sobre la resolución de problemas algoritmicos,hemos supuesto que se posee un cierto conocimiento sobre el dominio al quepertenece el problema. En problemas sencillos, como los que hemos visto hastael momento, el único conocimiento del dominio que se precisa es el de lafamiliaridad con los rudimentos del Álgebra y de la Lógica. Para poder cons­truir soluciones a problemas más avanzados, es necesario tener unos conoci­mientos más profundos dentro del campo de la alta Matemática, Informática,Ciencias Naturales, Ciencias Sociales, Lingüística, Economía o Comercio.El Pascal estándar no incluye una rutina que calcule la raíz cuadrada de unnúmero. Supongamos que estamos trabajando con un problema que requiereesta rutina. Por ejemplo, necesitamos calcular, además del valor medio de unaslecturas pluviométricas, su desviación estándar. Este cálculo precisa la utiliza­ción de una rutina que calcule la raíz cuadrada de x, siendo x un valor nonegativo. La construcción de esa rutina puede comenzarse con la especificaciónsiguiente:

sqrtCx):(pre: x>=O)(post: result ~ y 1\ y2 ~ x)

Donde se ha utilizado el simbolo ~ para resaltar el hecho de que la raizcuadrada de algunos números sólo se puede calcular de forma aproximada.Por ejemplo, la raíz cuadrada de 2 es aproximadamente, con una precisión detres decimales, 1,414.Un conocido método de las matemáticas para calcular raíces cuadradas deforma aproximada es el método de Newton. De hecho, el método de Newtones un método general para calcular las raíces de ecuaciones, entre las que laecuación y = x2 es tan sólo un caso particular. El método de Newton es unmétodo iterativo que trabaja de la forma siguiente. Comenzamos con unaprimera aproximación al valor esperado; por ejemplo, y = 1. La elecciónparticular de este valor inicial es habitualmente indiferente para la efectividad

Pedro Pacheco
Highlight
Page 175: ComputacionI A

168 Computación l. Lógica, resolución de problemas, algoritmos y programas

del método. A partir de y calculamos un nuevo valor «más aproximado», y',mediante la fórmula:

y'y + x/y

2

La apliqción reiterada de esta fórmula crea una serie de valores candidatosque converge rápidamente hacia el valor de la raíz cuadrada de x. Por ejemplo,en la Tabla 5.2 se muestran los valores obtenidos, suponiendo x = 2 Y asu­miendo un valor inicial de y = 1. Así, utilizando el método de Newton, pode­mos construir una rutina que calcule el valor aproximado de una raiz cuadra­da, simplemente escribiendo un bucle que realice las aproximaciones sucesivasde y' a y, y que termine cuando se haya alcanzado un grado de precisiónadecuado (por ejemplo, una diferencia de 0,0001).

Tabla 5.2. Primeros pasos del cálculo aproximado de )2 por el métodode Newton

Estimación (y)

11,51,416671,41422

x/y

2/1 = 22/1,5 = 1,333332/1,41667 = 1,41176

Cálculo de y'

(1 + 2)/2 = 1,5(1,5 + 1,33333)/2 = 1,41667(1,41176 + 1,41667)/2 = 1,41422

Existe una forma alternativa de calcular raíces cuadradas que nos permiteesquivar el necesario conocimiento del dominio que supone el método de New­ton. Sin embargo, esta alternativa nos obliga a conocer el dominio de las ca­racterísticas más avanzadas de las bibliotecas de funciones estándar de Pascal.

En concreto, Pascal incorpora las funciones exp(x) y ln(x) que calcu­lan las funciones eX y el logaritmo neperiano de x, respectivamente. Combinan­do esta información con los conocimientos adquiridos en el Capítulo 2, pode­mos obtener:

b In (a)a

Por lo que tenemos una forma simplificada de calcular la raiz cuadrada de x.Recuérdese que es posible escribir la raíz cuadrada de un número como X

1/2

.

Por lo que utilizando logaritmos:

In (x 1/2) = 1/2 In x

Ahora, aplicando eX, que excribimos como exp (x), obtendremos:

exp (In (X 1/2 ) = exp (1/2 In x)

Page 176: ComputacionI A

Resolución de problemas algorítmicos 169

o bien:

X'f2 = e1f2 In (xl

Que puede escribirse en Pascal como:

y :~ exp(O,5 * ln(x»

Por lo que 1<1 solución que demos al problema algoritmico estará fuertementeinfluida por nuestro conocimiento de la relación del mismo y sus disciplinasrelacionadas.

5.5. TERMINACiÓN DEL CASO DE ESTUDIOVolviendo al caso de estudio, nos quedan por aplicar tres pasos de la metodo­logía MAPS propuesta: codíficación, verificación y prueba, y presentación.

5.5.1. Codificación

En pocas palabras, la codificación es la traslación de la solución de un proble­ma algorítmico a un programa, junto con su documentación. En la resoluciónde un problema algorítmico, la mayoría del código se obtiene durante lasetapas de partición y abstracción. Por ejemplo, hemos completado la codifica­ción de los pasos 3 y 4, del problema de la pluviometria, en la búsqueda denuevas rutinas que sean apropiadas para ellos. También los pasos 1 y 2 estánprácticamente codificados; sabemos que pueden implementarse reutilizando ycombinando rutinas de otros problemas ya existentes.El proceso de codificación implica el juntar las partes de la solución alproblema, asegurándonos de que el resultado conjunto es coherente, inteligi­ble, y satisface las pre y poscondiciones originales. Cuando codificamos enPascal suele ser útil utilizar una plantilla como la siguiente:

program <nombre>;{Breve comentario que describa el problema, la estructura general dela soluci ón, el autor y la fecha}uses <Bibliotecas de las que se tomarán algunas rutinas>;<Declaración de las variables identificadas en el proceso de parti­ción>

begin{pre: <Precondición del problema>}{Paso 1. <Descripción del primer paso de la partición>}{Paso 2. <Descripción del segundo paso de la partición}{post: <Poscondiciones del problema>}end.

Figura 5.25. Plantilla de un programa escrito en Pascal.

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 177: ComputacionI A

170 Computación l. Lógica, resolución de problemas, algoritmos y programas

Podemos codificar el programa de la pluviometría que hemos desarrollado,utilizando como guía la plantilla de la Figura 5.26. En este programa se hasupuesto que las rutinas PromedioLista, MaxLista y MinLista estánalmacenadas separadamente en la biblioteca denominada Herramientas­Lis t a s, y otras operaciones diversas para manipulación de listas de reales enla biblioteca Listas. Una vez que se ha construido el esqueleto del programa,el código de lbS pasos individuales puede completarse mediante su inserción enlos lugares apropiados.

program Pluviometrias;{El programa calcula algunas caracteristicas Pluviométricasa partir de datos mensuales. Diseñador: Allen Tucker, 30 de marzode 1990. Reutiliza las rutinas MaxLista, MinLista y PromedioLista.}uses Listas, Herrami entasL i stas;

type NombreMeses = array [1 •. 12] of string[10];

val' Meses: NombreMeses;Pluviometrias: Lista;PluviometriaProm: real;MaxPluviometria: real;MinPluviometria: real;

{Los nombres de los 12 meses}{Las 12 lecturas pluviométricas}{La medi a de las lecturas}{Valor máximo de las lecturas}{Valor minimo de las lecturas}

begin{pre: entrada = (e" e" .. "' e,,) /\ Vi E {1, .•. , 12} e, es el valorpluviométrico del i-ésimo mes del año}

{Paso 1. Inicializar lista de meses y pluviometrias}

{Paso 2. Mostrar pluviometria promedio, máxima y minima}

{Paso 3. Mostrar meses por debajo del promedio}

{Paso 4. Mostrar mes(es) con pluviometria más alta.}

{post: entrada =0/\ salida = ESTADISTICAS PLUVIOMETRICASmedia = Sum i E {1, .. "' 12}: e,/12máxi ma = Max i E {1, , 12}: e,minima = Min i E {1, , 12}: e,

Meses por debajo de la media:{m;: e J < Su. i E {1, ... , 12}: e,l12}

Mes(es) máxima:{m;: e j ~ Max i E {1, ... , 12}: e, /\ 1,; j,; 12})

end.

Figura 5.26. Plantilla en Pascal para el problema de la pluviometria.

Para completar la codificación de los pasos de entrada de datos, es necesa­rio que el programa emita los mensajes necesarios para que el usuario intro·

Pedro Pacheco
Highlight
Page 178: ComputacionI A

Resolución de problemas algoritmicos 171

duzca los datos correctamente. Lo que hay que hacer se refleja en el esquemadel paso 1 siguiente:

{Paso 1. Inicializar lista de meses y pluviometrias}InicializarMesesCMeses);WritelnC'Introducir la lista de los 12 valores pluviométricos men­suales:' );Readlista(pluviometrias);

Donde es necesario diseñar la rutina In; c; aL; za rMeses de forma que elarray Meses se inicialice adecuadamente con los nombre de los doce meses delaño. Podemos añadir entradas protegidas (para el caso en que las prccondicio­nes deban ser comprobadas explícitamente por el programa). Por ejemplo, envez de reducir el paso 1 a las instrucciones:

WritelnC'Introducir la lista de los 12 valores pluviométricosmensuales:');ReadlistaCPluviometrias);

Es posible comprobar que se introduce exactamente una lista de doce elemen­tos con las instrucciones:

repeatWritelnC'introducir la lista de los 12 valores pluviométricosmensuales: 1);ReadlistaCpluviometrias);

until lengthlistaCPluviometrias) = 12;

El código de los pasos 2 a 4 se ha completado en el programa de la Figu­ra 5.27. Obsérvese que se ha omitido el cuerpo del procedimiento In; c; aL;­za rMeses, que se deja como ejercicio.

5.5.2. Prueba y verificación

El objetivo de la prueba y la verificación es garantizar lo más posible que lasolución diseñada es correcta y completa en todos sus extremos. Es decir, setrata de poder asegurar que la ejecución del programa, utilizando unos datosde entrada permitidos por las precondiciones, producirá un resultado consis­tente con las poscondiciones. Debido a que la prueba y verificación son funda­mentales en el proceso de resolución de problemas algorítmicos, se analizaránen profundidad en el Capítulo 6.

5.5.3. Presentación

Cuando la solución a un problema algorítmico ha sido desarrollada completa­mente, el programa debe ser suficientemente autodocumentado, para cuando

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 179: ComputacionI A

172 Computación l. Lógica, resolución de problemas, algoritmos y programas

sea leído por alguien no familiarizado con la solución obtenida, pero sí con lametodología y el dominio al que pertenece el problema. Es decir, el texto delprograma ---con su documentación, estructura paso a paso, y pre y poscondi­ciones- debe ser fácilmente legible por un colega profesional, como lo sería unartículo del ABe para cualquier persona bien educada.

La presentación de una solución completa de un problema algorítmicodebe incluir, además del propio texto del programa, los elementos siguientes:

1. Una introducción escrita en castellano identificando el(1os) autor(es) yque descríba el problema, la solución y algún aspecto inusual o innova­dor de la solución.

2. Un ejemplo de las entradas y las respectivas salidas obtenidas en una ovarias ejecuciones del programa.

3. Un resumen de los resultados de la verificación y/o prueba del progra­ma, en los casos en que sea adecuada.

program Pluviometrias;(El programa calcula algunas caracteristicas Pluviométricasa partir de datos mensuales. Diseñador: Allen Tucker, 30 de marzode 1990. Reutiliza las rutinas MaxLista, MinLista y PromedioLista.)

uses Listas, HerramientasLi stas;

type NombreMeses = array[1 .. 12] of string[10];

var Meses: NombreMeses;Pluviometrias: Lista;PluviometriaProm: real;MaxPluviometria: real;MinPluviometria: real;

(Los nombres de los 12 meses)(Las 12 lecturas pluviométricas){La media de las lecturas}(Valor máximo de las lecturas)(Valor minimo de las lecturas)

begin{pre: entrada = (e" e" .•• , en) /\ Vi E {1, .• ",12) e, es el valorpluviométrico del i-ésimo mes del año)

{Paso 1. Inicializar lista de meses y pluviometrias)InicializarMeses(Meses)WriteLn('Introducir la lista de los 12 valores pluviométricosmensuales:');

ReadLista(Pluviometrias);

(Paso 2. Mostrar pluviometria promedio, máxima y minima)WriteLn('ESTADISTICAS PLUVIOMETRICAS');PluviometriaProm := PromedioLista(Pluviometrias);WriteLn(' media = " PluviometriaProm:5:2);MaxPluviometria :=MaxLista(Pluviometrias, LengthLista(Pluviome­trias»;

WriteLn(' máxima = " MaxPluviometria:5:2);MinPluviometria :~ MinLista(Pluviometrias, LengthLista(Pluviome­trias»;

WriteLn(' minima = " MinPluviometria:5:2);

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 180: ComputacionI A

Resolución de problemas algorítmicos 173

(Paso 3. Mostrar meses por debajo deL promedio)WriteLn( 'Meses por debajo de La media:');for i :~ 1 to LengthLista(PLuviometrias) do

if PLuviometrias[i] < PLuviometriaProm thenWriteLn('Meses[i]);

{Paso 4. Mostrar mes(es) con pLuviometria más aLta.)WriteLn( 'Mes(es) máxima:');fQr i := 1 to LengthL ista(PLuviometrias) do

if PLuviometrias[i] = MaxPLuviometria thenWriteLn(' " Meses[i]);

{post: entrada ~01\ saLida = ESTADISnCAS PLUVIOMETRICASmedia = Sum i E {1, , •. ,12): e,l12máxima = "ax i E (1, .. ",12): e iminima = "in i E (1, ." ,,12): e i

Meses por debajo de La media:{mj: e j < Sum i E {1, .. "' 12): e,l12 )

Mes(es) máxima:(m j : e j ~ "ax i E (1, """,12): eiI\1~j~12))

end.

Figura 5.27. El programa Pascal PLuviometrías, compLeto.

En pocas palabras, la presentación de la solución a un problema debe hacesede forma que un lector interesado sea capaz de comprenderla. El lector será,por el momento, su profesor, pero en un futuro podría ser cualquier otroresolutor de problemas profesional (programador o analista) al que se le asignela tarea de revisar o extender la solución al problema en cuestión.

5.6. RESUMEN

En el Capítulo 4 introdujimos las técnicas y herramientas básicas para cons­truir programas sencillos en Pascal a partir de sus especificaciones. En estecapítulo hemos aprendido cómo analizar un problema y a desarrollar su solu­ción, identificando elementos del programa más pequeños (rutinas) y combi­nándolas todas en un programa completo.

Aprendimos algo del proceso de abstracción y de su realización en Pascal.La creación de rutinas que puedan ser reutilizadas, es una de las tareas funda­mentales del proceso de resolución de problemas algoritmicos. Podemos reuti­lizar rutinas y recombinarlas en cuatro formas fundamentales --empalmándo­las, anidándolas, adaptándolas y mezclándolas durante el proceso de creaciónde una solución a un problema nuevo. Fuera de estos limites, es preciso utilizarla creatividad y el conocimiento del dominio. Los otros aspectos de la resolu­ción de problemas algorítmicos son evidentes en la metodología MAPS --eldiálogo, la especificación, la partición, definición de abstracciones, codificación,verificación y prueba, y presentación.

Pero entender no es lo mismo que hacer. Antes de proseguir con el libro,tómese algún tiempo para diseñar y escribir programas para los problemas

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 181: ComputacionI A

174 Computación l. Lógica, resolución de problemas, algoritmos y programas

propuestos en los ejercicios siguientes. Asegúrese de aplicar correctamente lastécnicas del método MAPS.

Ejercicios

5.23. Implementar una rutina del método de Newton para calcular raicescuadradas en forma de función de Pascal, y que tenga Z + como domi­nio y R como rango. Probar el resultado para diversos valores de x, ycompararlos con los resultados de utilizar la rutina de cálculo de raícescuadradas de la Sección 5.4.

5.24. Escribir el cuerpo del procedimiento In; e; al; za rMeses del progra­ma de la Pluv;ometr;a.

5.25. Continuar con el diseño MAPS sobre los números romanos esbozadoen el Ejercicio 5.20; definir las abstracciones y codíficar el programacompleto. ¿Es posible utilizar abstracciones vistas previamente? ¿Quéabstracciones nuevas es necesario introducir, y qué tipo de creatividad yconocimiento del dominio es necesario utilizar para completarlo?

5.26. Diseñar e implementar un sistema de manipulación de información deuna pequeña compañía. El programa deberá leer un archivo del perso­nal, en el que cada empleado tiene su número y sueldo anual. Diseñarun programa que realice un informe. Diseñar el formato del informecuidadosamente; cada elemento debe estar etiquetado cuidadosamente.Para poder probar el programa, suponer que la compañia tiene 25 em­pleados y diseñar un archivo de empleados sencillo, consistente en núme­ros de empleados y su sueldo anual. En el informe, mostrar lo siguiente:

a) La nómina anual de la empresa, los sueldos anuales máximo, mini­mo y medio.

b) Un apartado de la misma información para los rangos de salariossiguientes (en dólares):

< sueldo < 15.00015.000 < sueldo < 20.00020.000 < sueldo < 30.00030.000 < sueldo < 45.00045.000 < sue ldo

(Es decir, el número de trabajadores de cada intervalo, junto con lossueldos máximo, mínimo y medio de cada intervalo.)

5.27. Desarrollar un diseño basado en la metodología MAPS, para un gestorde apuestas múltiples en las carreras de caballos. Antes de cada carrera,el usuario debe introducir la apuesta que realice, dando el número del

Page 182: ComputacionI A

Resolución de problemas algorítmicos 175

caballo y el valor de la apuesta. Tras la campana de «última apuesta», elprograma debe calcular y visualizar la relación de las apuestas sobrecada caballo, que se calcula dividiendo el valor total de las apuestassobre todos los caballos por la cantidad total apostada a cada caballo.Por ejemplo, en una carrera con tres caballos, el total de apuestas parael número 1 fueron 100 dólares; para el número 2, 150 dólares; y 250dólares Pllra el número 3. Las relaciones para el ejemplo anterior serán5 a 1 para el primero, 5 a 3,33 para cl segundo, y 2 a 1 para el tercero.No es necesario implementar todo el programa, sino sólo el diseño(pasos de MAPS del 1 al 4).

Page 183: ComputacionI A

CAPíTULO 6ROBUSTEZ Y PRUEBADE LOS ALGORITMOS

Todo lo que pueda funcionar mal, lo hará.MURPHY

La disciplina de resolver problemas algorítmicos puede resultar cruel. El dise­ñador no sólo debe cuidar que el programa funcione correctamente para lasentradas que se ajustan a las especificaciones, sino que debe cuidar que elprograma responda adecuadamente cuando se encuentre entradas incorrectaso inesperadas. Asi, el resolutor de problemas se convierte rápidamente en unescéptico sobre la infalibilidad de los programas que pretenden resolver unproblema. Invariablemente, siempre que oimos en el laboratorio «¡he encon­trado el último error!», sabemos que después comprobará que sólo era elpenúltimo.

¿Es posible resolver problemas complejos y diseñar un software que tengauna fiabilidad alta? Es decir, ¿cómo podemos asegurar que nuestros progra­mas, que son el producto final de nuestra metodologia de resolución de proble­mas algoritmicos (MAPS), detecten combinaciones de entradas inesperadas, yaun así trabajen de forma correcta y predecible?

En este capítulo analizamos estas cuestiones de diferentes formas. Primero,definimos las nociones complementarias de corrección, robustez y amigabili­dad. Segundo, ilustramos la aplicación de estas ideas en dos situaciones dife­rentes: una que involucra el procesamiento de textos, y otra que involucra eltratamiento de gráficos. En ambos casos utilizamos la metodología de resolu­ción de problemas MAPS, lo que nos servirá para afianzarnos en su conoci­miento para utilizarla en otro tipo de problemas algorítmicos. Tercero, intro­ducimos una estrategia para diseñar datos de prueba, y una metodología deprueba sistemática que aporta un grado de confianza sobre la corrección yrobustez del programa mayor que si se utilizan pruebas aleatorias. Cuarto,introducimos la noción complementaria de verificación formal y mostramosque está estrechamente relacionada con el lenguaje de la lógica y los procesosde demostración que fueron presentados en el Capitulo 3. Como veremos, lastécnicas de verificación y prueba pueden combinarse para crear una serie demétodos que aseguren la calidad y fiabilidad del software.

Pedro Pacheco
Highlight
Page 184: ComputacionI A

178 Computación l. Lógica, resolución de problemas, algoritmos y programas

6.1. CORRECCiÓN V ROBUSTEZ

¿Qué significa que un programa sea correcto?

Definición. Un programa es correcto si, para cualquier entrada que satisfa­ga la precondición, termina generando una salida que satisface sus poscon­diciones. De forma análoga, un procedimiento (o función) es correcto si,para todos los posibles valores de los parámetros de entrada que satisfacenlas precondiciones, termina y, además, los parámetros de salida (resultados)satisfacen las poscondiciones.

Por ejemplo, el programa que calcula la calificación media CaLcuLaCM, delCapitulo 4, es correcto en este sentido. Es decir, para todas las entradas deltipo (Notas!' Notas2, .•. , Notasn), donde n > Oy cada Notas, es un número enel intervalo {O, ..., 4} el programa calcula y escribe la calificación media ytermina. A continuación, se demuestran algunas entradas y sus correspondien­tes salidas, para diferentes ejecuciones del programa.

Entrada

(3 1 2 4)(2 )(2 3 3 3 3 3 3 2)

Salida

2,502,002,75

Un estudio cuidadoso del programa de la Figura 4.6 hace que nos plantee­mos algunas dudas sobre lo que ocurre cuando las entradas no satisfacen lasespecificaciones de las precondiciones. Por ejemplo, ¿qué ocurre si la entradaes la lista vacia( )? ¿Qué ocurre si la lista de entrada contiene valores fuera delintervalo {O, ..., 4}, como la lista de pluviometrías mensuales utilizadas en laFigura 5.17b, utilizadas para un problema completamente distinto? ¿Qué ocu­rre si la lista contiene algo distinto de números, como la lista de los docenombres de meses de la Figura 5.17a?

Una posible alternativa para responder a esas preguntas es correr el pro­grama con varias entradas alternativas que no satisfacen las precondiciones, yver qué ocurre en cada caso. Observemos el cuerpo del programa Ca Lcu La CMy analicemos cómo tratará cada uno de los distintos casos (véase Figura 6.1).

Este es un programa tan sencillo que resulta conveniente un análisis tandirecto. En el caso en que la lista de entrada esté vacia, no se satisface lacondición n > O, por lo que el programa no genera ninguna salida. Sin embar­go, en el caso en que los valores de la entrada no estén en el intervalo {O, ..., 4},el programa calcula sin problemas el promedio y escribe (erróneamente) elvalor de la CM, aunque algunas entradas numéricas no sean calificacionesválidas, según las especificaciones.

Pedro Pacheco
Highlight
Page 185: ComputacionI A

Robustez y prueba de los algoritmos 179

begin{pre: entrada ~ (Notas" Notas" . o., Notas,) 1\ n > O 1\

\;Ii E {1, o •• , ni: Notas, E {O, .•. , 4}}

{Paso 1. Obtenemos la lista de calificaciones}WriteLn( 'Introducir la lista de calificaciones:');ReadLista(Notas);

{Pas6 2. Calcular n o número de calificaciones en la lista}n:~ LengthLista(Notas);i f n > O then

begin{ent rada =0 A n>O}

{Paso 3. Calculamos Sum = la suma de las calificaciones de la lista}Sum := O;i :~ 1;while i <= n dobegin

Sum := Sum + Notas[i];i := i + 1

endend;

{Paso 4. Calculamos CM = Sum/n}CM = Sum/n;

{Sum = Su. i E {1, ... , n}: Notas, 1\ CM ~ Sum/nj

{Paso 5. Se muestra CM}WriteLn('La CM de esas calificaciones es ~', CM 5: 2)

end {if}{pos t: ent rada = 0 1\

salida = SUII i E {1, o •• , n}: Notas,!n}end. {CalculaCM}

Figura 6.1. Cuerpo del programa CalculaCM.

Finalmente, consideremos el caso en que la entrada no es completamentenumérica:

(31 hello 2)

Cómo trate el programa esta entrada dependerá de cómo manipule la rutinaReadL i s ta las entradas no numéricas. Es decir, los valores obtenidos porReadLista<Notas) parai = 1,2y4sonlosnúmeros3,1 y2,respectiva­mente. Para el caso de i = 3 (donde la entrada es Notas = heL Lo) ¿seproducirá un error?, ¿debe devolver la rutina algún valor especial, por ejemplo0, cuando se introduzca un valor no numérico? Obsérvese que simplementeanalizando las pre y poscondiciones de la rutina ReadL i s ta (véase Apén­dice C), no se contesta a esta pregunta, puesto que éstas están enunciadas paraentradas válidas. Sin embargo, ejecutando el programa podemos descubrir que

Page 186: ComputacionI A

180 Computación l. Lógica, resolución de problemas, algoritmos V programas

la referencia a Notas[3] devuelve el valor °para esta lista en concreto, porlo que el valor promedio es, por tanto, 1,50.

Tenemos que destacar, por tanto, que el programa Ca Lcu LaCM es correctoen el sentido de la definición anterior. Sin embargo, no es robusto.

Definición, Se dice que un programa es robusto si reúne las dos condicio­nes siguientes:

1. Es correcto.2. Para todas las entradas que no satisfacen las precondiciones, el

programa termina y produce una salida que refleja el hecho de queha ocurrido un error en la entrada.

Seguramente, el programa Ca Lcu LaCM no es robusto, aunque seguramente escorrecto. En general, la creación de software robusto es más complicada que lacreación de software correcto. Más aún, la robustez es una característica desea­ble para el software de computadoras, sobre todo si va a ser manipulado porgente no familiarizada con los detalles del diseño, o que son proclives a come­ter ocasionalmente errores cuando escriben la entrada.

¿Cómo es posible robustecer el programa de la Figura 6.1? Es necesariohacer dos cambios básicos. Primero, es preciso revisar el procedimientoReadL; s ta de forma que ponga L; s tError a t rue siempre que aparezcaun dato no numérico en la lista de entrada. El paso 1 del programa debeexplorar específicamente la corrección de cada calificación (es decir, que sea unvalor numérico dentro del conjunto {O, ..., 4}). Segundo, es necesario completarla instrucción condiciorral que compruebe si n > 0, con una cláusula e Lse, deforma que el programa escriba el mensaje de error apropiado cuando se pre­sente como entrada una lista vacía. Podemos revisar el paso l de la formasiguiente:

(Paso 1. Obtenemos la lista de calificaciones}WriteLn( 'Introducir la lista de calificaciones:');ReadLista(Notas);n := LengthLista(Notas);if Li stError o .. (n = O) thenentradaválida := false

elsebeginentradavál ida :~ true;for i := 1 to n doif Notas[i] < O) o .. (Notas[i] > 4) thenentradaválida := false;

end;i f not ent radavá l i da thenWriteLn('Entrada no válida. Programa terminado')

else begin

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 187: ComputacionI A

Robustez y prueba de los algoritmos 181

Donde la nueva variable booleana ent radavá L; da indica si la entrada seajusta o no a los requisitos de la precondición. El resto del programa quedariade la forma original, salvo que la comprobación de si n > O puede ser elimina­da (puesto que se ha incorporado el paso 1 de esta nueva versión).

Una tercera caracteristica que es valorable en un programa es la de laamigabilidad. Es decir, es deseable un programa que no sólo identifique loserrores de entrada, sino que, a ser posible, realice avisos constructivos alusuario sobre cómo tiene que escribir ésta para que se ajuste a las especifica­ciones.

Definición. Se dice que un programa es amigable si reúne los requisitossiguientes:

1. Es correcto.2. Para todas las entradas que no se ajusten a las precondiciones, el

programa indica el tipo de error de entrada y concede al usuario laoportunidad de corregirlo y continuar.

Cómo podemos convertir el programa CaLcuLaCM en un programa amiga­ble? Podemos revisar el paso 1 en la forma siguiente:

{Paso 1. Obtenemos la lista de calificaciones}repeat

WriteLn('Introducir La lista de calificaciones:');ReadLista(Notas);n := LengthLista(Notas);if ListError 01' (n = O) thenentradavál ida ;= false

elsebeginentradavál ida := true;for i :~ 1 to n doif Notas[i] <O) 01' (Notas[i] > 4) thenentradaválida := false;

end;until entradaválida;

Esta entrada es más constructiva que la anterior, porque permite al usuariomúltiples oportunidades de reintroducir la lista de calificaciones. Es decir, elprograma continúa en el bucle del paso 1 hasta que se introducen las califica­ciones apropiadas, tras lo cual pueden ser ejecutados los pasos del 2 al 5.

Asegurarse de que un programa es correcto, robusto y amigable es unatarea dura. Ello implica la aplicación cuidadosa de técnicas de prueba deprogramas intrínsecas a la metodología MAPS. Puesto que esta actividad estan crucial en la resolución de problemas algorítmicos, hacemos hincapié enella en las Secciones 6.2 y 6.3, donde resolvemos dos problemas muy diferentesutilizando la metodología MAPS.

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 188: ComputacionI A

182 Computación l. Lógica, resolución de problemas, algoritmos y programas

Ejercicios

6.1. ¿Es correcto el programa de las Tres-en-Raya de la Figura 4.21? ¿Esrobusto? Justificar la respuesta.

6.2. Mostrar cómo puede modificarse el problema de las Tres-en-Rayapara que sea má~ amigable.

6.3. a) Revisar la precondición del programa de las Tres-en-Raya, deforma que describa exactamente cuál movimiento es legal y cuál no.

b) Considerando esta revisión, ¿qué cambios adicionales pueden reali­zarse para hacer el programa más robusto?

6.4. ¿Es correcto el programa ContarPalabras de la Figura 4.17? ¿Esrobusto? Justificarlo.

6.5. Mostrar la forma en que se puede alterar el programa ContarPala­bras para hacerlo amigable.

6.2. RESOLUCiÓN DE PROBLEMAS DE PROCESAMIENTODE TEXTO UTILIZANDO MAPS: CRIPTOGRAFíA

Las computadoras se han utilizado desde la Segunda Guerra Mundial paraayudarnos en la resolución de problemas criptográficos, que requieren descu­brir el esquema de codificación, o cifrado, que subyace en un mensaje codifica­do. En el Capítulo 2 presentamos un ejemplo del conocido método César decifrado que convirtió el mensaje

SERGEANT PEPPERS LONEL y HEARTS CLUB BANO

en el mensaje codificado

VHUJHOQW SHSSHUV ORQHOB KHOUWV FOXE EOQG

Aquí, el esquema de codificación subyacente consiste en reemplazar cada letrapor la que ocupa tres posiciones posteriores en el alfabeto. En la práctica,se utilizan otros esquemas de codificación más elaborados, y el descubrimientotanto del cifrado como del mensaje original puede ser una tarea bastantecomplicada.

En nuestro caso, el problema es mucho más sencillo: dada una serie demensajes codificados según el método César, descodificar cada uno y escribir eltexto del mensaje ya descodificado. Por tanto, para el mensaje codificado quese muestra arriba, la salida debería ser SERGEANT PEPPERS LONELyHEARTS CLUB BAND.

Page 189: ComputacionI A

Robustez V prueba de 105 algoritmos 183

Etapa 1: El diálogo. Existen tan pocas dudas acerca de este problema, quepodemos estar tentados de abordar directamente el diseño. Sin embargo, esnecesario apuntar y resolver algunas cuestiones de detalle. Por ejemplo, ¿puedecontener el texto tanto letras mayúsculas como minúsculas, e incluso caracte­res no alfabéticos? Presumiblemente la respuesta es si, y tales caracteres debenaparecer en el mensaje descodificado tal y como aparecían en el mensaje origi­nal. Por ejemplo, el blanco del mensaje codificado permanece igual en el men­saje descodificado.

Etapa 2: Las especificaciones. Las especificaciones para este problema puedenestablecerse de la forma siguiente:

[pre: entrada = una serie de mensajes, siendo cada uno una secuenciade caracteres c" ... , cn representando una codi fi cación uti LizandoeL método de César

"post: saLida = una serie de textos descodificados de La formad" ... , dn en La que cada d, satisface La reLación c, ~ César(d,) /\c,es un carácter aLfabético v para todo i en {1, ... , n): c, = di}

Donde Césa r (di) representa la codificacíón César del; -ésimo carácter dien el texto de salida. Esta codificación se describe en la Tabla 6.1.

Tabla 6.1. El cifrado de César

Letra (1) César (1) Letra (1) César (1)

a d A Db e B E

x a X AY b Y Bz e Z C

Etapa 3: La partición. El programa necesita ejecutar tres pasos principalespara cada mensaje que descodifica. En el paso dc entrada se obtendrá el men­saje descodificado, a continuación se hará un paso de descodificación y, final­mente, se realizará el paso de salida que escribe el programa ya descodificado.Estos pasos se resumen de la forma siguiente:

repeat

{Paso 1. Obtener eL mensaje. J

{Paso 2. Descodificar eL mensaje.)

{Paso 3. Escribir eL mensaje descodificado.)

until no existan más mensajes para descodificar

Page 190: ComputacionI A

184 Computación ,. Lógica, resolución de problemas, algoritmos y programas

Si acordamos que la longitud máxima de un mensaje está limitada a lalongitud máxima de un string de Pascal (255 caracteres en la mayoría de lasimplementaciones), entonces existe una pequeña dificultad al implementar lospasos de entrada y salida para este programa. Sin embargo, si pretendemosmás generalidad, es necesario realizar algunas cuidadosas consideraciones so­bre el almacenamiento y los requerimientos de codificación de cada mensaje.En esta solución vamos a atenernos a la versión más simple.

Así, el programa tendrá dos variables del tipo s tri n9 principales, la va­riable mensaje y la variable deseodi fi cado. La propia descodificaciónpuede hacerse de dos maneras. Una forma es la de almacenar las letras delalfabeto en un array, por ejemplo el array César, de forma que la descodifica­ción de una letra concreta Césa r [i] puede obtenerse directamente buscandoen César[i-3]. Si utilizamos esta estrategia, tendremos que tener cuidadocon las tres primeras letras del alfabeto. (¿Por qué?)

Otra forma de descodificar las letras del alfabeto es la de hacer operarsobre el ordinal que corresponde a cada carácter en la tabla ASCII (véase elApéndice A). Por ejemplo, el ordinal de la letra A es el 65, que se diferencia delordinal de la letra D (68) en tres unidades. Así, si e es una letra del mensaje deentrada, la función de Pascal ehr(ord(e)-3) devolverá la letra codificada,suponiendo de nuevo que e no es una de las tres primeras letras del alfabeto.(¿Por qué?)

Etapa 4: Definición de abstracciones. El paso 2 de este programa, la descodifi­cación del mensaje, puede considerarse como el anidamiento de dos rutinas. Esdecir, la función que calcula la inversa de la función de cifra de César (véaseTabla 6.1) para una sola letra del alfabeto, puede anidarse dentro de otra queanalice uno a uno los caracteres que componen el mensaje codificado. Laúltima puede implementarse como un bucle for, mientras que la primerapuede implementarse como una función de Pascal a la que denominaremosCésarlnversa(e), que toma un solo carácter como argumento y devuelvecomo resultado el carácter descodificado. El anidamiento debe tener lugar,puesto que esta operación se realiza para todos los caracteres del mensaje.Podemos definir las especificaciones de esas dos rutinas en la forma siguiente:

Descodificar(mensaje){pre: mensaje = C 1 , e 2 , •• _, en}{post: resultado = d" d" •. "' dn 1\ para todo i in (1, "."' n):di = Césarlnversa(c»)

Césarlnversa(c)(pre: c es un carácter)(post: resultado = d, Y bien d es alfabético 1\ CésarCd) = c or d noes alfabético 1\ d = c)

Etapa 5. Codificación. Las especificaciones anteriores pueden codificarsecomo rutinas Pascal de la forma siguiente:

Page 191: ComputacionI A

Robustez y prueba de los algoritmos 185

function Descodificar (mensaje: string): string;yar

i: integer;descodificado: string;

begin{pre: mensaje = C1, C2 , •• "' en}

descodificado := mensaje;for i := 1 to Length(mensaje) do

descodifi cado[i] := CésarInyersa (mensa j e[i]);Descodif i ca r : = descodi f i cado

{post: resultado=d" d" ... , do 1\ para todo i in {1, ... , ni:di = CésarInversa(c i )}

end;

function César Inversa (c: char): char;yar

d: char;j: integer;alpha: string;

begin{pre: c es un carácter}

alpha := concat('abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ');

j := pos(c, alpha); {busca c en el al fabeto}case j of

O:d := c; {no es alfabético}

1 .. 3:d := alpha[23 + n; {descodifica a, b, c}

4 .. 26:d := alpha[j - 3]; {descodifica d, e, .. "' z}

27 .. 29:d := alpha[23 + n; (descodifica A, B, C)

30" .52:d :~ alpha[j - 3J; {descodifica D, E, ... , Z}

end;César Inversa := d;

(post: resultado = d, Y bien d es alfabético /\ César(d) = cor d no es al fabético 1\ d = c}

end;

Teniendo todo lo anterior en mente, podemos escribir el esbozo de programasiguiente:

program Criptografia;{El programa descodifica una serie de mensajes y escribe cada unodescodi fi cado; se supone que cada mensaje se ha codi fi cadoutil izando la cifra de César.}

function CésarInversa

function DescodificarYar

mensaje, descodificado: string;

Page 192: ComputacionI A

186 Computación l. Lógica, resolución de problemas, algoritmos y programas

begin{pre: entrada ~ una serie de lineas, conteniendo cada una un mensajecodifi cado}

repeat{Paso 1. Obtener el mensaje}

WriteLn('Introducir en una sola linea un mensaje codificado, y');WriteLn,( 'pulsar <RET> para terminar:');ReadLn(mensaje);

{Paso 2. Descodificar el mensaje.}descodificado:~Descodificar(mensaje);

{Paso 3. Escribir el mensaje descodificado.)WriteLn('El mensaje descodificado es:');WriteLn(descodificado);

unti l mensaje = "

{post: entrada ~ vacia 1\ salida ~ el correspondiente mensajedescodificado}

Etapa 6: Prueba. Es útil probar este tipo de programas utilizando como entra­da un texto almacenado en un archivo separado. De esta forma, no es necesa­rio reescribir de forma tediosa el mensaje de entrada cada vez que se ejecute elprograma. Una sencilla alternativa al programa anterior, que permita utilizaruna variable archivo (tipo file), en el que se escribiría la entrada, y que condi­ciona la terminacíón del programa a que se lea la marca de fin de fichero, seobtendría con las modificaciones siguíentes. Previas al paso 1 habría que escri­bir:

var Archi voTexto: text

reset(ArchivoTexto, 'codificado,txt');

El paso 1 debería alterarse para que tome la entrada del archivo, en lugar detomarla desde el teclado, en la forma siguiente:

ReadLn(ArchivoTexto, mensaje);WriteLn(mensaje);

Finalmente, la condición de terminación del bucle repea t debe explorar elfinal del archivo de entrada en la forma siguiente:

until not eof(Archi voTexto);

Es evidente que, separadamente, se debe preparar en la forma adecuada elarchivo cod i f i cado. t x t para que incluya los textos codificados antes deejecutar esta nueva versión del programa.

Page 193: ComputacionI A

Robustez y prueba de los algoritmos 187

Etapa 7: Presentación. La presentación de la solución a este problema requie­re la realización de varias ejecuciones del programa, imprimiendo la salidacorrespondiente a cada ejecución. La combinación de estas salidas con el textodel programa, una breve exposición escrita con el propósito del mismo, y unaexplicación con alguna característica inusual (si la tiene), completarán la pre­sentación.

6.3. RESOLUCiÓN DE PROBLEMAS GRÁFICOS UTILIZANDOMAPS: EL JUEGO DE LA VIDA

El Juego de la Vída lo inventó John H. Conway en 1970. Su propósito esproporcionar una simulación gráfica sencilla de la variación de población a lolargo de varias generaciones. El juego se juega en un entramado rectangularque representa «el mundo» para una especie particular de organismo viviente(personas, amebas, pollos u otros). En el entramado, cada celda sombreadarepresenta un organismo vivo, y la coleccíón completa de celdas sombreadas lapoblación viva en una generación concreta. Por ejemplo, la Figura 6.2 muestrauna población de seis pollos vivos en un mundo que puede albergar un totalde 64 en una generación.

Figura 6.2. Una generación de seis pollos en el Juego de la Vida.

Cada nueva generación de pollos se obtiene de la anterior siguiendo cuatroreglas muy simples que regulan la supervivencia, muerte o nacimiento de cadaindividuo. Estas reglas están relacionadas solamente con el entorno fisico enque vive el pollo -es decir, las condiciones de superpoblación o la baja densi­dad de población en la que se incluye el pollo-o Se define el entorno de unacelda del entramado, como el conjunto de celdas contiguas a ella. Las cuatroreglas mencionadas son:

1. Supervivencia. Un pollo sobrevive hasta la siguiente generación, si tie­ne dos o tres vecinos vivos en la generación actual.

2. Nacimiento. Un pollo nacerá en la generación siguiente, si: a) no existeen la generación actual; y b) tiene exactamente tres vecinos vivos en lageneración actual.

Page 194: ComputacionI A

188 Computación l. Lógica, resolución de problemas, algoritmos y programas

3. Muerte por soledad. Un pollo morirá en la generación siguiente, si enla actual tiene cero o un solo vecino.

4. Muerte por superpoblación. Un pollo morirá en la siguiente genera­ción, si en la actual tiene 4 o más vecinos vivos.

Asi, si extendemos el ejemplo de la Figura 6.2 hasta la generación siguiente,nuestra población de ppllos se transformará en la de la Figura 6.3.

Observamos, en la Figura 6.3b, que el pollo de abajo, a la izquierda, hamuerto por soledad, mientras que dos pollos en la «cruz» han muerto porsuperpoblación. Los otros tres pollos de la cruz han sobrevivido porque teníantres vecinos en la generación anterior. Finalmente, nacieron tres nuevos pollosen celdas que estaban sin ocupar, y tenian exactamente tres vecinos en lageneración anterior.

a) b)

Figura 6.3. Dos primeras generaciones en el Juego de la Vida.a) Seis pollos en la primera generación. b) Seis en la segunda.

Después de algunas pruebas, podemos concluir que la configuración de po­llos en cada generación puede diferir de la precedente. El Juego de la Vida yalgunas derivaciones que presentan pequeñas diferencías, han fascinado a mate­máticos y científicos que los han estudiado detenidamente. Los científicos hanestudiado la forma de aplicar este tipo de simulacíones o técnicas de modeliza­ción, como ayuda para comprender los cambios de población en la vida real.

Sin embargo, el problema al que nos enfrentamos aquí es simplemente el deconstruir un programa que, para una configuración inicial sobre un entramadode 8 x 8 celdas, muestre la secuencia de generaciones que siguen las reglassobre supervivencia, vida y muerte anteriores.

Etapa 1: El diálogo. Seguramente, nuestro programa debe proporcionar alusuario una forma sencilla de describir la configuración inicial de los pollos enel entramado. Mientras no sea dificil generalizar el programa para que puedamanipular entramados de cualquier tamaño, esto no parece ser importantepara el programa, por lo que lo ignoraremos por el momento. Sin embargo, esnecesario incorporar algún mecanismo por el cual el usuario pueda controlarel paso de las generaciones, e incluso parar el proceso.

Page 195: ComputacionI A

Robustez y prueba de los algoritmos 189

Podemos considerar la entrada en dos etapas. Primero, el usuario introdu­ce las filas y columnas de cada celda que estarán ocupadas por la primerageneración de pollos. Segundo, el usuario introducirá una serie de órdenes queindicarán al programa si debe avanzar a la siguiente generación, o bien termi­nar el juego.

La salida la constituyen una sucesión de gráficos como los de la Figura 6.3.La configuración inicial se compone de un entramado, colocado a la izquierda,con la distribución inicial, y otro entramado vacío a la derecha. La segundaimagen, que se visualiza ante la entrada por el usuario de la orden de progre­sar, estará constituida por un entramado a la izquierda con la configuracióninicial, y el de la derecha con la distribución obtenida en la segunda genera­ción. La tercera imagen, si se ordena, presentará a la segunda generación a laizquierda, y la tercera a la derecha, y asi sucesivamente.

Etapa 2: Las especificaciones. Después del diálogo, podemos escribir las si­guientes especificaciones para este problema:

{pre: entrada =n, X1, y" XZ' Y2' •• _, Xn , Yn , C" e Z' ••• , Cm /\ Cm = I q ' /\n > O 1\ m> O pa ra todo i in {1, ... , n}: 1 ,;; Xii y; ,;; 8}

{post: salida = una serie de m- 1 imágenes del Juego de la Vida,donde la pri mera imagen está determi nada por las n celdas(x" y,>, (x" y,> ••• , (Xn, Yn>' y cada imagen sucesiva presentala i-ésima generación que se obtiene de la (i -1)-ésima al aplicarlas reglas de nacimiento, supervivencia y muerte. El final deljuego lo provoca el usuario pulsando' 'q" (de' 'quit' '>')

Donde las pulsaciones de teclas C" Cl' ••• , Cm-' sirve para proporcionar alusuario el control de las transiciones entre una generación y la siguiente. Esdecir, el carácter (incluida la barra espaciadora) que se simboliza por c; indicaal programa que tiene que calcular la i -ésima generación, a partir de la(i -1)-ésima y dibujarlas una alIado de la otra. Por tanto, en cada momento, elprograma debe mostrar las dos últimas generaciones calculadas, siendo la de laderecha la más reciente. La primera generación, dada por las coordenadas x"y" x2 ' Yl' ••• , xn, Yn' se identifica con el nombre de generación 1 de lasecuenCia.

La Figura 6.3 muestra una generación 1 inicial (en el entramado del ladoizquierdo) y la generación 2, que se obtendría si se pulsa la tecla de continua­ción (lee las celdas sombreadas, fila a fila, suponiendo que las filas y las colum­nas estén numeradas del 1 al 8):

6364546475456

Etapa 3: La partición. Inmediatamente nos vienen a la cabeza varias ideas pararesolver este problema. Primero, será útil usar las facilidades de la abstracciónGri d. Segundo, será útil declarar dos variables del tipo Gri d; por ejemplo,Gen1 (para el entramado de la izquierda) y Gen2 (para el de la derecha).

Page 196: ComputacionI A

190 Computación l. Lógica, resolución de problemas, algoritmos V programas

El programa deberá incorporar tres pasos principales para simular el Juegode la Vida. El primer paso debe inicializar los dos entramados Gen1 y Gen2,leyendo la primera parte de la entrada, y sombreando las celdas de Gen1apropiadas. El paso 2, simplemente leerá del teclado la orden de si se debecontinuar a la siguiente generación o terminar el juego. El paso 3 se encargaráde calcular la generación actual a partir de la anterior, y de mostrar el re­sultado.

El secuenciamiento de esos tres pasos puede ser gobernado por la estructu­ra iterativa que se muestra más adelante. En ella, una instrucción wh i Lecontrola el bucle, y cada repetición de éste provoca el cálculo de una nuevageneración que resulta visualizada.

{Paso 1. Inicializar Gen1 y Gen2}

{Paso 2. Leer una orden de cont ro l}

while control <> 'q' dobegin

{Paso 3. Obtener y mostrar la generación siguiente}

{Paso 4. Leer una orden de control}end¡

Donde la variable de control se utiliza para almacenar el carácter que elusuario pulsa en el teclado para indicar si se debe calcular y mostrar la próxi­ma generación. Por esta razón, el paso 4 es una repetición del paso 2; es decir,se necesita una orden distinta para iniciar el proceso y para cada repeticiónsucesIva.

El paso 1 primero crea los dos entramados con un tamaño de celda apro­piado, por ejemplo, 10 pixels, y coloca los entramados Gen1 y Gen2 en lascoordenadas apropiadas para que aparezcan uno al lado del otro. Este pasotambién necesita inicializar la variable entera n seguida de n pares de enteros iy j, en el rango 1 al 8 que designe la posición inicial de la población de lageneración 1. A diferencia de la primera parte del paso 1, esta segunda partenecesitará ser abstraida como un procedimiento -que podríamos llamarIni ciaL izar.

El paso 2 es prácticamente inmediato. Puede construirse simplemente in­cluyendo una instrucción Read que asigne el carácter de la tecla pulsada a lavariable control. El paso 3 es el más complejo del programa, por lo que se debesubdividir en varias partes. Es decir, para el cálculo y visualización de unanueva generación, primero debemos borrar el entramado que contendrá lageneración siguiente (Gen2 o Gen1, dependiendo de cuál de los dos contienela generación actual), y a continuación determinar para cada celda en esageneración cuál está «viva» y cuál no. El acto de borrar un entramado puedeabstraerse bajo el nombre de Bor ra rG r i d. La determinación de la configura­ción de la próxima generación puede abstraerse bajo el nombre Si gui ente­Generación.

Page 197: ComputacionI A

Robustez y prueba de los algoritmos 191

El procedimiento SiguienteGeneración puede subdividirse a su vezen partes, puesto que para cada celda debe contarse el número de vecinos vivosque tiene. Abstraeremos esa tarea con la función Vec i nos. El procedureNuevaGene ra c ión puede construirse anidando la función Vec i nos dentrode un bucle que examine por separado cada celda de la generación actual.Puede utilizarse una instrucción case (véase el manual de laboratorio paramás detalles sobre esta función) para discriminar entre si las cuatro reglas delnacimiento, supervivencia y muerte. Por tanto, el paso 3 tendrá la estructurade control siguiente, suponiendo que Gen1 es la generación actual, y Gen2 lasiguiente:

{Paso 3. Obtener y mostrar la generación siguiente}BorrarGrid<Gen2);SiguienteGeneración<Gen1, Gen2);

El procedimiento S; gui enteGenerac i ón tiene la siguiente estructuracuando se aplica al cálculo de Gen 2 a partir de Gen1:

for i := 1 to 8 dofor j := 1 to 8 do

case Vecinos<Gen1, i, j) of{sobrevivir: poner a on la celda i, j de Gen2}{nacimiento: poner a on la celda i, j de Gen2}{muerte: poner a off la celda i, j de Gen2}end

Donde se han establecido informalmente las distintas alternativas para evitardetalles innecesarios para este paso.

Obsérvese que los papeles de Gen1 y Gen2 serán los opuestos cuando seproduzca el cambio de población siguiente de la generación 2 a la 3. Es decir,para la generación 3 habrá que borrar el entramado Gen1 y recalcular susceldas a partir de los valores actuales de Gen2. Por tanto, para valores impa­res del número de generación (1, 3, 5, Yasi sucesivamente), el entramado Gen1mostrará la nueva generación, y para valores pares (2, 4, 6, ..., etc.). Este papello jugará Gen2. Debido a esta alternancia de papeles, Gen1 y Gen2 deben serparámetros en la implementación de las rutinas BorrarGri d, Si gui ente­Generación y Vecinos.

Paso 4: Definición de abstracciones. A continuación, resumimos las abstrac­ciones nuevas más importantes que son necesarias para este programa:

procedure Inicializar<var G: Grid);{pre: entrada = n, x" y" X2, Y2' •• -, xn , Yn }

{post: todas las celdas de G que corresponden a los pares de enterosXi' Yi se ponen a on, para todo i in 1, .. "' n, A entrada = vacia}

procedure BorrarGrid<var A: Grid);{post: todas las celdas del Grid A se ponen a off}

Page 198: ComputacionI A

192 Computación l. Lógica, resolución de problemas, algoritmos y programas

function Vecinos(G: Grid: i, j: integer): integer;{post: resultado ~ el número de vecinos vivos de la celda i, jdel grid G}

procedure SiguienteGeneración(A: Grid; var B: Grid);{post: entramado B = nueva generación de celdas vivas, calculadasdel entramado A uti l izando las cuatro reglas de nacimiento,supervivenci a,Y muerte}

El resto de las abstracciones pueden implementarse directamente a partir delos procedimientos y funciones generales disponibles para los entramados.

Etapa 5: Codificación. El código de este programa se muestra en varios frag­mentos. El cuerpo principal del programa puede verse en la Figura 6.4. Esbastante autoexplicativo, puesto que se ha obtenido a partir de las etapasprevias de la metodología MAPS.

program vi da;usesGrids;

varGen1, Gen2: Grid;control: char;Gennumero: integer;

begin{pre: entrada = n, X1, y" x2' Y2' ••• , xn, Yn, C1, e2, .... , Cm 1\ ClII = Iql A

n > O 1\ m> O pa ra todo i in {1, ••. , n}: 1 <:; x;, y; <:; 8}

{Paso 1. Inicializar Gen1 y Gen2}WriteLn( 'El juego de la Vida');StarsGrids;SetUpGrid(Gen1, 8,10,10, 10};SetUpGrid(Gen2, 8, 120, 10, 10};Inicializar(Gen1);

{Paso 2. Leer una orden de control}gennúmero:= 1; {lleva el control del número de generación}WriteLn( 'pulsar <RET> para ver la generación', gennumero + 1 :3);WriteLn( 'pulsar "q" para terminar');Read(control);while control <> 'q' do

begin

{Paso 3. Calcula y visualiza la generación siguiente}if gennumero IIOd 2 = 1 then

beginBorrarGrid(Gen2); {las generaciones pares en el grid derecho}SiguienteGeneración(Gen1, Gen2);

endelse

beginBorrarGrid (Gen1 ); {las generaciones impares en el gri d i zqui erdo}SiguienteGeneración(Gen2, Gen1);

end;

Page 199: ComputacionI A

Robustez y prueba de los algoritmos 193

{Paso 4. Leer una orden de cont ro l )gennúmero + 1;WriteLn( 'pulsar <RET> para ver la generación', gennumero + 1 :3);WriteLn( 'pulsar' 'q" para terminar');Read(controL> ;

end

{post: salida = una serie de m-1 imágenes del Juego de la Vida,donde la primera imagen está determinada por las n celdas(x" y,), (x" y,) ••• , (xn, Yn)' y cada imagen sucesiva presentala i-ésima generación que se obtiene de la (i - 1)-ésima al aplicarlas reglas de nacimiento, supervivencia y muerte. El final deljuego lo provoca el usuario pulsando 'q' (de 'quit').)

end

Figura 6.4. Cuerpo del programa principal del programa Vi da.

Obsérvese que el paso 3 tiene dos partes alternativas. Una que se ejecuta alcalcular una generación par, y la otra al calcular una impar. Esto se obtienedirectamente de la idea de los «papeles invertibles» de los entramados Gen1 yGen2. La variable gennumero lleva la cuenta de la generación que se estácalculando y visualizando.

Las rutinas nuevas que se utilizan en este programa se muestran a conti­nuación. La primera es la rutina 1ni e; aL; za r, que se muestra en la Figu­ra 6.5. Simplemente pone a on cada celda del entramado G que se indica por lafila y columna.

procedure Ini c i a l i zar (val' G: Gr i d);val'

k, n, i, j: integer;begin{pre: entrada =0, x" y" XZ, Y2' a •• , Xn , Yn }

Writeln('Introducir el número n de celdas inicialmente vivas:');Read(n);Writeln(' Introducir una serie n de pares de enteros');Writeln('indicando cada uno las coordenadas x, y de una celdavi va. ' );for k :~ 1 to n do

beginrepeat

read(i, P;until (1 <= i) and (i <= GridSize(G» and

(1 <= j) and (j <= GridSize(G»;TurnCellOn(G, i, j);

end;{post: todas las celdas de G que corresponden a los pares de enteros

Xi' Yi se ponen a on para todo i in 1, ..• , n /\ entrada = vacía)

Figura 6.5. La ruti na 1ni e i a l iza r.

Page 200: ComputacionI A

194 Computación l. Lógica, resolución de problemas, algoritmos y programas

Además, obsérvese que el procedimiento IniciaLizar lee reiteradamentepares de enteros i, j hasta que el par represente una celda válida del entra­mado G. Es decir, si i o j estuvieran fuera de rango de filas y columnas de G, elpar se vuelve a leer. Esto es un ejemplo de la construcción de programasrobustos y amigables. 'La segunda rutina, 80 r ra rG r id, realiza la sencilla tarea de poner a offtodas y cada u¡na de las celdas del entramado G. Esto se muestra en la Figu­ra 6.6.

p ..ocedu..e Bo....a ..Gr-id (va.. A: Grid);(post: todas las celdas del Gr-id A se ponen a off}

va"i,j:intege.. ;

beginfa .. i := 1 to Gr-idSize(A) do

fo .. j := 1 to GridSize(A) doTu ..nCellOfHA, i, j)

end;

Figura 6.6. La rutina BorrarGrid.

La rutina Vec i nos, de la Figura 6.7, cuenta el número de vecinos vivospara la celda i, j del entramado G. Obsérvese que se considera vecina acualquier celda viva a la que se acceda directamente desde la celda i, j poruno de sus cuatro lados, o por una de sus cuatro esquinas. Por tanto, cadacelda puede tener como máximo ocho vecinas. Sin embargo, las celdas que seencuentran en los bordes del entramado G tienen menos de ocho vecinos. Porejemplo, la celda 1,1 no tiene más que tres vecinos, y la celda 1,2 no tienemás que cinco. Para asegurarnos de que la rutina calcula valores correctospara esos casos, debemos saber que la rutina Ce LLOn (k, L>, que se suminis­tra con el tipo Grid, devuelve el valor faLse siempre que el par k, L no secorresponda con una celda de G. Por ejemplo, si k = O o L = O Ce LLOn (k,L) = fa Ls e. Podemos cerciorarnos de esto viendo la especificación de larutina CeL LOn (véase Apéndice D).

function Vecinos(G: grid; i, j: integer): integer;var

k, l, con t: i nt ege r;begin

cont := O;for k : = i - 1 to i + 1 do

for l := j - 1 to j + 1 doif CellOn(G, k, l) and not ((k ~ i) and (L = j» then

cont := cont + 1;Vecinos := cont

: post: resul tado = eL número de vecinos vivos de la celda i, j del grid G:

Figura 6.7. La rutina Vecinos.

Page 201: ComputacionI A

Robustez V prueba de los algoritmos 195

Finalmente, la rutina Si gui enteGeneraci ón (véase Fig. 6.8) calcula lasceldas vivas para la siguiente generación del entramado B, a partir de la gene­ración actual del entramado A. Incluye una interpretación detallada de lascuatro reglas de supervivencia, nacimiento y muerte.

Etapa 6: Prueba. Para probar este programa suficientemente, necesitamosdiseñar una serie de éasos de prueba, que no sólo prueben el Juego de la Vidapara unas configuraciones iniciales inusuales, sino también otras que suminis­tren datos de entrada no válidos. Queremos asegurar que nuestro programa estan robusto como correcto. Un paso inicial es ejecutar el programa para unaentrada conocida, tal como la de la Figura 6.2. ¿Producirá el programa lasalida correcta para la generación 2?, ¿y para la 3 y sucesivas?

A continuación, debemos probar el programa con otras entradas, especial­mente aquellas que representan poblaciones con una evolución fácil de prede­cir, tal como la que se muestra en la Figura 6.9. Esta configuración es intere­sante porque prueba la corrección del programa cuando las celdas vivasocupan los bordes.

procedure SiguienteGeneración (A: Grid; var B: Grid);var

i, j, cont: integer;begin

for i := 1 to GridSize(A) dofor j :~ 1 to GridSize(A) do

case Vecinos(A, i, j) of{RegLa 1. Supervivencia}

2, 3:if CeLLOn(A, i, j) then

TurnCeLLOn(B, i, j){RegLa 2. Nacimiento)

else if (Nacimiento(A, i, j) = 3) and(CeLlOff(A, i, j))

then TurnCellOn(B, i, j);{Regla 3. Muerte por soLedad)

O, 1 :if CellOn(A, i, j) then

TurnCellOff<B, i, j);{Regla 4. Muerte por superpobLación}

4,5,6,7,8:if CeLLOn(A, i, j) then

TurnCeLLOff(B, i, j);end

{post: entramado B =nueva generación de ceLdas vivas, caLcuLadasdel entramado A utiLizando Las cuatro regLas de nacimiento,supervi venci a y muerte}end;

Figura 6.8. La rutina SiguienteGeneración.

Etapa 7: Presentación. La presentación del programa está completa cuando seha preparado un esbozo de su propósito general, junto con un listado del

Page 202: ComputacionI A

196 Computación l. Lógica, resolución de problemas, algoritmos y programas

propio programa y con las salidas de algunas ejecuciones como ejemplo. Elesbozo debe contener no sólo un resumen de lo que hace el programa, sinotambién de cómo trata las situaciones excepcionales, junto con otras limitacio­nes que el usuario se pueda encontrar.

a) b)

Figura 6.9. Un caso de prueba diferente para el Juego de la Vida.a) Primera generación. b) Segunda generación.

Ejercicio

6.6. Obtener a mano las generaciones 2 y 3 para las generaciones inicialessiguientes.

a) b) e)

6.4. GARANTíA DE LA ROBUSTEZ: DISEÑO DE CASOSDE PRUEBA

La metodología de resolución de problemas MAPS proporciona una estructu­ra que, si se manipula cuidadosamente, puede conducirnos a la obtención deprogramas robustos -programas que no sólo funcionan bíen para entradascorrectas, sino que también se comportan «elegantemente» para un amplio

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 203: ComputacionI A

Robustez y prueba de los algoritmos 197

rango de entradas incorrectas-o Una etapa fundamental de la metodologíaMAPS es la etapa 6, o etapa de prueba y verificación. Esta es una etapa que, ennuestro camino, puede que sea la más critica de todo el proceso. Si un progra­ma resulta no ser correcto como resultado de la aplicación sistemática demétodos de prueba y/o verificación, todas las etapas anteriores de la metodolo­gía MAPS habrán sido inútiles. En las Secciones 6.4 y 6.5 introduciremosmétodos esp¡::cificos para llevar a cabo en esta importante etapa de prueba yverificación. La discusión de estos temas concluye con una evaluación compa­rativa de la utilización de ambos métodos en la construcción del software.

Un conjunto ya clásico de técnicas para asegurar la corrección, robustez yamigabilidad de los programas, se incluye bajo el nombre genérico de prueba.Las técnicas de prueba han sido desarrolladas por diseñadores e ingenieros delsoftware durante las últimas décadas.

Definición. La prueba de un programa es la aplicación sistemática de casosde prueba al programa, procedimiento o función, con el objetivo de detec­tar y corregir los errores (o «fallos») del programa. Los casos de pruebaconsisten en distintos conjuntos de valores de entrada, elegidos intenciona­damente para analizar el comportamiento del programa bajo unas condi­ciones que pueden o no haber sido sugeridas por el diseñador del progra­ma. Conjuntamente, todos los datos que están incluidos en esas pruebasreciben el nombre de juego de pruebas.

El resultado de la prueba ofrece menores garantías que la de la verificación. Esdecir, la prueba, por su naturaleza limitada, no asegura la ausencia de errores-sólo puede poner de manifiesto los errores presentes.

Para que sea eficaz, la prueba debe realizarse por una persona distinta a laque construyó el programa. Esto es importante, porque una persona ajenapuede ser bastante más objetiva sobre el comportamiento del programa que lapersona que lo ha desarrollado.

Existen varias formas de diseñar juegos de prueba y de aplicarlas a unprograma o a un procedimiento concreto. Son necesarias estrategias de pruebamás largas cuando se trata de probar programas construidos con extensosconjuntos de instrucciones, que cuando tratamos de probar casos de estudio.En esta sección nos concentraremos en el diseño y aplicación de métodos deprueba rigurosos para programas relativamente pequeños, dejando para elVolumen II de esta serie los métodos de prueba del software de gran escala.

6.4.1. Ejemplo: Prueba de un procedimiento o funcióncompletos

Cuando desarrollamos una abstracción procedimental para un problema biendefinido, o para una rutina, es necesario probarla ejecutando el procedimientosuministrándole una amplia gama de valores a los parámetros de entrada, y

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 204: ComputacionI A

198 Computación l. Lógica, resolución de problemas, algoritmos V programas

asegurándonos de que, en cada caso. el resultado del procedimicnto es consis­tente con sus poscondiciones.

Puesto que es imposible probar (odos los posibles valores de entrada. ten­dremos que seleccionar un subconjunto de ellos que sea significativo, y ejecutarel programa e imprimir el resultado con cada uno de los elementos de esesubconjunto. Una forma bastante útil de realizar este proceso es construir unprograma cO/lductor. Se denomina así porque, literalmente. «guia» la ejecucióne impresión de resultados del procedimiento o función con los valores seleccio­nados para la prueba.

Ilustremos estas ideas construyendo un juego de pruebas para la funciónMaxL i sta (véase Figura 5.12). ¿Cuál seria un conjunto de pruebas apropiadopara esta función, y cómo podemos diseñar un conductor para estudiar elcomportamiento de MaxL i sta frente a estos datos?

Los juegos de prueba pueden crecer rápidamente. Consideremos el númerototal de posibles entradas válidas que podríamos construir para la funciónMaxL i sta, utilizando O ó más elementos. Supongamos que cada elemento esun entcro en el rango - 2':; al 2':; - 1, habrán 2\6 = 65.536 listas diferentesde un solo elemento. El número de posibles listas diferentes de /l elementosresulta astronómico --seguramente excesivo para incluirlas en un juego depruebas.

Pensemos un momento sobre algunas posibles listas que pueden ser pasa­das a MaxLista. y a lo que esperamos que MaxLista produzca como res­puesta. En la Tabla 6.2 se ofrecen algunas ejemplos obvios.

Tabla 6.2

Parámetros de entrada L

(3 1 2 8)

(8 1 2 3)

(3 8 1 2)

(-1 ·2··3 -8)

(3 1 2 8)

(3 1 2 8)

(3 2 8)

m

4

4

4

4

3

2

Resultado esperado

4

2

Los dos primeros datos de pruebas son importantes porque el valor máximoocupa la última y primera posición de la lista. respectivamente. El tercer casotambién es importante. pues representa el caso típico que puede ocurrir---es

Pedro Pacheco
Highlight
Page 205: ComputacionI A

Robustez y prueba de 105 algoritmos 199

decir, el valor máximo ocupa una posición cualquiera entre el primero y elúltimo elemento de la lista--. El cuarto comprueba si MaxL i s ta trabajacorrectamente con valores negativos. Los tres últimos son importantes, puestoque restringen el valor de m forzando a la función a buscar el máximo en unasublista.

Pero, ¿qué otras cosas deben introducirse en un juego de pruebas~ Eviden­temente, debem9s asegurarnos de que la lista vacía ( ) devuelva el valor O.¿Qué hacer con los otros incontables casos que se nos pueden presentar?¿Cómo presentar a MaxL i sta un subconjunto de esos casos que nos asegureque el procedimiento hace lo que debe? Así mismo, ¿cómo podcmos probar larobustez y amigabilidad de Ma xLi s ta? Es decir, ¿cómo se comportará Ma x­Lista con entradas como la lista (-1, -2, hoLa, -8)? ¿ü ante un valorde L, como I hoLa I o I asrtfadesr I o 3332123442 que no sean unalista? Debemos añadir todos esos casos a nuestro juego de pruebas para deter­minar cómo responde MaxL i sta.

Por tanto, debemos ser muy selectivos al diseñar los juegos de pruebapara un procedimiento. Sólo debemos incluir en los juegos de pruebas aquellasentradas que representen a un gran número de casos posibles. Es convenientealmacenar aparte nuestro juego de pruebas en un archivo de disco, de formaque no necesitemos reescribirlo cada vez que queramos probar el procedi­miento.

En la Figura 6.10 se muestra la estructura general dc un conductor depruebas. En la notación utilizada <p (x, y) > simboliza a un procedimiento pcon parámetros de entrada x y parámetros de salida y; <archivo juegosprueba> simboliza al archivo del que se pueden obtener los juegos de prueba.Esta estructura es fácilmente adaptable para el caso en que lo que deseemossca probar una función f (x) en lugar de un procedimiento p (x, y); en estecaso la variable y se identifica con la salida de la función, la instrucción <p (x,y» se sustituye por y := f(x) en el conductor de la Figura 6.10, y loscomentarios se modifican para indicar que se prueba una función en lugar deun procedimiento.

program conductor;(Este programa conductor prueba eL procedimiento <p(x, y»}{ut i Lizando un juego de pruebas como datos de ent rada}(deL archivo <archivo juego pruebas>}

procedure <p(x, y»;begin

end;

var <variabLes correspondientes a Los parámetros>;<archivo juego pruebas>: text;

beginWriteLn(' Comi enza La prueba deL procedimi ento <p(x, y»');read«archivo juego pruebas», <x»;while not eof«archivo juego pruebas» do

Pedro Pacheco
Highlight
Page 206: ComputacionI A

200 Computación l. Lógica, resolución de problemas, algoritmos y programas

beg;nWrHeLn('Parámetros de entrada = " <x»;

<p(x, y»;Wr; teLn(' Resul tado de p(x, y) =' , <y»;read«arch;vo juego pruebas>, <x»;

end;WrHeLn( 'F;nal de la prueba del proced;m;ento <p(x, y»')

end.

Figura 6.10. Estructura general de un conductor de pruebas.

Supongamos que se quiere probar la función MaxL; sta utilizando unprograma conductor y el archivo de juegopruebasmax que contiene laslistas siguientes:

(3 1 2 8) 4(8 1 2 3) 4(3 8 1 2) 4(-1 -2 -3 -8) 4(3 1 2 8) 3(3 1 2 8) 2(3 1 2 8) 1(-1 -2 hello -8) 4() O

Los enteros que aparecen a la derecha no están almacenados en el archivo,sino que son escritos por el usuario cuando el conductor se lo solicita. Elprograma conductor siguiente podría ser eficaz:

program Conductor;{Este prog rama conductor prueba la fune; ón MaxU sta ut H ; zando un

juego de pruebas como datos de entrada del arch;vo juegopruebasmax}

function MaxUsta(L: Usta; m: integer): integer;val' j, k: ;nteger;

begin{pre: L = (e1 , e 2 , •• _, em, •• _, en) A n ~ O 1\ cada e i es un número}if (O < n) and (m <= LengthUsta(L» then

beginj := 1;for k := 2 to m do

{; nv: v; E {1, ... , k - 1 }: e [j] >= e [;] /\ 2 <= k <= m+ 1 }if L[k] > L[j] then

j := k;end

elsej := O;

MaxUsta := j;(pos t: n > O /\ v; E {1, ... , n}: e j ;;O e, /\ re su l tado = j vn = 0/\ resul tado = O}

end;

Page 207: ComputacionI A

Robustez y prueba de los algoritmos 201

varL: Lista;m, j: integer;juegopruebasmax: text;

beginWriteLn( 'Comienza la prueba de la función MaxLista(L, m)');WriteLn('Introducir el nombre del archivo del juego de pruebas: ');ReadLista(U;while not eof(juegopruebasmax) do

beginWriteLn( 'Lista de entrada L ='); WriteLista(U;Write(Introducir valor de m: '); ReadLn(m);j := MaxLista(L, m);WriteLn('Resultado de MaxLista(L, m) ~ " j);ReadLista(U;

end;WriteLn('Final de la prueba de la función MaxLista(L, m)end.

La salida que produce este conductor cuando se le suministra el archivo j ue­gopruebasmax se muestra en la Figura 6.11.

Comienza la prueba de la función MaxLista(L, m)Introducir el nombre del archivo del juego de pruebas:milistaLista de entrada L =(3 1 2 8)Introducir valor de m: 4Resultado de MaxLista(L, m) = 4Lista de entrada L =(8 1 2 3)Introducir valor de m: 4Resul tado de MaxLista(L, ro) = 1

i.. i sta de entrada L =OInt roduci r va lar de ro: OResultado de MaxLista(L, ro) = OFinal de la prueba de la función MaxLista(L, ro)

Figura 6.11. Resultado de ejecutar el conductor de pruebas parala función MaxL ista, con el archivo de entrada juegopruebasmax.

Como puede verse, la construcción y utilización de un conductor de prue­bas es casi un proceso mecánico. Sin embargo, cuando se utiliza con cuidado,no sólo nos permite descubrir errores ocultos, sino que nos sugiere formas deconseguir que el programa sea más robusto y amigable. j Utilizar el procesa­miento con un juego de datos desconocido puede conducirnos a resuÍtadossorprendentes! Sin embargo, es preferible realizar esos descubrimientos en elmomento de la prueba, que no después, cuando se ha entregado el procedi­miento a una persona desconocida para cualquier utilización.

Pedro Pacheco
Highlight
Page 208: ComputacionI A

202 Computación l. Lógica, resolución de problemas, algoritmos y programas

6.4.2. Ejemplo: Prueba de un programa completo

Debemos probar los programas «de abajo a arriba». Es decir, debemos probartodos los procedimientos y funciones antes de probar el programa que losutiliza. Después de realizar esto, podemos proceder a la prueba del programacompleto en la misma forma en que probamos un procedimiento. Para cllo,convertimos e' programa en una especie de autoconductor de si mismo, aña­diéndole un bucle externo que lea sistemáticamente datos de entrada alternati­vos desde un archivo externo que contenga un juego de pruebas, y despuésprosiga con su ejecución normal, produciendo las salidas a todas las entradasdel juego de pruebas, en lugar de la salida de un único juego de datos.

Por ejemplo, considérese el programa Ca Lcu La CM, de la Figura 4.6, el cualmodificamos para ser más amigable (véase Sección 6.1). Para probar este pro­grama, podemos convertirlo en el autoconductor que se muestra más abajo, yejecutarlo con los datos de el archivo que contiene varias listas de calificacio­nes alternativas, en lugar de sólo una. El resultado de convertir este programaen amigable y en un autoconductor, se muestra en la Figura 6.12. Para conver­tirlo en autoconductor, basta con añadirle un bucle repea t abarcando las prey poscondiciones del programa. Esta modificación hace que el programa lea yprocese entradas hasta que lea una lista vacia 0, lo que señala el fin de lasejecuciones de prueba.

program caLcuLaCM;uses

Listas;var

Notas: Listas;i, n: integer;Sum, CM: reaL;entradaváLida: BooLean;

beyinrepeat{pre: entrada = (Notas" Notas" ... , Notas") 1\ n > O

1\ \1'i E {1, .""' n}: Notas, E (O, .. "' 4}}repeatWriteLn ('Introducir La Lista de caLificaciones:');ReadLista(Notas);n :~ LongLista(Notas);entradaváL ida :~ true;for i :~ 1 to n do

if not isNumeric(Notas[i] or Notas[i] < O) or (Notas[i] > 4) thenentradaváL ida := faLse;

until entradaváLida;if n > O thenbeyin

Sum :~ O:i := 1;whi le i <= n do

beginSum := Sum + Notas[i];

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 209: ComputacionI A

Robustez y prueba de los algoritmos 203

i := i + 1end

CM = Sum/n;WriteLn('La CM de esas caLificaciones es=', CM: 5: 2)

end {i f}{post entrada =0"saLida=Sumi E {1, ... ,n}:Notas;ln}

untiL n ~ O;end.

Figura 6.12. Un autoconductor para la versión amigable del CaLcuLaCM.

6.5. GARANTíA DE CORRECCiÓN: VERIFICACiÓNDE PROGRAMAS

Como metodología general, la veríficacíón de programas tíene como objetívola aplícacíón de la lógíca matemática, para demostrar formalmente que elprograma incluido entre la precondicíón y la poscondición cumple esas especi­ficaciones bajo cualquier circunstancía de ejecución posible. En este sentido, laverificacíón formal es un logro relativamente nuevo en el área del software.Pienso que es importante tener unos conocimientos básicos de la verificaciónformal, sus métodos y sus objetivos. De todas formas, esta materia está en un«punto de corte» de la investigacíón en informática. La verificación de progra­mas proporciona a los lectores un punto de vista alternativo sobre la correc­ción de los programas, que pone de manifiesto uno de los mayores defectos delas técnicas de prueba clásicas: éstas nunca garantizan la corrección.

El estilo de verificación que utilizaremos es informal, resaltando los funda­mentos más que explicando el proceso de demostracíón con mucho detalle.Partimos de la hipótesis de que las propiedades algebraicas de los números,con las que estamos familiarizados, se preservan cuando se utilizan los núme­ros en programación. Sabemos que es una restricción bastante fuerte. Sabe­mos, por ejemplo, que en los números -reales o enteros- no tiene una repre­sentación exacta en los programas Pascal. Sabemos también que, enmatemáticas, las operaciones entre reales y enteros siempre producen resulta­dos exactos, mientras que en computación se introducen a veces pequeñoserrores. Para el propósito de esta introducción, ignoraremos estas pequeñasdesviacíones, con objeto de simplificar la presentación de la verificación ycentrarnos en los principios y en la metodología.

6.5.1. Tableau de demostración

Para verificar un programa, desarrollamos una prueba del tableau. Un comien­zo de prueba del tableau, o «tableau vacío», es un listado del programa con susprecondiciones, poscondiciones y comentarios vacios antes y después de cada

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 210: ComputacionI A

204 Computación l. Lógica, resolución de problemas, algoritmos y programas

instrucción, tal y como se muestra en la Figura 6.13. El objetivo de la verifica­ción es rellenar este tableau con asertos válidos. Cada instrucción del progra­ma debe preceder y seguir a un aserto, y debemos demostrar, siguiendo unalínea sistemática de razonamiento, que la instrucción conduce de una situaciónque satisface el aserto que le precede al que le sigue, partiendo de otros cuyavalidez ya ha sido demostrada. Así, la verificación de un programa es unproceso en el que se desarrollan una serie de asertos (y razonamientos que lesacompañan) en una forma similar al de las demostraciones de la lógica (comovimos en el Capítulo 3). El resultado de este proceso se denomina demostraciónde la corrección del programa, o simplemente demostración.

El proceso por el que descubrimos sistemáticamente la validez de los aser­tos que componen una prueba, se le denomina razonamiento sobre programas.Podemos definir esas ideas más formalmente como sigue:

Definición. Una demostración es un conjunto de asertos P1 , Pu ... ,Pr>+1' que, cuando se insertan sucesivamente entre las instrucciones 51' Su

••• , sn en un tableau vacío, dan origen a la siguiente prueba de tableau:

begin(precondiciones}{P,}, 5,; {P2}, 52; ••• ; {Pn}' Sn; {Pn+,}(poscondiciones}

end

Donde los asertos siguientes son válidos (es decir, tautologías):

1. precondi ciones =<> P,2. {P;}, s,, (P '+1} para todo i en (1, ••. , n}3. P0+' =<>poscondi ciones

La notación {P;} s; {P H1} quiere decir que, respecto de la ; -ésima ins­trucción del programa, si P; es válido antes de la ejecución de S;, el asertoP H1 será válido después de la ejecución de s;. En otras palabras, Pi y P H1son, respectivamente, precondición y poscondición de la instrucción s;.

Supongamos que tenemos el programa y el tableau vacío de la Figura 6.14. Esdecir, queremos demostrar la corrección del programa que se ha diseñado paracalcular y escribir el resultado del producto de dos números cualquiera n1 Yn2.

Para completar la demostración, necesitamos descubrir y justificar los aser­tos p1 al P4 del tableau, uno a uno, hasta rellenarlo. El resultado se muestra enla Figura 6.15. Las justificaciones que aparecen en la columna de la derecha dela Figura 6.15 son el resultado de aplicar equivalencias lógicas y reglas deinferencia a la secuencia de instrucciones de Pascal. Algunas de esas justifica­ciones (por ejemplo, aritméticas) se basan en las hipótesis comunes que sesuelen realizar en la aritmética. Otras (por ejemplo, A -introducción) se hantomado de las reglas de inferencia de la lógica (véase Capítulo 3). Otras (por

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 211: ComputacionI A

Robustez y prueba de los algoritmos 205

begin

(pre: precondición)

5,;

(post: poscondición);

Figura 6.13. Aspecto inicial de una prueba de tableau: el tableau vacío.

ejemplo, la regla de la asignación) reflejan las propiedades de algunas instruc­ciones de Pascal (véanse Secciones 6.5.2 a 6.5.5), y las estudiaremos en estecapítulo.

La demostración completa del tableau refleja el estilo de las demostracionesde la lógica, tal como se vio en el Capítulo 3.

begin

{pre: entrada = n1, n2 /\ salida =0l( @)

Read (x, y);---

{ @z:=x*y;~

{ @YWrite (z) ---­

( )

{post: entrada =0/\ salida = n1 * n2

end.

Figura 6.14. Tableau vacío para un sencillo programa de tres instrucciones.

Page 212: ComputacionI A

206 Computación l. Lógica, resolución de problemas, algoritmos y programas

6.5.2. La regla de inferencia de la asignación

Al igual que otros métodos de demostración, la verificación de programasutiliza los axiomas y las reglas de inferencia. Las reglas de inferencia songeneralizaciones sobre el comportamiento de determinados tipos especificos deinstrucciones de los programas en Pascal. Estas reglas aportan métodos conlos que derivar asertos nuevos, a partir de otros existentes, para algunas ins­trucciones específicas.

begin

{pre: entrada ~ n1, n2 /\ salida =0}

~{entrada~n1,n2 }

QY Read (x, y);.. @[entrada =0/\ x = n1 /\ y = n2 /\ x*y = n1*n2)® z:~x*y;.. @{x = n1 /\ y = n2 /\ z = n1 *n2 /\ sa l i da = 0® Write (z) .. @{z = n1 *n2 /\ sa l i da = n1 *n2 }

® {post: entrada =0/\ salida ~ n1 * n2 }

Jus! ¡Cica! iuus

{A-eLiminación

i regla de la asignación,aritmética,/\-introducción}

{regla de la asignación,A-eliminación,/\-introducción}

{regla de la asignación,/\-el iminación}

{/\-eliminación,/\-introducción}

Figura 6.15. Prueba del tableau completapara un programa sencillo.

En la verificación formal de programas, el sistema de inferencias, y concre­tamente las reglas de inferencia, son mucho más complicadas que las que sehan presentado aquí. Consideremos cuatro reglas de inferencia básicas para losprogramas: la regla de la asignación, la regla de los procedimientos, la regla delas condicionales y la regla de los bucles.

Definición. La regla de inferencia de la asignación.

a) {P(e)} v := e { }

{P(e)} v := e {P(v)}

b) {entrada ~ n} Read(v) { }

[entrada ~ n} Read(v) {entrada = 0 /\ V = n}

e) [salida=0/\e=n} Write(e):}

[salida ~0 /\ e = n) Write(e) {salida = e}

Pedro Pacheco
Highlight
Page 213: ComputacionI A

Robustez y prueba de los algoritmos 207

El apartado a) de esta regla dice que si una proposición es válida para elestado de una expresión e (la satisface) antes de que la instrucción deasignación v : = e sea ejecutada. Podemos inferir que la misma proposi­ción es válida para la variable y después de la ejecución de la asignación.

Los apartados b) y e) simplemente destacan el hecho de que las instruc­ciones Read y Wr; te producen el mismo efecto que la asignación. En lainstrucción .Read, el origen del valor para la asignación es el flujo deentrada, y el receptor la variable v. En la instrucción Wr; te, el origen delvalor es la expresión e, y el destino el propio flujo de salida. Más concreta­mente, el apartado b) significa que la instrucción Read retira un valor n delflujo de entrada, y se lo asigna a la variable v. El apartado e) indica que lainstrucción Wri te(e) añade una copia del valor n, que actualmente es elresultado de evaluar la expresión e, al flujo de salida. Esto no es más queuna formalización directa de lo que ya conociamos de la actuación deRead y Wr; te en nuestros programas.

Por ejemplo, en el programa de la Figura 6.14, supongamos que lo únicoque conocemos antes de la ejecución de la instrucción de asignación z : = x * y,es que los valores de x e y son dos números n1 y n2. Por las reglas de laaritmética, también sabemos que x * y = n1 * n2. Podemos utilizar estosconocimientos en la forma siguiente:

{x*y~nl*n2}

z:=x*y;{z=n1 *n2} {regLa de La asignación}

Lo único que hemos hecho, al realizar esta inferencia, ha sido poner z en todaslas ocurrencias de x * y en la proposición ya conocida P(x * y) para poderobtener P(z >. Obsérvese que se ha marcado esta inferencia de la demostra­ción, con una justificación situada a la derecha, para clarificar las razones de lainferencia realizada. Esto es consistente con el estilo de las demostraciones dela lógica.

Está claro que esta regla es fácilmente extensible para instrucciones Read yWr; te, con más de una variable, para las instrucciones ReadLn, Wr; tLn,ReadL; sta y Wr; teL; sta, y así sucesivamente. Por simplicidad, no re­cargaremos esta regla tratando de formalizarla para todas esas situaciones,aunque la utilizaremos en nuestras demostraciones como si lo hubiéramoshecho.

Como ejemplo adicional, consideremos la primera instrucción del progra­ma de la Figura 6.14, para la que se cumple lo siguiente cuando razonamossobre ella:

{ent rada ~ n1, n2)Read(x, y);

{ }

Page 214: ComputacionI A

20S Computación l. Lógica, resolución de problemas, algoritmos y programas

La parte b) de la regla de la asignación nos permite escribir la inferenciasiguiente:

(entrada = n1, n2]Read(x, y);

{entrada =0/\ x = n1 /\ y ~ n2} {regla de la asignación}

Lo que justifica formalmente que se les asignan valores a x e y, utilizando lainstrucción Read, y los valores son eliminados, simultáneamente, del flujo deentrada.

De forma similar, podemos razonar sobre la instrucción Wr i te, de laFigura 6.14, utilizando el apartado e) de la regla de asignación. Comencemoscon:

{z = n1 * n2 /\ sal ida =0}Wr ite (z);

{

Lo más importante de esta inferencia es que z debe tener el valor n1 * n2,para que dicho valor pueda aparecer en el flujo de salida. Podemos escribiresta conclusión formalmente utilizando la regla de la asignación de la formasiguiente:

{z = n1 * n2 /\ sal ida =0}Write(z);

{salida=n1 *n2} {regla de la asignación}

El razonamiento sobre programas siempre requiere que utilicemos activa­mente nuestros conocimientos sobre aritmética, aunque no reflejemos los deta­Hes de este conocimiento durante el proceso de la demostración. Aqui presen­tamos otro ejemplo. Supongamos que sabemos que el valor de la variable i esno negativo, inmediatamente antes de que se ejecute la asignación i := i + 1en un programa. ¿Cómo nos puede ayudar la regla de la asignación a razonaracerca de esto? Formalmente comenzamos con:

{i ~ O]i:=i+1;

{i > Ol {Regla de la asignación, aritmética}

Si analizamos detenidamente los detaHes de esta asignación, descubriremosque si i ?> O, antes de la asignación, entonces ; + 1 ?> 1. Así, para utílizar laregla de la asignación identificamos las variables v e i + 1 con la expresión e,y el aserto P(e) con i + 1 ?> 1. Por todo ello, podemos inferir P(v) o i ?> O.Aplicando de nuevo las reglas de la aritmética, podemos reescribir el asertosólo en términos de la variable i, lo que nos conduce a i > O.

Page 215: ComputacionI A

Robustez y prueba de los algoritmos 209

6.5.3. Reutilización de las reglas de inferencia de la lógica

Cuando escribimos la demostración de un programa, además de las reglas quedefinen el comportamiento del programa y la aritmética, utilizamos las reglasde inferencia de la lógica que estudiamos en el Capitulo 3. Esas reglas nospermiten «mover» los asertos a lo largo del programa, lo que permite utilizar­los para escribir nuevas inferencias en otros puntos del programa. Por tanto,podemos conseguir una línea de razonamiento coherente que incluya a todo elprograma, desde el principio hasta el final.

Para ilustrarlo, consideremos el programa de la Figura 6.15. Obsérvesecómo se utiliza la regla de la asignación para construir ciertas partes de losasertos del P1 al P4' Pero, ¿qué ocurre con sus interconexiones? Por ejemplo,¿cómo justificar la migración del aserto ent rada = 0 desde P2, donde seorigina, saltándose P3 y P4' Yapareciendo finalmente en la poscondición dondese necesita para que la prueba esté completa? Aunque la regla de la asignaciónno nos permite realizar esta migración, las reglas de inferencia de la lógica, sí.

El primer paso de la demostración de la Figura 6.15 contiene el aserto P1

{ent rada = n1, n2}

que se infiere de la precondición, utilizando la /\ -eliminación

{ent rada = n1, n2 " sa l i da =0}

La derivación de P2 es el resultado de la combinación de tres pasos diferentes:la regla de la asignación, las propiedades de la aritmética, y la regla de in­ferencia de la 1\ -introducción. En concreto, la proposición x*y = n1 *n2aparece en P2 como preparación para la derivación de los asertos P3 de P2

y S2'

Las reglas de la /\ -introducción y de la /\ -eliminación se utilizan tambiéna lo largo de la prueba. Sin embargo, esas reglas de inferencia deben aplicarsecon cuidado cuando el predicado que se va a añadir viene de una posicióndistante del programa. Por ejemplo, considérese la reintroducción del asertosa l i da =0 en la proposición P3 después de haber desaparecido de las propo­siciones P1 y P2. Esto es posible hacerlo si en el programa no se han ejecutadoinstrucciones que invaliden este predicado: es decir, alguna instrucción Wr i te(o, de forma equivalente, alguna aplicación del apartado e) de la regla deasignación) entre la última posición en que el predicado era válido y la instruc­ción donde se reintroduce.

6.5.4. Reglas para las condicionales

Los programas incluyen otros tipos de instrucciones, aparte de las que asignanvalores a las variables. Cuando se pretenden escribir demostraciones sobre losprogramas, es necesario conocer axiomas para poder razonar sobre selecciones

Page 216: ComputacionI A

210 Computación l. Lógica, resolución de problemas, algoritmos V programas

condicionales (instrucciones i f), invocaciones a procedimientos y funcionessobre bucles. Existen reglas de inferencia que son aplicables a estas instruccio­nes.

Definición. La regla de inferencia de la selección condicional.

a) ;P 1\ 6} 5 {Q)

PI\-6o>Q

{Pi if 6 then 5 {Q)

b) {P 1\ 6) 5, {Q }

{P 1\ -6) 5, {Q )

{Pi if 6 then 5, el5e 5, {Q}

El apartado a) permite inferir la validez de Q tras la ejecución de la selec­ción condicional, si podemos inferirla independientemente de cuál alterna­tiva se haya seguido -en una tanto, P como B son verdaderas, y se ejecutala instrucción s; y en la otra, B es falso, y P =Q es también válido-o Elapartado b) es simplemente una extensión del a), en la que se establece lavalidez de q, independientemente de cuál de los dos caminos alternativos sehaya seguido -ejecución de S1 (cuando B es ve rdade ro), o la de S2

(cuando B es fa Lso).

Consideremos las asignaciones y selección condicional siguientes, que sehan diseñado para asignar a la variable z el mayor de los valores x o y:

z := x;if x <~ y then

z :~ y

Para verificar esto, tenemos que establecer la validez del aserto Q:

Q = {z = X 1\ X > y v z ~ y 1\ X <~ y)

Que es una manera más formal de describir la salida que deseamos para z. Lasinslrucciones de asignación y la selección condicional están en secuencia, porlo que necesitamos utilizar, en el proceso de verificación, tanto la regla de laasignación como la de la selección condicional. Por tanto, podemos comenzarcon lo siguiente:

I 1, J

Z := x;{z = x}if x <~ y then

z := y{x > y 1\ Z = X v X <= Y 1\ Z = y)

Utilizando la regla de la asignación, podemos identificar P como z = x (lavalidez de P se deduce de la linea anterior a él y de la regla de la asignación), yB como x <= y. Por tanto, tendremos que demostrar ahora la validez del

Page 217: ComputacionI A

Robustez y prueba de los algoritmos 211

aserto Q para completar la demostración. Sustituyendo por B, P Y Q susvalores en la regla de la selección, obtendremos:

{z ~ X /\ X <= y} z : = y (z ~ X /\ X > y v z = y /\ X <= y) /\{z = X /\ ~(x <= y) "'" z ~ X /\ X > y v z = y /\ X <= YJ

Para demostrar la validez del aserto anterior, consideramos los dos casosx <= y Y~(x <= y) que, como sabemos por aritmética, son los únicos posibles.

Cuando x <= y la linea 1 es válida, puesto que se realizará la asignaciónx : = y, y la regla de la asignación garantiza que z = y. La regla de la/\ -introducción nos permite inferir z = y /\ X <= y, Yfinalmente, la regla de lav -introducción nos permite inferir z = x /\ x > y v z = Y /\ X <= y. La línea 2también es trivialmente válida, puesto que ~(x <= y) es fa Lso y fa Lso =o> pes siempre válido para cualquier proposición p.

En el segundo caso, x > y, la segunda línea de la disyunción de arriba esválida. Es decir, tanto ~(x <= y) (o equivalentemente, x> y) y z = x sonválidos, por lo que lo es su conjunción por la /\ -introducción. Pero

z = X /\ ~(x : = y)

es equivalente a

z=x/\x>y

por lo que la línea 2 completa tiene la forma de un aserto de tipo p =o> P V q,que es válido por la v -introducción. La línea 1 también es trivialmente válida,puesto que x <= y es fa Lso. Esto completa la justificación para el aserto Q.

Considérese la alternativa siguiente para asignar a z el mayor de los valo­res de x e y:

if x > y thenz := x

elsez := y

Para demostrar esto, es necesario establecer de nuevo la validez del aserto Q:

Q = {z = X /\ X > y v z = y /\ X <= y}

Utilizaremos de nuevo la regla de inferencia de la selección condicional, juntocon otras reglas de inferencia apropiadas, la aritmética e identidades. Comen­zamos con un tableau de prueba parcial:

{verdadero}if x ) y then

z := xelse

z :~ y: z = x /\ x > y v z ~ y /\ X <= y}

Page 218: ComputacionI A

212 Computación l. Lógica, resolución de problemas, algoritmos V programas

Identificamos B como x> y, 5, como z := x, 52 como z := y, y P comoverdadero (esto es lo mismo que decir que no nos importa cuál era el valorque tenian esas variables antes de ejecutar la selección condicional). Asi, laparte b) de la regla de la selección tomaria la forma siguiente, de la que debe­mos demostrar su validez para establecer la propia validez de Q:

{verdadero A x ~ y} z := x{z = X A X > y v z = y A X <= y} A{verdadero A ~(X > y)} z := y{ z = X A X > y v z = y A X <= y}

Analicemos por separado cada una de las lineas de la disyunción, como hici­mos en el ejemplo anterior. La línea 1 se corresponde con el caso en que x > y.Utilizando la regla de la asignación, la propiedad de la identidad para el valorverdadero y la 1\ -introducción, podemos poner lo siguiente:

{X>Y} z :~X(Z=XAX>Y}

Por lo que, utilizando la v -introducción, es posible validar la línea I con lahipótesis de que x > y. La linea 2 cubre el caso alternativo en el que supone­mos que x <= y. Es posible establecer la validez de la línea 2 siguiendorazonamientos similares a los que se utilizaron con la 1.

6.5.5. Verificación de bucles

Para verificar un bucle de un programa es necesario realizar dos operacionesindependientes: debemos encontrar y justificar sus asertos asociados, y debe­mos verificar por inducción su invariante.

Recuérdese, del Capítulo 4, que es posible explicar lo que hace un bucle«desplegándolo». Es decir, si reescribimos el bucle como una secuencia deocurrencias del cuerpo del bucle, podemos deducir con exactitud qué clase degeneralización representa el bucle. Considérese el bucle wh i l e de la Figu­ra 6.16, que suma los enteros del 1 al 5.

sum := o;i :~ 1;while i <= 5 dobegin

5um := sum + i;i:=i+1;

end

Figura 6.16. Un bucle wh i Le sencillo.

Las cinco ejecuciones del cuerpo del bucle pueden ser desplegadas de la mane­ra siguiente:

sum := sum + i;i:=i+1;

Page 219: ComputacionI A

Robustez y prueba de los algoritmos 213

sum : = sum + i;i:=i+1;suro : = sum + i;i:=i+1;sum : = sum + i;i:=i+1;sum := sum + i;i:=i+1;,

Recuérdese también de! Capitulo 4, que el invariante del bucle es un asertoque es válido antes y después de cada repetición del bucle, incluidas la primeray la última. El invariante para e! bucle de arriba es:

{inv: sum=Su. j E {1, •.. , i -1}: j 1\ 1 <= i <=6)

Es posible comprobar que este invariante es verdadero, tanto antes comodespués de cada repetición del bucle wh; Le. En particular, el bucle explicacada uno de los pasos individuales de la expansión del bucle siguiente:

{sum = O 1\ i = 1}sum := sum + i;i:=i+1;

{sum = O + 1 1\ i = 2}sum := sum + i;i:=i+1;

{sum = O + 1 + 2 1\ i = 3}sum : = sum + i;i:=i+1;

{sum = O + 1 + 2 + 3 1\ i = 4}sum := sum + i;i:=i+1;

{sum = O+ 1 + 2 + 3 + 4 1\ i ~ 5}sum := sum + i;i:=i+1;

( sum = O + 1 + 2 + 3 + 4 + 5 1\ i = 6 }

Otro aspecto importante de la verificación de bucles es demostrar que termi­nan. Es decir, estamos interesados sólo en bucles controlados, bucles que termi­nan después de un número de pasos finito, independientemente del estado delas variables en el momento en que empieza su ejecución. Existen tres reglas deinferencia diferentes para describir la condición de terminación de un bucle,una por cada tipo de bucle existente. Cada una de estas variantes utiliza elinvariante y la presunción de terminación de forma diferente.

Definición. La regla de inferencia de los bucles.

a) { i nv 1\ e} s {i nv}

{inv} while e do s {inv 1\ -e}

Page 220: ComputacionI A

214 Computación l. Lógica, resolución de problemas, algoritmos y programas

b) (inv) s {inv}

{inv) repeat s until B {inv A B)

e) (inv A 1 ~ i ~ n} s {inv}[ i nv) for i := 1 to n do s {i nv A i = n + 1)

La parte a) de la regla dice que si {i nv !\ B} s {i nv} es válido para unaúnica ejecución del cuerpo del bucle s, entonces {i nv} whi le B do s{; nv !\ ~B} es válido para el bucle completo. Obsérvese que la condiciónde terminación del bucle (~B) está incluida en la expresión de formaexplicita. Los apartados b) y e) son similares, aunque se aplican a los otrosdos tipos de bucles de Pascal.

Reconsideremos el bucle whi le de la Figura 6.16. La regla del bucle nospermite inferir los asertos siguientes, en los que B es la expresión i <= 5.

5Uro := o;i :~ 1;while i <= 5 do{i nv: sum = Sum i E (1, ... , i - 1 ): i A 1 <~ i <= 6)begin

sum := suro + i;j:~i+1;

end{sum = Sum i E {1, ... , i - 1 ): i A 1 <~ i <= 6 A -( i <= 5) )

Este último aserto puede simplificarse a

{sum = Sum i E {1, o o ., 5}: i A i = 6)

utilizando reglas elementales de la aritmética.Observando las formas de la regla de los apartados b) y e), podemos ver

que la relación entre el invariante y la condición de terminación son ligeramen­te diferentes, y reflejan con exactitud el significado de los bucles repeat yforo Por ejemplo, si reescribimos el bucle de la Figura 6.16 en forma de buclerepeat, la regla del bucle nos dará lo siguiente:

sum :~ O;i := 1;repeat(inv: sum= Sumi E [1, o •• , i -1): i A 1 <= i <~6}

sum := suro + i;i:~i+1;

until i > 5{sum = SUII j E {1, .. o, i - 1 }: j A 1 <~ i <= 6 A i > 5 }

Donde la condición B es ahora; > 5, que especifica la condición para que elbucle termine (en lugar de la condición para que continúe, como pasaba en el

Page 221: ComputacionI A

Robustez V prueba de los algoritmos 215

bucle wh; Le). De nuevo, podemos simplificar utilizando las reglas de la arit­mética:

{ s um = SUI! j E {1, ... , S}: j /\ ; = 6 }

Finalmente, reescribiremos el bucle de la Figura 6.16 como un bucle for.Podemos ver de nuevo que la regla para este bucle alternativo genera losasertos siguientes:

sum :~o;

for ; := 1 to 5 do{ ; nv: sum ~ Sumj E {1, ... , ; - 1 }: j /\ 1 <~ ; <= 6}

sum := sum + i;{sum = Su. j E {1, •.. , ; - 1 }: j /\ 1 <= ; <= 6 /\ ; = 6}

donde el último aserto se simplifica de nuevo a

{ sum = Sum j E {1, ... , S}: j /\ ; = 6}

Utilización de la inducción en la verificación del invariante. Hasta ahora, he­mos admitido la validez del invariante del bucle muy informalmente. Es decir,hemos supuesto que el invariante es, sin ninguna duda, válido para el bucleque describe. Sin embargo, cuando verificamos un programa, debemos escrutarla corrección de todos los invariantes del bucle. ¿Cómo podemos hacer esto?Puesto que cada iteración del bucle sigue a una iteración anterior, podemosutilizar el método de la inducción que se introdujo en el Capitulo 3.

Aqui, la base de la inducción es el número ;, de la iteración del bucleque se va a ejecutar. Concretamente, es necesario demostrar: 1) Que el in­variante se satisface antes de la primera interación; y 2) Que la satisfaccióndel bucle después de las ; - 1 primeras iteraciones (es decir, antes de la; -ésima iteración) garantizan la satisfacción del invariante después de la ite­ración; -ésima (es decir, antes de la iteración ; + 1). Consideremos de nuevoel bucle siguiente:

sum := o;for ; := 1 to 5 do{; nv: SUm = Su", j E {1, ... , ; - 1}: j /\ 1 <= ; <= 6}

sum :~ sum + 1;

Antes de la primera iteración del bucle; = 1 Y sum = O, por lo que se vefácilmente que el invariante se satisface en este caso. Supongamos ahora que elinvariante se satisface después de ; - 1 iteraciones, para algún ; = 2, 3,... , 6. Es decir, supongamos que:

sum ~ Sum j E {1, ... , ; - 1 }: j /\ 1 <= ; <= 6

Page 222: ComputacionI A

216 Computación l. Lógica, resolución de problemas, algoritmos y programas

Ahora tendremos que demostrar por, inducción, que tras una ejecución detodo el cuerpo del bucle, se garantiza que:

sum = SUII j E (1, ... , ;' - 1 ): j 1\ 1 <= ; , <= 6

donde ; , = ; + 1.Podemos hacer esto examinando el efecto de las instrucciones sobre el

invariante original. Es decir, una simple ejecución de la instrucción sum :=sum + 1 conduce a

sum = ; + Sum j E (1, ... , ; - 1 ): j= Sum j E (1, , ;): j= Sum j E (1, , (; + 1 ) - 1 } := SUII j E (1, , ; , - 1 ): j

por reglas algebraicas sencillas. La instrucción; :=; + 1 conduce a

1 <= ; + 1 <= 6 '" 1 <= ;' <~ 6

puesto que el valor limitador de ; = 5 en el bucle for limita a 6 el valor de; , . Luego, por inducción, se deduce que el invariante del bucle es válido, loque completa la verificación del bucle.

6.5.6. Verificación formal frente a verificación informalde programas

Las técnicas que se han introducido en este capítulo reciben habitualmente elnombre de técnicas de verificación formal. Como es fácil imaginar, la aplicaciónde las técnicas de verificación formal a un programa razonablemente largo seconvierte rápidamente en algo inabarcable. Adicionalmente, existe una ampliagama de problemas de programación para los que no se han desarrolladosuficientemente las técnicas de verificación. El proceso de verificación formalde programas está todavía en la infancia -hace falta hacer mucho todavíapara que pueda utilizarse como una herramienta que garantice la robustez delos programas.

Sin embargo, existen diferentes niveles de granularidad de programas, enlos que se puede aplicar las técnicas de verificación de programas. El procesode la verificación i'!formal parece aportar medios de argumentar, de formaconvincente, sobre la corrección de los programas, evitando muchos de losinconvenientes de la demostración línea-a-linea de los métodos formales. Esteproceso es similar al que se sigue en Matemáticas, en la demostración de unteorema, o en una simplificación algebraica, tal como se vio en el Capítulo 3.Es decir, cuando simplificamos una expresión algebraica, no solemos enumerartodos los pasos que se siguen ni su justificación formal en términos de propie-

Pedro Pacheco
Highlight
Pedro Pacheco
Highlight
Page 223: ComputacionI A

Robustez y prueba de los algoritmos 217

dades algebraicas básicas (asociatividad, conmutatividd, etc.). En su lugar, sole­mos saltarnos los pasos que son evidentes para el lector, concentrándonos sóloen aquellos esenciales y dificiles de comprender.

Este es el caso de la verificación informal. En lugar de construir una demos­tración completa mediante una prueba tableau, nos centramos en los aspectosmás complejos del programa, y argumentamos en castellano sobre la forma enque esas partes complejas satisfacen las especificaciones. Así, las nociones deprecondición, poscondición e invariante juegan aún un papel esencial en esteproceso, pero las argumentaciones sobre la corrección del programa se realizanmás informalmente.

6.6. RESUMEN

En este capítulo se han presentado las nociones de correCClOn, robustez yamigabilidad de los programas. En el capítulo se ha incidido sobre la utiliza­ción de la estrategia de resolución de problemas MAPS, ilustrando su utiliza­ción en la resolución de un problema de tratamiento de textos, y otro grá­fico.

Hemos presentado y desarrollado dos metodologías complementarias paraasegurar la corrección y robustez de nuestros programas: prueba y verificación.Éstas permiten desarrollar buenos programas, aun a los más escépticos, sitienen una mentalidad positiva. Es evidente que tendremos que realizar unanálisis activo de nuestros propios diseños y los programas que resultan amedida que sean más complejos los problemas que queremos resolver.

El método de prueba que se ha estudiado en este capítulo aporta herra­mientas que nos permiten adquirir una mayor confianza sobre la corrección delos programas. Aunque el proceso de prueba no garantiza la inexistencia deerrores, nos ayuda a adquirir confianza en la validez de nuestras soluciones. Laprueba es uno de los fundamentos pragmáticos en el campo de la garantiza­ción de la calidad del software.

Cuando es posible aplicar los métodos de verificación estudiados en estecapitulo, garantizan la ausencia de errores. A su vez, inciden en la importanciade la lógica para la informática. Es decir, los principios de la lógica y lasdemostraciones que se introdujeron en el Capítulo 3, son la base notacional ymetodológica para la combinación de precondiciones y poscondiciones en laespecificación de problemas, con las reglas de inferencia en la verificación deprogramas. Sin embargo, la verificación tiene limitaciones prácticas, y es nece­sario que las conozcamos bien cuando tengamos que decidirnos entre prueba overificación de programas. En el Volumen JI de esta serie, veremos técnicas deprueba y verificación adicionales.

Pedro Pacheco
Highlight
Page 224: ComputacionI A

218 Computación l. Lógica, resolución de problemas, algoritmos y programas

Ejercicios

6.7. Verificar los siguientes grupos de instrucciones, rellenando la precondi­ción o poscondición que falta, utilizando la regla de inferencia de laasignación:

a) { } e) { }i := i + 1 Write(x>{i > O} {saLida ~ 12)

b) {i ~ O} J) {i ~ 10}i :~ i + 1 j :~ 25{ } { }

e) {i+j=O} g) { }i := i + 1; s :~ s + t ~ 1j :~ j ~ 1 {O <= s){ }

d) {entrada ~ 4 7 5)Read(x>{ }

6.8. Verificar el bucle siguiente, utilizando la regla de inferencia para bucles,incluyendo una demostración (por inducción) del invariante.

{L~ (e[1], e[2], .. " e[m], .•• , e[n]>)j := 1;k := 2;

whi le k <= m do{inv: para todo i in {1, ... , k ~ 1): e[j] <= e[i] /\ 2 <~ k <= m + 1}

if L[k] < L[j] thenj := k;

Min := j}

6.9. Escribir un bucle controlado utilizando una instrucción for o unarepeat y que sea equivalente al bucle del Ejercicio 6.8. Encontrar elinvariante y verificar el bucle resultante.

6.10. En cada una de las instrucciones siguientes, escribir el aserto que falta(utilizando la regla de inferencia de la selección condicional) de formaque éste sea válido.

a) { }if a = 1 then b :~ a else b := a + 1{b ~ 1}

Page 225: ComputacionI A

Robustez y prueba de los algoritmos 219

b) {i=nAj=m}H i = O then j := O else j := 1{ }

e) {i = n A j = m}if i = O then j :~ O{ }

6.11. Confrontar los procesos de prueba y verificación como garantes de lacorrección, robustez y amigabilidad de los programas. ¿Qué ventajastiene cada uno? ¿Cuáles son las desventajas? Para el problema de laPluviometria del Capítulo 5, ¿cuál de los dos procesos parece sermás adecuado y por qué?

6.12. Verificar el invariante del segmento de programa siguiente, suponiendoque s = •R2D2 I . Escribir los valores de las variables Count y Loe encada iteración de bucle.

Count := o;Loe := O;whi le Loe < Length(S) do{inv: O <= Loe <= Length(S) A

Coun t = Num i E {1, ... , Lo e}: 'O' <= S[ i] <= '9')begin

Loe :~Loe+1;

if (S[Loe] >= 'O') and (S[Loe] <~ '9') thenCount := Count + 1

end¡

6.13. Encontrar el invariante del bucle de la función siguiente:

function EstaOrdenada (A: Lista): Soolean;var i: i nteger

beginEstaOrdenada := true;for i := 1 to LengthLista(A) -1 do

i f A[ i] > A[i + 1] t henEstaOrdenada := false¡

end¡