INTRODUCCIÓN − DEFINICIONES DATO, PROCESO E INFORMACIÓN Dato e información son dos términos que suelen confundirse. Se consideran datos a toda entrada de información a una computadora. Estos datos pueden ser administrativos, científicos, comerciales, etc. son elementos primitivos, de los cuales a través del procesamiento se obtiene la información. La computadora se utiliza para procesar en forma automática y a gran velocidad esos datos. Como resultado del procesamiento de esos datos se obtiene la información deseada, la cual será útil en la toma de decisiones. DATO PROCESO INFORMACIÓN SISTEMA Un sistema es un conjunto de componentes relacionados que interactúan para realizar una tarea. Un sistema de informática está compuesto por el Hardware (CPU, dispositivos periféricos) y el Software (sistema operativo y los programas). El software de un sistema de información está formado por los datos, los programas de ingreso, actualización e informe de resultados y los procedimientos manuales y por máquina. ESTRUCTURA DE UNA COMPUTADORA Una PC es una computadora personal, originalmente diseñada para servir a un sólo usuario. Sale al mercado en 1981 y va evolucionando en capacidad y velocidad, además su costo se va reduciendo. Existen diferentes configuraciones para adecuarse a la múltiples necesidades de los usuarios. La informática es la ciencia que estudia el tratamiento, elaboración , transmisión y utilización de la información. Es una ciencia porque constituye un conjunto de conocimientos de validez universal y porque utiliza el método científico para el logro de sus objetivos. Se denomina HARDWARE (ferretería) a todos los componentes electrónicos y mecánicos, es decir físicos de una computadora. Se denomina SOFTWARE al conjunto de programas o procedimientos que determinan las acciones de la máquina, es todo lo concerniente a la programación. Las computadoras están estructuradas según un modelo básico de funcionamiento que describe la interacción que se realiza entre los elementos que la componen. Este modelo es: MONITOR MOUSE CPU IMPRESORA SCANNER TECLADO MÓDEM UNIDADES Las unidades son las partes físicas que componen nuestro ordenador, y se clasifican en unidades de entrada−salida (E/S) denominadas periféricos, y la unidad de proceso (UCP o CPU). Además de las unidades encontramos los soportes, que son elementos externos al ordenador, no imprescindibles para su funcionamiento, pero necesarios para el almacenamiento de la información. 1 Unidades E/S Las unidades de entrada−salida son aquellos elementos del hardware que fueron diseñados para el ingreso y egreso de los datos. Existen unidades cuya tarea específica es el ingreso de datos, otras que solo sirven para el egreso de la información, y hay un tercer grupo que puede cumplir con ambas funciones. Entrada Teclado Mouse o Ratón, TrackBall, Cat Scanner Lectora de barras Lápiz óptico Lectora de CD−ROM (DVD) Micrófono Monitor Sistema de vídeo Unidades de Entrada−Salida Placa de vídeo Salida Impresora Plotter Parlante Placa de audio Sistema de audio Parlantes E/S Modem Disqueteras Grabadora/Reproductora de CD Integer Pantallas táctiles Soportes de la información Los soportes de la información son medios físicos de almacenamiento de información. Ellos pueden ser clasificados como: Papel: es el soporte más antiguo de información que aún sigue en uso. Listados Magnéticos: son aquellos medios que están basados en las propiedades magnéticas para el registro de la información. La mayoría de los mismos son usados como elemento de almacenamiento masivo. • Cintas de carrete abierto de 1/2" de ancho. • Cintas de vídeo (casete denominado super 8) • Disquetes • Cintas en tarjetas plásticas Medios Ópticos: están basados en la capacidad de poder o no reflejar la luz emitida por un determinado elemento (emisor) • CD−ROM. 2 • DVD (Digital Vídeo Disk o Digital Versatil Disk El Disco Rígido es difícil de catalogar ya que es un sistema en sí mismo, y posee una unidad de entrada/salida que son las cabezas lectoras−grabadoras y un soporte que son los discos propiamente dicho. Alguno de ellos vienen con una pequeña pero completa unidad de proceso. LA UNIDAD CENTRAL DE PROCESO Y EL PROCESADOR La unidad central de proceso UCP es el verdadero cerebro de la computadora; su misión consiste en coordinar y controlar o realizar todas Las operaciones del sistema. Se compone de elementos cuya naturaleza es exclusivamente electrónica (circuitos). Sus partes principales son Las siguientes: • El Procesador (P). Que a su vez se compone de: • La unidad de control (UC). • La unidad aritmético−lógica (UAL). • La Memoria Central (MC). La unidad central de proceso también incorpora un cierto número de registros rápidos (pequeñas unidades de memoria) de propósito especial, que son utilizados internamente por la misma. Una aproximación a diseño interno de un microprocesador es el siguiente 3 Figura 1 Como vemos en el esquema 1, la unidad de control y la unidad aritmético−lógica constituyen lo que se ha venido a denominar el procesador central del sistema; este elemento es parte de la unidad central de proceso encargada del control y ejecución de las operaciones del sistema. Estos elementos en un ordenador personal se encuentran integrados en un único chip llamado microprocesador. Las funciones principales de la UCP de un ordenador son: • Ejecutar las instrucciones de los programas almacenados en la memoria del sistema. • Controlar la transferencia entre la UCP y la memoria o las unidades de E/S • Responder a las peticiones de servicio procedente de los periféricos. Todo programa tiene como objetivo realizar diferentes funciones o aplicaciones, solo limitadas por la capacidad e imaginación del programador. Para que un programa sea ejecutado el mismo se debe hallar en determinadas posiciones de memoria y escrito en un lenguaje que la UCP pueda entender. La UCP lo único que comprende es lenguaje binario. La UCP lee en forma ordenada la lista de instrucciones, luego las interpreta, y posteriormente controla su ejecución de cada una de ellas. Las ejecuciones se realizan en forma consecutiva una tras otra. 4 Para ejecutar cada instrucción la UCP realiza la siguiente serie de pasos: • Lee de la memoria la instrucción que hay que ejecutar y la guarda en un registro interior de la UCP. • Identifica la instrucción que acaba de leer • Comprueba si la instrucción necesita utilizar nuevos de memoria, si fuera así, determina donde debe ir a buscarlos. • Busca los datos en la memoria y los trae en UCP. • Ejecuta la instrucción propiamente dicha. • El resultado de la misma puede ser que se almacene o invoque la necesidad de tener que comunicarse con la memoria o con otro elemento externo a la propia UCP. • Vuelve al primer paso para empezar una nueva instrucción. La anterior es una lista simplificada de los pasos que ejecuta el microprocesador. La ejecución de cada instrucción implica el movimiento de datos, como estos pasos deben ser se deben realizar en forma secuencial y ordenada, para lo cual la UCP siguen las señales dadas por un reloj. El reloj es un elemento simple pero de gran importancia como se verá luego. Para una mejor compresión del funcionamiento de la UCP, la misma se puede dividir en dos unidades la unidad de control y la unidad aritmético−lógica. . Unidad de control (UC) La unidad de control (UC) es el centro nervioso de la computadora; desde ella se controla y gobiernan todas las operaciones (búsqueda, decodificación, y ejecución de la instrucción). Para realizar su función, consta de los siguientes elementos: • Registro de contador de programas (CP) • Registro de Instrucciones (RI) • Decodificador (D) • Reloj (R) • Generador de Señales o Secuenciador (S) Registro de contador de programas (CP). También denominado registro de control de Secuencia (RCS), contiene permanentemente la dirección de memoria de la próxima instrucción a ejecutar. Si la instrucción que se está ejecutando en un instante determinado es de salto o de ruptura de secuencia, el RCS tomará la dirección de la instrucción que se tenga que ejecutar a continuación; esta dirección la extraerá de la propia instrucción en curso. Como ya se dijo el primer paso para la ejecución de una instrucción, consiste en ir a buscarla en memoria, el CP indica cual es la dirección de memoria donde se halla esa instrucción. Una vez obtenida y antes de continuar con los siguientes pasos una señal de control incrementa el CP en una unidad, por lo cual los programas deben estar escritos (cargados) en posiciones consecutivas de memoria. El CP pasa la dirección al Registro de Direcciones Registro de Direcciones (RD). Contiene la dirección de memoria donde se encuentra la próxima instrucción y esta comunicado con el Bus de Direcciones. El tamaño de este registro determina el tamaño de la memoria que puede direccionar.( Si es de 32 bits se puede direccionar 232=4.294.967296 (4 GB posiciones de memoria). 5 Con la dirección de memoria, se transfiere a través el Bus de Datos desde la memoria central al Registro de Datos en la UC la instrucción correspondiente. Esta transferencia se realiza mediante señales de control. Una vez que la instrucción se encuentra en la UCP, el código de la instrucción pasa al registro de instrucciones. Registro de Instrucciones (RI). Contiene la instrucción que se está ejecutando en cada momento. Esta instrucción llevará consigo el código de operación (CO), acción de que se trata, y en su caso los operandos o las direcciones de memoria de los mismos. Pasa el CO al decodificador. Decodificador (D). Se encarga de extraer y analizar el código de operación de la instrucción en curso (que está en el RI) y dar las señales necesarias al resto de los elementos para su ejecución por medio del Generador de Señales. Generador de Señales(GS). En este dispositivo se generan órdenes muy elementales (microórdenes) que, sincronizadas por los impulsos del reloj, hacen que se vaya ejecutando poco a poco la instrucción que está cargada en el RI. Reloj (R). Proporcionar una sucesión de impulsos eléctricos a intervalos constantes (frecuencia constante), que marcan los instantes en que han de comenzar los distintos pasos de que consta cada instrucción. Figura 2 Unidad aritmético−lógica (UAL) Esta unidad es la encargada de realizar las operaciones elementales de tipo aritmético (generalmente sumas o restas) y de tipo lógico (generalmente comparaciones). Para realizar su función, consta de los siguientes elementos: • Banco de registros (BR). • Circuitos operadores (CIROP). 6 • Registro de resultado (RR). • Señalizadores de estado (SE). Banco de registros (BR). Está constituido por 8, 16 ó 32 registros de tipo general que sirven para situar dates antes de cada operación, para almacenar datos intermedios en las operaciones y para operaciones internas del procesador. Circuitos operadores (CIROP). Compuesto de uno o varios circuitos electrónicos que realizan operaciones elementales aritméticas y lógicas (sumador, complementador, desplazador, etc). Registro de resultado (RR). Se trata de un registro especial, en el que se depositan los resultados que producen los circuitos operadores. Señalizadores de estado (SE). Registro con un conjunto de biestables en los que se deja constancia de algunas condiciones que se dieron en la última operación realizada. LA MEMORIA CENTRAL (MC) Es la parte de la unidad central de proceso de una computadora donde están almacenadas las instrucciones y los datos necesarios para que un determinado proceso pueda ser realizado. La memoria central está constituida por una multitud de celdas o posiciones de memoria, numeradas de forma consecutiva, capaces de retener, mientras la computadora esté conectada, la información necesaria. Por otra parte, es una memoria de acceso directo, es decir, puede accederse a una de sus celdas conociendo su posición. Para esta memoria el tiempo de acceso es más corto que para Las memorias auxiliares, por tanto, los datos que manejan los procesos deben residir en ella en el momento de su ejecución. Es importante no confundir los términos celda o posición de memoria con el de palabra de computadora, ya que esta última es el conjunto de posiciones de memoria que pueden introducirse o extraerse de la memoria de una solo vez (simultáneamente). La memoria central tiene asociados dos registros para la realización de operaciones de lectura o escritura, y un dispositivo encargado de seleccionar una celda de memoria en coda operación de acceso sobre la misma: • Registro de dirección de memoria (RDM)). 7 • Registro de intercambio de memoria (RIM). • Selector de memoria (SM). · Registro de dirección de memoria (RDM). Contiene la dirección de memoria donde se encuentran o va a ser almacenada la información (instrucción o dato), tanto si se trata de una lectura como de una escritura de o en memoria central, respectivamente. · Registro de intercambio de memoria (RIM). Si se trata de una operación de lectura, el RIM es quien recibe el dato de la memoria señalado por el RDM, para su posterior envío a uno de Los registros de la UAL. Si se trata de una operación de escritura, la información a grabar tiene que ester en el RIM, para que desde él se transfiera a la posición de memoria indicada por el RDM. · Selector de memoria (SM). Es el dispositivo que, tras una orden de lectura o escritura, conecta la celda de memoria cuya dirección figure en el RDM con el RIM, posibilitando la transferencia de Los dates en un sentido o en otro. La memoria central suele ser direccionable por octeto o byte; por tanto, una celda o posición de memoria contiene 8 bits. Una de Las características fundamentales de una computadora es su capacidad de memoria interna (memoria central), la cual se mide en un múltiplo del byte denominado Kilobyte, Kbyte, Kb o simplemente K, y que equivale a 1 024 bytes (1 024 = 2'°). Otro múltiplo utilizado ampliamente en Los últimos tiempos es el Megabyte o simplemente Mega, que equivale a 1 024 * 1 024 Bytes; es decir, a 1 048 576 bytes. Bus de Bus de Datos Registro Direcciones de dirección Registro de intercambio de memoria de memoria Bus de Control Selector Memoria Central 0001 0010 0110 1011 TIPOS DE INSTRUCCIONES Nos referiremos en este apartado a instrucciones del lenguaje máquina. Son aquellas que puede ejecutar directamente el hardware de la computadora. Las instrucciones máquina se pueden clasificar por la función que desempeñan en: • Instrucciones de transferencia de datos. • Instrucciones de ruptura de secuencia. • Instrucciones aritméticas y lógicas. 8 • Instrucciones declarativas. • Etcétera. O por su contenido, teniendo en cuenta que todas ellas tienen en primer lugar lo que se llama código de operación (CO), que indica qué operación se debe realizar por el procesador, y aquellas en Las que su misión sea hacer alguna operación con determinados dates; llevarán, además, implícita o explícitamente dichos dates, que denominaremos operandos. Instrucciones de tres operandos También se denominan instrucción es de tres direcciones. En primer lugar constan de un código de operación al que siguen tres operandos, de Los cuales, Los dos primeros son Los operandos y el tercero es la dirección donde se depositará el resultado. Este formato de instrucción es el más cómodo de trabajar, pero es el que precise mayor número de bits. Esquema siguiente. Código de operación Operando1 Operando2 Operando3 Instrucciones de dos operandos Constan de un código de operación, seguido de dos operandos, de Los cuales uno de ellos actúa además como receptor del resultado. También se denominan instrucciones de dos direcciones. En el siguiente esquema se ve la Instrucción de dos operandos. Código de operación Operando 1 Operando2 Instrucciones de un operando También denominadas instrucciones de una dirección. Son Las que se utilizan generalmente en máquinas cuya arquitectura funciona con filosofía de acumulador. El acumulador es un registro especial, en el que se encuentra uno de Los operandos para este tipo de instrucciones y donde además se guarda el resultado. En la instrucción se encuentra el código de operación seguido del segundo operando Código de operación Operando 1 Instrucciones sin operandos También denominadas instrucciones sin ninguna dirección. Este tipo de instrucciones se utilizan generalmente en computadoras cuya arquitectura tiene filosofía de pila. Una pila está formada por dates almacenados en orden consecutivo en la memoria, existiendo un registro especial denominado puntero de pila que nos indica la dirección del último dato introducido en ella. Cuando un dato es sacado de ella, el puntero de pila decrece, apuntando al dato que está a continuación en la pila hacia el fondo de la misma y que será aquel dato que se introdujo en primer lugar. Cuando se trata de introducir un dato en ella el puntero toma la dirección de memoria siguiente en orden ascendente y se introduce en dicha dirección. 9 Estas instrucciones sólo llevan código de operación, de tal forma que cuando se trata de una operación, se sacan Los operandos de la pila (previamente introducidos) y el resultado se introduce en la misma. código de operación Una computadora en su lenguaje máquina puede tener instrucciones de las anteriores, según sea su arquitectura. METODOS DE DIRECCIONAMIENTO Se habla de direccionamiento en una instrucción al modo de indicar en la misma el lugar donde está situado el dato que va a intervenir en ella. Los direccionamientos utilizados en Las instrucciones son Los siguientes: • Direccionamiento inmediato: en él, el dato a utilizar se halla en la propia instrucción, en el acumulador o en la pila. • Direccionamiento directo: en este caso la instrucción contiene la dirección de memoria central donde se encuentra el dato. • Direccionamiento indirecto: la instrucción contiene la dirección de memoria central donde se encuentra la dirección de memoria que contiene el dato. • Direccionamiento indexado: en el la dirección de memoria central donde se encuentra el dato, se obtiene sumándole a la dirección que lleva la instrucción una cantidad, que se encuentra en un registro especial llamado índice. LENGUAJES DE PROGRAMACIÓN Para poder desarrollar las capacidades del hardware, se ha necesitado la creación de códigos por medio d los cuales hacer que el ordenado ejecute una serie de órdenes a este conjunto de códigos se denomina lenguaje. Un lenguaje de programación es una notación para escribir programas, a través de los cuales podemos comunicarnos con el hardware y dar así las órdenes adecuadas para la realización de un determinado proceso. Un lenguaje viene definido por una gramática o conjunto de reglas que se aplican a un alfabeto constituido por el conjunto de símbolos utilizados. Los distintos niveles en que se clasifican los lenguajes, no son índice de la capacidad del lenguaje. Cuando se habla de lenguajes de bajo nivel implica indicar que el lenguaje es fácil de ser procesado por el microprocesador, ocupa poca lugar en memoria y de muy difícil programación para el hombre, cuando hablamos de alto nivel nos indica que el mismo programa es de fácil programar por un programador pero ocupa mucho lugar de memoria y es de difícil acceso al hardware, de tal forma que según utilicemos un nivel u otro así tendremos que utilizar un determinado lenguaje ligado a sus correspondientes traductores. El siguiente esquema representan la evolución de los distintos lenguajes. Periodo Influencias 1950 − 1955 Ordenadores primitivos 1956 − 1960 Lenguajes Lenguajes ensamblador. Ordenadores pequeños, caros y lentos Lenguajes experimentales de alto nivel FORTRAN Cintas magnéticas. ALGOL 58 y 60 Compiladores e intérpretes COBOL 10 Optimización del código. Ordenadores grandes y caros LISP FORTRAN IV Discos magnéticos COBOL 61 Extendido Sistemas operativos ALGOL 60 Revisado Lenguajes de propósito general. APL (como notación sólo) PL/I Ordenadores de diferentes tamaños, velocidades, y costes. FORTRAN 66 (estándar) 1961 − 1965 COBOL 65 (estándar) Sistemas caros de almacenamiento masivo ALGOL 68 de datos. 1966 − 1970 Sistemas operativos multitarea e interactivos. SIMULA 67 BASI Compiladores con optimización. Lenguajes C estándar, flexibles y generales. APL/360 Micro ordenadores. 1971 − 1975 Sistemas pequeños y baratos de almacenamiento masivo de datos. Programación estructurada. PASCAL Ingeniería del software. PL/I Lenguajes sencillos. Ordenadores baratos y potentes. Sistemas distribuidos. ADA Programación interactiva. FORTRAN 77 Abstracción de datos. PROLOG Programación con fiabifidad y fácil mantenimiento. Ordenadores más baratos y potentes. C Mayor abstracción de datos. OOCOBOL Menor costo de memorias C++ Programación Orientada o Objetos Ojective C COBOL 74 1976 − 1980 1980 SmallTalk Object Pascal (Delphi) 11 Visual Basic Lenguajes de programación se clasifican: • Bajo nivel (Lenguaje máquina) • Intermedios (Lenguaje ensamblador), C • Alto nivel Gestión Científicos Propósito general y específicos Lenguaje máquina El lenguaje máquina es el único que entiende directamente la computadora, utiliza el alfabeto binario que consta de los dos únicos símbolos 0 y 1, denominados bits (abreviatura inglesa de dígitos binarios). Fue el primer lenguaje utilizado en la programación de computadoras, pero dejó de utilizarse por su dificultad y complicación, siendo sustituido por otros lenguajes más fáciles de aprender y utilizar, que además reducen la posibilidad de cometer errores. EJEMPLO 0000 0001 1010 0001 01 A1 1000 1001 1001 1010 89 9A 0011 1010 1001 1100 3A 9C 0111 0100 0111 0000 74 70 1110 1001 0010 0000 E9 20 Lenguaje ensamblador El lenguaje ensamblador es el primer intento de sustituir el lenguaje máquina por otro más similar a los utilizados por las personas. En este lenguaje cada instrucción equivale a una instrucción en lenguaje máquina, utilizando para su escritura palabras nemotécnicas en lugar de cadenas de bits. EJEMPLO INICIO: ADD B, 1 MOV A, E CMP A, B JE FIN JMP INICIO FIN : END Este lenguaje presenta la mayoría de los inconvenientes del lenguaje máquina: • Cada modelo de computadora tiene un lenguaje ensamblador propio diferente del de los demás, por lo cual un programa sólo puede utilizarse en la máquina para la cual se programó. 12 • El programador ha de conocer perfectamente el hardware del equipo, ya que maneja directamente las posiciones de memoria, registros del procesador y demás elementos físicos. • Todas las instrucciones son elementales, es decir, en el programa se deben describir con el máximo detalle todas las operaciones que se han de llevar a cabo en la máquina para la realización de cualquier proceso. Por otro lado, tanto el lenguaje máquina como el ensamblador gozan de la ventaja de mínima ocupación de memoria y mínimo tiempo de ejecución en comparación con el resultado de la compilación del programa equivalente escrito en otros lenguajes. Lenguajes de alto nivel Los lenguajes de alto nivel, también denominados lenguajes evolucionados, surgen con posterioridad a los anteriores, con los siguientes objetivos, entre otros: • Lograr independencia de la máquina, pudiendo utilizar un mismo programa en diferentes equipos con la única condición de disponer de un programa traductor o compilador, que lo suministra el fabricante, para obtener el programa ejecutable en lenguaje binario de la máquina que se trate. Además, no se necesita conocer el hardware específico de dicha máquina. • Aproximarse al lenguaje natural, para que el programa se pueda escribir y leer de una forma más sencilla, eliminando muchas de las posibilidades de cometer errores que se daban en el lenguaje máquina, ya que se utilizan palabras (en inglés) en lugar de cadenas de símbolos sin ningún significado aparente. • Incluir rutinas de uso frecuente como son las de entrada/salida, funciones matemáticas, manejo de tablas, etc, que figuran en una especie de librería del lenguaje, de tal manera que se pueden utilizar siempre que se quieran sin necesidad de programarlas cada vez. Se puede decir que el principal problema que presentan los lenguajes de alto nivel es la gran cantidad de ellos que existen actualmente en uso (FORTRAN, LISP, ALGOL, COBOL, APL, SNOBOL, PROLOG, MODULA2, ALGOL68, PASCAL, SIMULA67, ADA, C++, LIS, EUCLID, BASIC), además de las diferentes versiones o dialectos que se han desarrollado de algunos de ellos. FORTRAN Abreviatura de Fórmula Translator (traductor de fórmulas), fue definido alrededor del año 1955 en los Estados Unidos por la compañía IBM. Es el más antiguo de los lenguajes de alto nivel, pues antes de su aparición todos los programas se escribían en lenguaje ensamblador o en lenguaje máquina. Es un lenguaje especializado en aplicaciones técnicas y científicas, caracterizándose por su potencia en los cálculos matemáticos, pero estando limitado en las aplicaciones de gestión, manejo de archivos, tratamiento de cadenas de caracteres y edición de informes. A lo largo de su existencia han aparecido diferentes versiones, entre las que destaca la realizada en 1966 por ANSI (American National Standard Institute) en la que se definieron nuevas reglas del lenguaje y se efectuó la independencia del mismo con respecto a la máquina, es decir, comenzó la transportabilidad del lenguaje. Esta versión se denominó FORTRAN IV o FORTRAN 66. En 1977, apareció una nueva versión más evolucionada que se llamó FORTRAN V o FORTRAN 77, esta versión está reflejada en el documento «ANSI X3.9−1978: Programming Language FORTRAN» y define dos niveles del lenguaje denominados FORTRAN 77 completo y FORTRAN 77 básico, siendo el segundo un subconjunto del primero. Esta última versión incluye además instrucciones para el manejo de cadenas de caracteres y de archivos, así como otras para la utilización de técnicas de programación estructurada. Estas características hacen que el lenguaje también sea válido para determinadas aplicaciones de gestión. 13 COBOL Es el lenguaje más usado en las aplicaciones de gestión, creado en 1960 por un comité denominado CODASYL, patrocinado por el Departamento de Defensa de los Estados Unidos, a fin de disponer de un lenguaje universal para aplicaciones comerciales como expresa su nombre (COmmon Business Oriented Language). Entre sus características se pueden citar su parecido al lenguaje natural (inglés), es auto− documentado y tiene gran capacidad en el manejo de archivos, así como en la edición de informes escritos. Entre sus inconvenientes están sus rígidas reglas de formatos de escritura, la necesidad de describir todos los elementos al máximo detalle, la extensión excesiva en sus sentencias e incluso duplicación en algunos casos, la inexistencia de funciones matemáticas y, por último, su no adecuación a las técnicas de programación estructurada. a PL/1 Fue creado a comienzos de los años 60 por IBM para ser usado en sus equipos del sistema 360. El PL/I (Programming Language 1) se desarrolló inspirándose en los lenguajes ALGOL, COBOL y FORTRAN, tomando las mejores características de los anteriores y añadiendo algunas nuevas, con el objetivo de obtener un lenguaje lo más general posible, útil para aplicaciones técnico−científicas, comerciales, de proceso de textos, de bases de datos y de programación de sistemas. Entre sus novedades está su gran libertad en el formato de escritura de los programas, soportar la programación estructurada y el diseño modular. No obstante, no ha superado a sus progenitores en sus aplicaciones específicas debido en parte a su amplitud y por ello, al tamaño de su compilador, que hasta ahora sólo se podía instalar en grandes equipos. BASIC Fue diseñado por los profesores John G. Kemeny y Thomas E. Kurtz del Dartmouth College en 1965 con el objetivo principal de conseguir un lenguaje fácil de aprender para los principiantes, como se indica en su nombre Benginner's All−purpose Symbolic Instruction Code (Código de instrucción simbólico de propósito general para principiantes). Entre sus principales novedades están las de ser un lenguaje interpretado y de uso conversacional, útil para aplicaciones técnicas y de gestión. Estas características, unidas a la popularización de las microcomputadoras y computadoras personales, ha hecho que su utilización se haya extendido enormemente, a la vez que ha propiciado el surgimiento de una gran diversidad de versiones que extienden y adaptan a necesidades particulares el lenguaje original. Existen multitud de intérpretes y compiladores del lenguaje. PASCAL Fue creado por el matemático suizo Niklaus Wirth en 1970, basándose en el lenguaje AL−GOL, en cuyo diseño había participado en los años 60. Su nombre proviene del filósofo y matemático francés del siglo xvii Blaise Pascal, que inventó la primera máquina de tipo mecánico para sumar. Aunque en principio la idea del diseñador era proporcionar un lenguaje adecuado para la enseñanza de los conceptos y técnicas de programación, con el tiempo ha llegado a ser un lenguaje ampliamente utilizado en todo tipo de aplicaciones, poseyendo grandes facilidades para la programación de sistemas y diseño de gráficos. Aporta los conceptos de tipo de datos, programación estructurada y diseño descendente, entre otros, además 14 de haberse convertido en predecesor de otros lenguajes más modernos, como MODULA−2 y ADA. C Fue creado en 1972 por Dennis Ritchie a partir del trabajo elaborado por su colega de los laboratorios Bell Telephone, Ken Thompson. Estos habían diseñado con anterioridad el sistema operativo UNIX, y su intención al desarrollar el lenguaje C fue la de conseguir un lenguaje idóneo para la programación de sistemas que fuese independiente de la máquina con el cual escribir su sistema UNIX. Aunque fue diseñado inicialmente para la programación de sistemas, posteriormente su uso se ha extendido a aplicaciones técnico−científicas, de bases de datos, de proceso de textos, etc. La utilización óptima de este lenguaje se consigue dentro de su entorno natural, que es el sistema operativo UNIX. Entre sus características destaca el uso de programación estructurada para resolver tareas de bajo nivel, así como la amplia librería de rutinas de que dispone. ADA Es el último intento de obtener un único lenguaje para todo tipo de aplicaciones e incluye los últimos avances en técnicas de programación. Su diseño fue encargado por el Departamento de Defensa de los Estados Unidos a la empresa Honeywell−Bull después de una selección rigurosa entre varias propuestas realizadas sobre una serie de requerimientos del lenguaje y de haber evaluado negativamente veintitrés lenguajes existentes. De éstos se seleccionaron como base para la creación del nuevo lenguaje el PASCAL, el ALGOL y el PL/I. La estandarización del lenguaje se publicó en 1983 con el nombre de ADA en honor de la considerada primera programadora de la historia Augusta Ada Byron, condesa de Lovelace. Entre las características del lenguaje se encuentran la compilación separada, los tipos abstractos de datos, programación concurrente, programación estructurada, libertad de formatos de escritura, etc., presentando como principal inconveniente su gran extensión. Interpretes y Compiladores Existen dos tipos principales de traductores de los lenguajes de programación de alto nivel: • Compilador, que analiza el programa fuente y lo traduce a otro equivalente escrito en otro lenguaje (por ejemplo, en el lenguaje de la máquina). Su acción equivale a la de un traductor humano, que toma un libro y produce otro equivalente escrito en otra lengua. • Intérprete, que analiza el programa fuente y lo ejecuta directamente, sin generar ningún código equivalente. Su acción equivale a la de un intérprete humano, que traduce las frases que oye sobre la marcha, sin producir ningún escrito permanente. Intérpretes y compiladores tienen diversas ventajas e inconvenientes que los hacen complementarios: • Un intérprete facilita la búsqueda de errores, pues la ejecución de un programa puede interrumpirse en cualquier momento para estudiar el entorno (valores de las variables, etc.). Además, el programa puede modificarse sobre la marcha, sin necesidad de volver a comenzar la ejecución. • Un compilador suele generar programas más rápidos y eficientes, ya que el análisis del lenguaje fuente se hace una sola vez, durante la generación del programa equivalente. En cambio, un intérprete se ve obligado generalmente a analizar cada instrucción tantas veces como se ejecute (incluso miles o millones de veces). • Un intérprete permite utilizar funciones y operadores más potentes, como por ejemplo ejecutar código contenido en una variable en forma de cadenas de caracteres. Usualmente, este tipo de instrucciones es imposible de tratar por medio de compiladores. Los lenguajes que incluyen este tipo de operadores y que, por tanto, exigen un intérprete, se llaman interpretativos. Los lenguajes compilativos, que 15 permiten el uso de un compilador, prescinden de este tipo de operadores. EVOLUCIÓN HISTÓRICA DE LA PROGRAMACIÓN En el comienzo de la informática, sólo había una forma de programar (en binario), que consistía en la ejecución secuencial (una tras otra) de instrucciones de la máquina, con posibles cambios de secuencia basados en dos tipos especiales de instrucciones de control Las instrucciones de control se dividieron en dos tipos: • instrucciones de transferencia • instrucciones de llamada de subrutina. Las instrucciones de transferencia dan lugar a un salto sin retorno en la ejecución, y a su vez pueden ser condicionales (si el salto se produce únicamente cuando se cumple una condición determinada) o incondicionales. La instrucción de llamada de subrutina guarda la dirección de retorno para que la secuencia de ejecución original se reanude cuando termina la ejecución de la subrutina (momento en el que se ejecutará una instrucción de retorno). En la década de los años cincuenta surgió un nuevo tipo da lenguajes (llamados simbólicos, o de segunda generación: assembler), que trataban de simplificar la programación: ya que, a medida que los programas eran cada vez más complejos, se hacía impracticable utilizar directamente el lenguaje de la máquina, en el que las instrucciones estaban formadas por secuencias de ceros y unos. Un lenguaje simbólico no es más que una representación codificada del lenguaje de la máquina, donde cada instrucción simbólica se traduce (en principio) por una sola instrucción de la máquina equivalente, y el código de operación y la dirección de memoria asociados a cada instrucción de la máquina se representan mediante símbolos alfanuméricos. En particular, dependiendo del lenguaje simbólico utilizado, las instrucciones de cambio de secuencia se suelen representar mediante los siguientes símbolos: • La instrucción de transferencia incondicional: JMP (jump, es decir, salto); B (branch, ramificación); GOTO (go to, ir a); etc. • Las instrucciones de transferencia condicional: JZ (jump on zero, salto si el resultado anterior es cero); BC (branch on condition, ramificación condicional); etc. • La instrucción de llamada de subrutina: CALL (llamar, en inglés); BAL (branch and link, es decir, ramificación con enlace); etc. • La instrucción de retorno de subrutina: RET (return, retorno); etcétera. A finales de los años cincuenta, y a medida que las aplicaciones iban creciendo en tamaño y en complicación, la programación en los lenguajes simbólicos resultaba aún demasiado compleja, por lo que se inventaron los lenguajes de alto nivel o de tercera generación, tales como FORTRAN, LISP, COBOL, ALGOL, APL, PL/I, BASIC, Pascal, C, etc., que hacían más legibles los programas mediante expresiones de aspecto matemático, como X + Y * Z (que significa, en muchos de los lenguajes citados, sumar el valor de la variable X al resultado de multiplicar el valor de la variable Y por el de la variable Z). Todos estos lenguajes, y muchos más que no voy a mencionar por el momento, no son totalmente independientes entre sí, sino que unos influyeron en el diseño de los otros, por lo que forman una jerarquía histórica. Además de simplificar la sintaxis de las expresiones, los lenguajes de alto nivel introdujeron una serie de instrucciones de control para hacer más simple la definición de la estructura de los programas. Estas instrucciones pueden agruparse en las siguientes clases: 16 • Una instrucción de transferencia incondicional (siempre se produce un salto sin retorno en la ejecución), generalmente representada mediante el símbolo GOTO, GO TO, u otro equivalente. • Instrucciones de transferencia condicional, como las sentencias GO TO calculada y asignada de FORTRAN, o la sentencia IF del mismo lenguaje, en su forma original. • Instrucciones de ejecución condicional, como el conjunto IF− THEN−ELSE de ALGOL y Pascal, la instrucción CASE de Pascal o el conjunto if−else y la instrucción switch de C. • Instrucciones de ejecución en bucle, en sus formas DO−UNTIL, DO−WHILE y FOR. • La instrucción de llamada de subrutina, representada mediante el símbolo CALL, o implícitamente, especificando sólo el nombre de la subrutina que se invoca, junto con un conjunto de argumentos entre paréntesis. • La instrucción de retorno de subrutina: RETURN o equivalente. PROGRAMACIÓN ESTRUCTURADA En ciertos lenguajes clásicos (como APL o las formas primitivas de FORTRAN y BASIC) se emplea con frecuencia la instrucción GOTO de transferencia incondicional, que permite pasar la ejecución del programa a otra parte del mismo, señalada por una etiqueta. En otros (como C o Pascal) se utiliza un estilo diferente de programar (la programación estructurada) en la que la instrucción GOTO está prohibida o, al menos, desaconsejada. Por ello, la programación estructurada se llama a veces programación sin GOTO. En la programación estructurada se utilizan sólo cuatro estructuras de control básicas: • El bloque de instrucciones consecutivas. En C se representa con los símbolos { y ). • La instrucción condicional. En C y en PASCAL existen dos tipos principales: • La instrucción if−else: Si la condición se cumple, se ejecuta la instrucción 1. En caso contrario, se ejecuta la instrucción 2. • La instrucción switch (o case of): • Si la variable tiene el valor1, se ejecuta el bloque de instrucciones 1. • Si tiene el valor2, se ejecuta el bloque de instrucciones 2. Y así sucesivamente. • Si no tiene ninguno de los valores indicados, se ejecuta el bloque de instrucciones n. • El bucle: En C (o en PASCAL) existen tres tipos principales: • La instrucción for: Se ejecuta primero la instrucción iniciadora. A continuación, mientras la condición se cumpla, se ejecutan repetidamente las instrucciones, seguidas por la instrucción terminadora. • La instrucción while: Mientras la condición se cumpla, se ejecutan repetidamente las instrucciones. Si la condición no se cumple cuando la ejecución llega a la instrucción while, las instrucciones no se ejecutan ninguna vez. • La instrucción do: Mientras la condición se cumpla, se ejecutan repetidamente las instrucciones. Si la condición no se cumple cuando la ejecución llega a la instrucción do, las instrucciones se ejecutan al menos una vez. • La cuarta instrucción de control es la llamada de subrutina, a la que dedicaremos el apartado siguiente. PROGRAMACIÓN PROCEDIMENTAL La llamada de subrutina (conocida, en general, como instrucción CALL) sirve para relacionar unos programas con otros y permite modular las aplicaciones, descomponiéndolas en dos o más secciones llamadas procedimientos, subrutinas, o funciones, según los casos. Por esta razón los lenguajes de programación clásica se llaman también procedimentales. Gracias a la capacidad de invocar la ejecución de procedimientos, los 17 distintos programas que constituyen una aplicación suelen formar una estructura jerárquica, con un programa principal (main en C) que llama a otros subprogramas, y éstos a otros, hasta llegar a los niveles más bajos de la jerarquía, donde suelen situarse los programas que prestan servicios especiales a casi todos los demás. La jerarquía en cuestión no forma siempre, un árbol invertido, sino un esquema algo más complejo. Es cierto que siempre suele haber un nodo principal o raíz (el programa principal), pero un mismo nodo puede tener más de un antecesor (puesto que una subrutina puede ser invocada por varios módulos). Además, es posible que haya ciclos, simples o compuestos, pues los módulos pueden ser recursivos, directamente o indirectamente. En cambio, en esta forma de programar, los datos no tienen ninguna organización preestablecida: cada programador decide cómo se relacionan unos con otros y cómo se distribuyen entre los subprogramas. En principio, existen dos clases de datos: • Datos globales: son accesibles por todos los subprogramas. • Datos locales: son accesibles por un solo subprograma, módulo o función. A veces, dependiendo del lenguaje de programación, los datos locales son automáticamente heredables por los subprogramas o funciones situados, en la jerarquía de llamadas, por debajo del subprograma en que dichos datos han sido definidos. SISTEMAS DE NUMERACIÓN El primer sistema de numeración del cual se tiene conocimiento fue el sistema egipcio. Posteriores a él son el romano, el maya, el chino, el indio, el árabe original hasta llegar al decimal actual. EL SISTEMA DECIMAL El sistema decimal es u sistema posicional, ya que el significado de un símbolo depende fundamentalmente de su posición relativa al símbolo coma (,), denominado coma decimal, que en caso de ausencia se supone colocada implícitamente a la derecha. Utiliza como base el 10, que corresponde al número de símbolos que comprenden para la representación de cantidades; estos símbolos (también denominados dígitos) son: 0123456789 Una determinada cifra, que se denominará número decimal, se puede expresar de la siguiente forma: n No = (dígito)i * (base)i i= −d Donde: • base = 10 • i = posición respecto a la coma • d = n.o de dígitos a la derecha de la coma, • n = n.o de dígitos a la derecha de la coma − 1, • dígito = cada uno de los que componen el número La fórmula responde al Teorema Fundamental de la Numeración que se verá en el siguiente tema. 18 El sistema decimal es un sistema posicional como ya hemos dicho, ya que el mismo dígito puede variar su valor de acuerdo a su posición. Ej.: 1000 mil 100 cien 10 diez 1 uno 0,1 un décimo 0,01 un centésimo TEOREMA FUNDAMENTAL DE LA NUMERACIÓN El teorema fundamental de la numeración dice: El valor en el sistema decimal de una cantidad expresada en otro sistema cualquiera de numeración, viene dado por la fórmula: ... + X4*B4 + X3*B3 + X2*B2 + X1*B1 + X0*B0 + X−1*B−1 + X−2*B−2 + X−3*B−3 + ... donde X es el dígito y B la base. Ejemplo: Supongamos la cantidad 3221,034 esta expresada en base 4 (ver subíndice al final de la cantidad), dicha base utiliza para representar cantidades los dígitos 0, 1, 2 y 3. ¿Cuál será el valor correspondiente en el sistema decimal? 3 * 43 + 2 * 42 + 2 * 41 + 1 * 40 + 0 * 4−1 + 3 * 4−2 = 3 * 64 + 2 * 16 + 2 * 4 + 1 * 1 + 0 * 0,25 + 3 * 0,0645 = 233,1875 El teorema aplicado a la inversa nos sirve para obtener el valor en una base cualquiera de un valor decimal, por medio de divisiones sucesivas por dicha base, como se verá más adelante. EL SISTEMA BINARIO Por razones técnicas, la mayoría de los circuitos electrónicos que conforman un ordenador solo puede detectar la presencia o ausencia de tensión en el circuito. Si a la presencia de tensión en un punto del circuito le asignamos el valor 1 y a la ausencia de la misma el valor 0 (a esta lógica se la denomina lógica positiva). Caso contrario la denominaremos lógica negativa. Por las razones antes vistas, ya que el hardware por el momento solo reconoce estos dos estados fue necesario crear un sistema de numeración basado en estos dos valores (0, 1), al cual se lo denominó Binario, y cuya base por lo tanto es 2 (números de dígitos del sistema). 19 En computación cada dígito de un número representado en este sistema se denomina bit (contracción de binary digit). Como múltiplos del bit hallamos: • 8 bits " Byte (palabra) B (10110110) • 1024 bytes " 1 kilobyte KB • 1024 KB " 1 Megabyte MB • 1024 MB " 1 Gigabyte GB • 1024 GB " 1 Terabyte TB Dos cosas a tener en cuenta: • La B de byte es siempre mayúscula, ya que Kb significa Kbit unidad utilizada en las memorias. • En el sistema de numeración decimal los múltiplos son potencias 10 (1K " 1000 unidades y 1M " 1000 K), en el binario es 210 = 1024. OPERACIONES CON BINARIOS Tanto la suma como la multiplicación son semejantes a la decimal con la diferencia que se maneja solo dos dígitos, sus tablas de operación se pueden observar en los siguientes esquemas Suma Multiplicación + 0 1 0 0 1 1 1 10 * 0 1 0 0 0 1 0 1 Ejemplos La resta como la división son procesos que la unidad de cálculo del ordenador no realiza por lo tanto no lo vamos a ver en forma directa. EL SISTEMA OCTAL Es un sistema cuya base es el número 8, es decir, utiliza 8 símbolos para la representación de un valor cualquiera. Estos símbolos son: 01234567 Este es un sistema también posicional, de aritmética muy similar al decimal. Su utilización comenzó como sistema de salida de las computadoras ya que para representar un valor la cantidad de símbolos que necesita es menor que el binario y la conversión entre ambos sistemas es muy sencilla de implementar. EL SISTEMA HEXADECIMAL Es un sistema cuya base es el número 16, es decir, utiliza 16 símbolos para la representación de un valor cualquiera. Estos símbolos son: 0123456789ABCDEF 20 Este es otro sistema posicional, de característica similar al octal. Su uso fue adoptado por idénticas razones que el octal. CONVERSIÓN ENTRE LOS DISTINTOS SISTEMAS Se denomina así la transformación de un valor en un sistema al equivalente en otro sistema. Conversión decimal a binario Para convertir un número decimal entero a binario, este debe ser dividido por dos y repetir el proceso con sus cocientes hasta que el cociente tome el valor 1. La unión de todos restos escritos en orden inverso encabezados por el último cociente, nos dará el valor expresado en binario. Ej. : Convertir el número 174 a binario 174 2 0 87 1 2 43 1 2 21 1 2 10 0 2 5 1 2 2 0 2 1 17410 = 101011102 Para convertir una fracción decimal a binario, esta fracción debe ser multiplicada por dos y tomamos la parte entera del resultado, repetimos el proceso con la parte fraccionaria del resultado anterior, dándonos una nueva parte entera, y así sucesivamente hasta que la parte fraccionaria se haga 0 (cero) o que tengamos suficientes decimales que nos permita estar debajo de un determinado error. Ej. : Convertir el número 0,90625 a fracción binaria 0,90625 * 2 = 1,8125 0,8125 * 2 = 1,625 0,625 * 2 = 1,25 0,25 * 2 = 0,5 0,5 * 2 = 1, 0,9062510 = 0,111012 Ej. : Convertir el número 0,64037 a fracción binaria 0,64037 * 2 = 1,28074 0,28074 * 2 = 0,56148 21 0,56148 * 2 = 1,12296 0,12296 * 2 = 0,24592 0,24592 * 2 = 0,49184 0,49184 * 2 = 0,98368 0,98368 * 2 = 1,96736 0,96736 * 2 = 1,93472 0,93472 * 2 = 1,86944 0,86944 * 2 = 1,73888 0, 6403710 = 0,10100011112 El error en el valor es " 2−10 ! " 0,001. Esto es así porque hemos obtenido 10 unidades binarias, de querer mejorar la precisión deberemos obtener un mayor número de fracciones binarias. Pase a binario las siguientes fracciones decimales con " 2−10 : 0,63965 y 0,064062. Si se desea convertir un número que tiene parte entera y decimal a binario, se deberá operar cada parte por separado como ya se ha visto, y luego obtener la suma de los resultados. Por ejemplo: 174,9062510 = 10101110,111012 Conversión binario a decimal Para realizar esta conversión se utiliza como base el teorema fundamental de la numeración. El método práctico consiste en multiplicar cada uno de los términos por potencias crecientes de 2 a partir de la coma decimal y hacia la izquierda, y realizar la suma de las operaciones. Por ejemplo: Pasar a decimal el binario 101011102 10101110 0 * 20 = 1 * 21 = 1 * 22 = 1 * 23 = 0 * 24 = 1 * 25 = 0 * 26 = 1 * 27 = 0 2 4 8 0 32 0 128 22 174 101011102 = 17410 En los casos de números que posean parte entera y decimal se recomienda el uso del teorema fundamental de la numeración. Ej.: Convertir 1101,0112 a base 10 Para pasar a base 10 deberemos hacer: 1 * 23 + 1 * 22 + 0 * 21 + 1 * 20 + 0 * 2−1 + 1 * 2−2 + 1 * 2−3 = 1 * 8 + 1 * 4 + 0 + 1 * 1 + 0 + 1 * 0,25 + 1 * 0,125 = 8 + 4 + 0 + 1 + 0 + 0,25 + 0,125 = 13,375 1101,0112 = 13,37510 Conversión octal a binario Al ser la base del octal (8) potencia de la base binaria (23), la transformación de una base a la otra se hace en forma directa dígito a dígito. Cada dígito octal será reemplazado por 3 dígitos binarios (3 por ser la potencia que relaciona ambas bases), según la tabla que tenemos a continuación. Octal 0 1 2 3 4 5 6 7 Binario 000 001 010 011 100 101 110 111 Ej.: Convertir a binario el número 276,5348 2 010 7 111 6, 110, 5 101 3 011 4 100 276,5348 = 10111110,10101112 Como se puede ver los ceros al comienzo se han quitado, igual que los ceros que se hallan a la derecha de la coma (ya que no tienen ningún sentido). Conversión binario a octal 23 Esta conversión es similar a la anterior, pero cada tres símbolos binarios corresponde uno octal. Para realizar correctamente esta conversión el número de dígitos a la derecha de la coma decimal debe ser múltiplo de 3 si no lo fuera deberá agregarse al final del número tantos ceros como sea necesario. Idéntico caso será a la izquierda de la coma, en dicho caso los ceros se agregan al principio del número. Ej. Convertir el binario 10101011,0011 a octal. 010 2 101 5 011, 3, 001 1 100 4 0 cero agregado al número para permitir la correcta conversión. 10101011,00112 = 253,148 Conversión hexadecimal a binario Por idénticas razones que el caso anterior (16 = 24), la transformación de una base a la otra se hace en forma directa dígito a dígito. Cada dígito hexadecimal será reemplazado por 4 dígitos binarios (4 por ser la potencia que relaciona ambas bases), según la tabla que tenemos a continuación. Hexadecimal 0 1 2 3 4 5 6 7 Binario 0000 0001 0010 0011 0100 0101 0110 0111 Hexadecimal 8 9 A B C D E F Binario 1000 1001 1010 1011 1100 1101 1110 1111 Ej.: Convertir a binario el número 5A8,39C16 5 0101 A 1010 8, 1000, 3 0011 9 1001 C 1100 5A8,39C16 = 10110101000,00111001112 Como se puede ver otra vez los ceros al comienzo se han quitado, igual que los ceros que se hallan a la derecha de la coma (ya que no tienen ningún sentido). Conversión binario a hexadecimal Esta conversión es similar a la conversión a octal, pero en lugar de tres, serán cuatro símbolos binarios los que corresponde a un hexadecimal. Para realizar correctamente esta conversión el número de dígitos a la derecha de la coma decimal debe ser múltiplo de 4 si no lo fuera deberá agregarse al final del número tantos ceros como sea necesario. Idéntico caso será a la izquierda de la coma, en dicho caso los ceros se agregan al 24 principio del número. Ej. Convertir el binario 1010101011,00111 a hexadecimal. 0010 2 1010 A 1011, B, 0011 3 1000 8 0 cero agregado al número para permitir la correcta conversión. 1010101011,00111 2 = 2AB,38816 Conversión decimal a octal o hexadecimal Para cualquiera de estos dos casos se hará en forma similar a la explicada para convertir de decimal a binario 1.7.1. Pero se deberá tener en cuenta que la base ya no es 2, sino 8 o 16 según corresponda. (Dividir por 8 o 16) Conversión octal o hexadecimal a decimal Para cualquiera de estos dos casos se deberá usar el teorema fundamental de la numeración, teniendo en cuenta base que corresponda ( 8 o 16 según el caso). Conversión octal a hexadecimal o hexadecimal a octal. Estas conversiones no son posibles en una forma directa. Para realizar cualquiera de ellas se deberá usar el pasaje a otra base como paso intermedio. Por ejemplo octal ! decimal ! hexadecimal octal ! binario ! hexadecimal Se recomienda como metodología de trabajo esta última, porque al ser las operaciones de conversión más sencillas disminuye la probabilidad de error. Además no existe la posibilidad de errores de redondeo. REPRESENTACIÓN DE NÚMEROS ENTEROS Existen 4 formas de representar un número entero en un ordenador (todos en sistema binario), ellas son • Módulo y signo • Complemento a 1 (C−1) • Complemento a 2 (C−2) • Exceso a 2 elevado a la N −1 En todos los casos se considera que tenemos un número limitado de dígitos para cada elemento numérico. El número de dígitos disponibles lo representa N (8, 16, 32, 64 o sea 1, 2, 3, 4... Bytes). Módulo y signo. En este método se utiliza el primer bit a la izquierda como signo, 0 si es positivo y uno si es negativo. Los restantes (7, 15, etc.), representan el módulo 25 Por ejemplo Signo Mantisa 19 se representa en 8 bits como 0 0010011 −19 1 0010011 19 se representa en 16 bits como 0 000000000010011 −19 1 000000000010011 El conjunto de valores que se puede representar en un método determinado se conoce como rango de la representación. Para módulo y signo el rango de representación para N dígitos es: − 2N−1 +1 " x " 2N−1 −1 Para 1 Byte (8 bits) es −127 " x " 127 Para 2 Byte (16 bits) es −32767 " x " 32767 Para 4 Byte (32 bits) es −2147483647 " x " 2147483647 Este método tiene la ventaja de poseer un rango simétrico, pero la desventaja de poseer dos representaciones para el número 0 Complemento a 1 (C−1). Para representar un número positivo es igual al método de MS. Pero en el caso de los negativos, se obtiene complementando al positivo (cambiando 1 por 0 y viceversa) Por ejemplo Signo Mantisa 19 se representa en 8 bits como 0 0010011 −19 1 1101100 19 se representa en 16 bits como 0 000000000010011 −19 1 111111111101100 Para complemento a 1 el rango de representación para N dígitos es: − 2N−1 +1 " x " 2N−1 −1 26 Para 1 Byte (8 bits) es −127 " x " 127 Para 2 Byte (16 bits) es −32767 " x " 32767 Para 4 Byte (32 bits) es −2147483647 " x " 2147483647 Este método presenta iguales ventajas y desventajas que el anterior. Complemento a 2 (C−2) Este método es similar al anterior, la representación de los números positivos es igual a la anterior, pero los negativos se obtiene en dos pasos: • Se complementa a 1 • Al resultado se le suma 1 Por ejemplo 19 se representa en 8 bits como 0 0010011 −19 1 1101100 C−1 +1 −19 1 1101101 C−2 Para complemento a 2 el rango de representación para N dígitos es: − 2N−1 " x " 2N−1 −1 Para 1 Byte (8 bits) es −128 " x " 127 Para 2 Byte (16 bits) es −32768 " x " 32767 Para 4 Byte (32 bits) es −2147483648 " x " 2147483647 Presenta la siguientes ventajas. Tiene una única representación para 0, la segunda es que en lugar de hacer A − B, puedo hacer A + BC−2. La unidad aritmético lógica del microprocesador solo suma, no resta. Exceso a 2 elevado a la N −1 27 En este método no hay bit de signo, todos los bits se utilizan para representar el valor del número más el exceso, que para N bits viene dado por 2N−1, que para una representación de 8 bits es 128. Para obtener un número en un exceso dado, se realiza la suma algebraica del exceso más el número. Solo se pueden representar valores en módulo menores o iguales al exceso. Ej. Exceso 128 10000000 19 + 00010011 19 en exceso 128 10010011 Por ejemplo 19 se representa en 8 bits como 1 0010011 −19 0 1101101 En este método el 0 tiene única representación, el rango de representación es asimétrico. Para complemento a 2 el rango de representación para N dígitos es: − 2N−1 " x " 2N−1 −1 Para 1 Byte (8 bits) es −128 " x " 127 Para 2 Byte (16 bits) es −32768 " x " 32767 Para 4 Byte (32 bits) es −2147483648 " x " 2147483647 La representación en exceso para un número cualquiera es igual a la representación en complemento a dos pero el valor del primer bit de la izquierda esta invertido. DESBORDAMIENTO (OVERFLOW) Este hecho se puede producir cuando se suman dos números en un método de representación y el resultado no puede ser representado por el método, dándonos un resultado erróneo. Para el ejemplo usaremos la notación de MS Ej. 52 0 0 1 1 0 1 0 0 52 + 97 + 0 1 1 0 0 0 0 1 97 28 149 1 0 0 1 0 1 0 1 −21 PRECISION FINITA DE LA INFORMACIÓN Muchos estudiantes consideran que el ordenador puede trabajar con números con cantidades de cifras infinitamente grande. Este preconcepto es uno de los más erróneos que se puede detectar en el alumno. Todo ordenador cuenta con un número finito de Bytes para poder almacenar una cifra. Este número puede ser de 1, 2, 4, 6, 8, 10 Bytes, pero nunca infinito. Por lo tanto solo se podrá ingresa, procesar, almacenar y extraer un rango de valores. Por ejemplo para números enteros se utiliza como máximo 4 Bytes (32 bits), siendo el rango de representación entre −247483648... 247483647. Coma Flotante Este método nace de la necesidad de representar números reales o enteros con un rango mayor que el dado por los otros métodos. En su representación se utiliza la representación matemática NO = mantisa * base exponente Por ejemplo 79436.54 = 0,7943654 * 105 A este proceso se lo denomina normalización. Para estos números se utilizan explicaremos dos formas de representación simple y doble precisión, pero existen otros formatos como real, extended, o comp. Para simple precisión se utiliza 32 bits (4 Bytes), en el segundo caso 64 bits (8 Bytes). (Todos los elementos en computación se comienzan a numerar por 0) El esquema en ambos casos es como se ve abajo Signo Exponente Mantisa Simple Precisión C. de bits B. Inicial 1 31 8 23 23 0 B. Final 30 22 Doble Precisión C. de bits B. Inicial 1 63 11 52 52 0 B. Final 62 51 Ejemplos de Pasajes de Decimal a Flotante 57 a Flotante 1) Paso 57 a Binario 57 ! 111001 2) Normalizo el binario 29 111001 ! 0,111001 * 26 3) Paso el exponente a binario 6 ! 110 4) Si trabajo en Simple Precisión (SP) lo expreso como excedente a 10000000 (por los 8 bits), si es en Doble Precisión como excedente a 10000000000 (por los 11 bits). EL exponente nos queda así. SP 10000110 DP 10000000110 5) Como el número es positivo el bit de signo es 0 El número queda estructurado de la siguiente manera SP Signo 0 Exponente 10000110 Mantisa 111001 Debería agregar 0 hasta completar los 24 bits El número en cuestión nos queda 0100 0011 0111 0010 0000 0000 7) Lo paso a HEXADECIMAL y nos queda 437216 En el caso de − 56 8) Como el número es negativo el bit de signo es 1 El número queda estructurado de la siguiente manera SP Signo 1 Exponente 10000110 Mantisa 111001 Debería agregar 0 hasta completar los 24 bits El número en cuestión nos queda 1100 0011 0111 0010 0000 0000 9) Lo paso a HEXADECIMAL y nos queda C37216 Ejemplo de exponente negativo El número 0, 13671875 repito los pasos anteriorres. 30 Paso a binario 0,13671875 ! 0,00100011 Normalizo 0,001000112 ! 0,1000112 *2−2 Paso el modulo de la potencia a Binario 2 ! 102 Si trabajo en Simple Precisión (SP) lo expreso como excedente a 10000000 EL exponente nos queda así. SP 01111110 Como el número es positivo el bit de signo es 0 El número queda estructurado de la siguiente manera SP Signo 0 Exponente 01111110 Mantisa 100011 Debería agregar 0 hasta completar los 24 bits El número en cuestión nos queda 0011 1111 0100 0110 (no se completó con ceros porque su representación en Hexadecimal son 0 que no afectan el número final) Lo paso a HEXADECIMAL y nos queda 3F4616 Si el número fuera negativo el bit de signo es 1 El número queda estructurado de la siguiente manera SP Signo 1 Exponente 01111110 Mantisa 100011 Debería agrega 0 hasta completar los 24 bits El número en cuestión nos queda 1011 1111 0100 0110 Lo paso a HEXADECIMAL y nos queda BF4616 31 Si el número (−0,13671875) quisiéramos expresarlo en flotante de 64 bits, el único cambio que tendríamos sería el exponente que ya no tiene 8 bits sino 11 bits quedándonos. El número queda estructurado de la siguiente manera SP Signo 1 Exponente 01111111110 Mantisa 100011 El número en cuestión nos queda 1011 1111 1110 1000 1100 Lo paso a HEXADECIMAL y nos queda BFE8C16 Como se puede ver el mismo número según se represente en 32 o en 64 bits −0,13671875 32 bits BF460000 64 bits BFE8C00000000000 Los ceros a la izquierda no son representativos, pueden o no escribirse. Este método de representación tiene sus rangos de representación los cuales no incluyen el número 0 (cero). Se puede representar números muy próximos a 0 pero no incluye este número. El módulo mayor que se puede expresar en doble precisión es 1,710 * 10308, con una precisión de 15 a 16 cifras(ver transformación de fracciones decimales a binarios). El número más próximo a cero será 1 * 10−309. El módulo mayor que se puede expresar en punto flotante (extended) es 1,10 * 104932. REPRESENTACIÓN INTERNA DE LA INFORMACIÓN: Codificación alfanumérica Cada vez que presionamos una tecla cualquiera en nuestra computadora, esta convierte el carácter presionado en un conjunto bits. Para esta transformación se utilizaron y se utilizan distintos códigos. El primero fue un código de 6 bits denominado FIELDATA. Es código fue reemplazado por el ASCII (American Standard Code for Information Interchange) que era un código de 7 bits (tenía 128 caracteres posibles), luego aparece el EBCDIC que fue el primer código de 8 bits por último aparece para el ambiente de PC el ASCII extendido que también es de 8 bits (256 caracteres). Tabla de conversión Decimal 0 1 2 3 4 5 6 Binario 0000 0001 0010 0011 0100 0101 0110 Octal 00 01 02 03 04 05 06 Hexadecimal 0 1 2 3 4 5 6 32 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 0111 1000 1001 1010 1011 1100 1101 1110 1111 10000 10001 10010 10011 10100 10101 10110 10111 11000 11001 11010 11011 11100 11101 11110 11111 100000 07 10 11 12 13 14 15 16 17 20 21 22 23 24 25 26 27 30 31 32 33 34 35 36 37 40 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 SISTEMAS DE NUMERACIÓN Práctica 1 − Pasar a base 10 los siguientes números, de las bases indicadas: 11012 0,101 2 101,11 2 1,01112 753 8 0,63 8 17,134 8 3A 16 0,FF 16 A5,3B 16 2 − Pasar los siguientes números de base 10 a la base indicada: 39 ! 2 0,525 ! 2 23,945 ! 2 123 ! 8 3,1 ! 8 0,14 ! 8 1068 ! 16 61,6 ! 16 3 Pasar el siguiente decimal a la base indicada con un error menor o igual al indicado Número Base Error 33 0,267 52,38 129,64 163,97 954,62 2 2 2 8 16 0,001 0,0001 0,1 0,0001 0,0001 4 − Pasar a las bases indicadas usando propiedad de base de potencia de otra base: 32 8 ! 2 F1 16 ! 8 F1 16 ! 2 73 8 ! 16 1010 2! 16 10,10 2 ! 8 5 − Realizar las siguientes sumas: 1010 2 + 0101 2 1001 2 + 0110 2 1110 2 + 1010 2 7354 8 + 1123 8 F1E5 16 + ABC116 3231 4 + 2123 4 0334 8 − 0137 8 1060 8 − 1776 8 6 − Realizar las siguientes restas: F91F 16 − 0101 16 7 − Realizar las siguientes operaciones por Complemento a la Base 100111012 − 001100112 011101012 − 000111112 001000112 − 000110012 8 − Realizar las siguientes restas en base 2. Los números tienen signo. 01000 − 00101 11001 − 00111 00110 − 11000 047 8 x 010 8 0018 18 x 010 18 9 − Realizar los siguientes productos. 0018 16 x 100 16 10 − Escribir con notación exceso 10000000 2 34 1010 2 − F1 16 3014 8 −1100 2 − 513 8 − 37 16 11 − Escribir como complemento a Dos (en 16 bits): 35 10 − 47 10 F1 16 − 16 16 12 − Escribir como complemento a Dos (en 32 bits): − 93 10 − FF 16 − F3 16 − 16 16 − 10 10 − 31 10 13 − Pasar a base 10 los números (16 bits complemento a dos): 1) 1000000000101000 2) 1110100000010101 3) 1001111011010111 4) 1000000000010101 14 − Pasar a base 10 los siguientes números expresados como punto fijo sin signo (16 bits) 1000000000101000 0110100000010101 1001111011010111 0000000000010101 15 − Escribir con notación exceso 10000000 2 1010 2 − F1 16 3014 5 33 4 − 513 6 − 37 16 16 − Escribir en base 2 y operar por complemento a la base 5349 10 − F1F0 16 + −34312 10 317F 16 −3511 10 − 39F1 16 17 − Escribir como complemento a Dos (en 16 bits): 35 10 − 47 10 F1 16 − 16 16 18 − Escribir como complemento a Dos (en 32 bits): − 93 10 − FF 16 − F3 16 − 16 16 − 10 10 − 31 10 19 − Expresar en base 10 los siguientes números dados en formato de Punto Flotante 35A1F 93900D ECF 3ED 35 20 − Pasar a base 10 los números (16 bits complemento a dos): 1) 1000000000101000 2) 0110100000010101 3) 1001111011010111 4) 0000000000010101 Realizar 1) + 2) y 1) − 4) 21 − Pasar a base 10 los siguientes números expresados como punto fijo sin signo (16 bits) 1000000000101000 0110100000010101 1001111011010111 0000000000010101 22 − Pasar a Punto Flotante: 39 −5826 0,0103 −0,00002103 9F1 −74F28B 9F3,G1 −0,002A359 23 − Decir que número decimal, representa el siguiente número expresado como Punto Flotante 9 E C 1 9 3 5 F 16 3 E A C 1 0 0 0 16 C D 9 4 0 1 0 3 16 A E 8 F 5 0 0 0 16 INTRODUCCIÓN A PASCAL PROGRAMACIÓN Los pasos necesarios para la creación de un programa son: • Análisis • Diseño del algoritmo • Construcción del programa (en un lenguaje de programación) • Ejecución • Validación • Mantenimiento ALGORITMO Es una secuencia ordenada de pasos − sin ambigüedades −, repetible, que es solución de un determinado problema. Las características fundamentales que debe cumplir todo algoritmo son: • Debe ser preciso e indicar el orden de realización de cada paso • Debe estar definido (si se repite n veces los pasos se debe obtener siempre el mismo resultado) • Debe ser finito (debe tener un número finito de pasos) • Es independiente del lenguaje de programación que se utilice La definición de un algoritmo debe describir tres parte Entrada, Proceso, Salida. PASCAL 36 Es un lenguaje de alto nivel, fuertemente tipeado (se debe definir el tipo de todos los datos), de propósito general, compilable, estructurado y procedimental. Un lenguaje compilable significa que todo programa será deberá pasar por los siguientes pasos: • Será escrito en un editor de texto (en un formato ASCII) • Luego lo toma el Compilador comprueba que todas las instrucciones del programa estan escritas siguiendo la sintaxis de PASCAL. Si todo es correcto lo traduce a Lenguaje de Máquina (Assembler). • Pasa posteriormente al Linkeador (o montador), une los distintos módulos que pueden componer un programa, unifica los códigos de los distintos subprogramas, y de los datos. Pasándolo por último a código de máquina. TIPOS DE DATOS Los diferentes objetos de información con los que un programa Pascal trabaja se conocen colectivamente como datos. Todos las datos tienen un tipo asociado can ellos. Un dato puede ser un simple carácter, tal como 's', un valor entero tal como 35 o un número real tal como 1415,92. Una operación de suma no tiene sentido con caracteres, sólo con números. Por consiguiente, si el compilador detecta una operación de suma de dos caracteres, normalmente producirá un error. Incluso entre tipos numéricos, la operación de suma se almacena de modo distinto. Esto se debe a que números enteros y reales se almacenan de modos diferentes. A menos que el programa conozca el tipo de datos, si es un valor entero a real, no Puede ejecutar correctamente la operación de suma La asignación de tipos a los datos tiene dos objetivos principales. 1. Detectar errores de operaciones en programas 2. Determinar cómo ejecutar las operaciones Pascal se conoce como lenguaje "fuertemente tipeado" (strongly.typed) o de tipos fuertes. Esto significa que todos las datos utilizados deben tener sus tipos declarados explícitamente y el lenguaje limita la mezcla de tipos en las expresiones. Pascal detecta muchos errores de programación antes que el programa se ejecute. La ventaja de los lenguajes de tipos fuertes (ricos en tipos de datos) es que se gasta menos esfuerzo en la depuración de programa, ya que el compilador detecta muchos de esos errores El tipo de un dato determina la naturaleza del conjunto de valores que puede tomar una variable. Otro concepto importante a tener en cuenta es la representación interna de los números, o al menos el espacio de memoria ocupado por una variable de un tipo dado. La unidad de medida de la capacidad de memoria, como ya hemos visto es el byte (octeto). Un byte se compone de ocho cifras binarias (bits) que Pueden tomar cada una el valor 0 ó 1. Ordinales Integer Boolean Char Enumerado Subrango No Ordinales Reales Tipos Simple Datos Estáticos Tipos de Datos Tipos Cadena String Array 37 Registro Tipos Estructurado Conjunto Archivo Tipos procedimientos Datos Dinámicos Procesos Tipos Punteros Tipos Enteros Tipo byte integer longint shortint word Rango 0 .. 255 −32768 .. 32767 −247483648 .. 24748367 −128 .. 127 0 .. 65535 Formato 1 Byte 2 Bytes 4 Bytes 1 Byte 2 Bytes El tipo integer se almacena en memoria como 2 (dos) bytes, el bit de mayor peso de los dos bytes es el bit de signo. Se puede separar un entero en sus dos bytes utilizando las funciones internas Hi y Lo Hi devuelve el byte de mayor peso de los dos bytes de memoria Lo devuelve el byte de menor peso Números Reales Tipo real single double extended comp Rango 2.9x10−39 .. 1.7x1038 1.5x10−45 .. 3.4x1038 5.0x10−324 .. 1.7x10308 1.9x10−4932 .. 1.1x104932 −(263 +1) .. 263 +1 Cifras 11−12 7−8 15−16 19−20 19−20 bytes 6 4 8 10 8 Tipos carácter (Char) El tipo char es un tipo de datos que puede contener un solo carácter. Cada uno de estos caracteres puede ser expresado gracias al código ASCII ampliado. Ejemplo `A' `a' `b' `*' `5' ` ` Se le puede asignar a una constante un carácter por medio de su código #65 equivale a chr(65) equivale A #26 o ^Z cierre del archivo #27 tecla ESC 38 #13 tecla ENTER Tipos lógicos (boolean) El tipo lógico (boolean) es, al igual que el carácter, parte de ISO Pascal estándar. Los valores de tipa lógico pueden tomar sólo das valores posibles: true (verdadero) y false (falso). Al igual que el tipo char, el tipo boolean es un tipo ordinal, que significa que tiene un núméro fijo de posibles valores que existen en un orden definido. Una variable lógica ocupa sólo un byte en memoria. Los valores lógicas son de tipo ordinal, y sus relaciones son: faÍse < true Tipos de datos definidos por el usuario Todos los tipos de datos estudiados hasta ahora son de tipo simple, predefinidos por Turbo y listos para utilizar. Sin embargo, uno de los aspectos más potentes de Turbo Pascal es su capacidad para crear estructuras de datos a partir de estos datos simples. Los datos estructurados aumentan la legibilidad de los programas y simplifican su mantenimiento. Los tipos de datos definidas por el usuario se clasifican en: • Escalares definidos por el usuario (enumemdo y subrango) • Registros • Arrays • Conjunto (set). • Archivo (file). • Puntero • Procedimiento Estos tipos de datos se verán en sucesivas clases. Tipo cadena (string) Un tipo string (cadena) es una secuencia de caracteres de cero o más caracteres correspondientes al código ASCII, escrito en una línea sobre el programa y encerrada entre apóstrofos. El tratamiento de cadenas es una característica muy potente de Turbo Pascal que no contiene ISO Pascal estándar, aunque tiene mucha similitud con el tipo packed array. Ejemplos 'Turbo' 'Estás de acuerdo' #13#10 `,' Notas Una cadena sin nada entre las apóstrofos se llama cadena nula o cadena vacía La longitud de una cadena es el número de caracteres encerrados entre los apóstrofos. CONSTANTES Una constante es un valor que no puede cambiar durante la ejecución del programa, recibe un valor en el 39 momento de la compilación del programa y este valor no puede ser modificado. Las constantes pueden ser constantes literales constantes con nombres o declaradas constantes expresión (sólo en la versión 5.0) constantes de tipos (tipeadas) Las constantes deben ser declaradas antes de su utilización y pueden ser enteros o reales, caracteres o cadenas de caracteres, conjuntos o arrays, e inclusive de tipo enumerado • Constantes literales Una constante literal es un valor de cualquier tipo que se utiliza como tal. VolumenEsfera := 4/3 * Pi * Radio * Rádio * Rádio, 4 y 3 son constantes literales de valores 4 y 3. • Constantes con nombres Son constantes que se identifican por un nombre y el valor asignado. Formato const identificador = valor, Ejemplos const Pi = 3.141592; {lee un valor real} DosPi = 2 * Pi; Direccion = $06; { representa valor hexadecimal } caracter = 'B'; { es un carácter } cuenta = 625; { lee un entero } Epsilon = 1E−4; { lee un real } Esc = #27; { carácter de control } CRLF = ^M^J; { secuencia CR/LF. retorno de carro/avance de lineal } 40 En Pascal estándar, la declaración de constantes se sitúa inmediatamente después de la cabecera Program. En Turbo Pascal no es obligatoria la situación anterior, pero si recomendable. VARIABLES Las variables son objetos cuyo valor puede cambiar durante la ejecución del programa. El cambio se produce mediante sentencia ejecutables. Todas las variables de un programa Pascal deben ser declaradas antes de ser usadas Declaraciones var variable1 : tipo1; variable2 : tipo2; ......................... ......................... variableN : tipoN; Ejemplos NumeroEmpleado : Integer; { número de empleado } Horas : real; { horas trabajadas } Tasas : real; { tasa horaria } Edad : Integer; { edad del empleado } Apellidos : string [30]; { apellidos del empleado } Letra1, Letra2, Letra3 : char; Num1, Num2 : integer; Notas Es buena práctica de programación utilizar nombres de variables significativas que sugieren lo que ellas representan, ya que esto hace al programa más legible y fácil de comprender, también es buena práctica incluir breves comentarios que indiquen cómo se utiliza la variable. Un comentario es cualquier frase encerrada entre llaves { } o bien entre signos (*, *) SENTENCIAS Las sentencias describen las acciones algorítmicas que pueden ser ejecutadas En general las sentencias se clasifican en, ejecutables (especifican operaciones de cálculos aritméticos y entradas/salidas de datos) y no ejecutables (no realizan acciones concretas, ayudan a la legibilidad del programa, pero no afectan en la 41 ejecución del Programa). Las sentencias ejecutables aparecen en el cuerpo del programa a continuación de la palabra reservada Begin LA SENTENCIA DE ASIGNACION La sentencia de asignación se utiliza para asignar (almacenar) valores o variables. La asignación es una operación que sitúa un valor determinada en una posición de memoria. la operación de asignación se demuestra en pseudocódigo con el símbolo '!', para denotar que el valor situado a su derecha se almacena en la variable situada a la izquierda Formato Variable ! expresión variable identificador válido declarado anteriormente expresión variable, constante o una expresión o fórmula a evaluar En Pascal el operador '!−' se sustituye por el símbolo := , que se denomina operador de asignación Variable := expresión El valor de expresión se asigna a la variable. Precaución El tipo de expresión debe ser del mismo tipo que el de la variable. Ejemplos A :=16 ; 16 se asigna a la variable A Inicial := 'LJ'; se asigna LJ a la variable Inicial Interruptor :=true; se asigna el valor true. (verdadero) a Interruptor N1 := N2; el valor de la variable N1 se cambia por el valor de la variable N2 N1 := N1 + 5; el valor de la variable N1 se incrementa en 5 Car := #70; se asigna a la variable Car el carácter 70 del código ASCII, es decir `F' Operaciones especiales de asignación Contador Un contador es una variable que se incrementa, cuando se ejecuta, en una unidad o en una cantidad constante. Contador .= 25 x: = 5 Contador := Contador + 1; x := x + 1; 42 N = 15 N :=N + 1; Al ejecutar Las sentencias de asignación, los nuevos valores de Contador y N son 25+1=26 y 50+1 =51. Acumulador Es una variable que se incrementa en una cantidad variable. Suma := Suma + x; x es una vanable Si x vale 7 y Suma 40, el nuevo valor de Suma será 47 Las operaciones contador y acumulador son de gran utilidad en programación. EXPRESIONES Y OPERACIONES ARITMETICAS Las variables y constantes estudiadas anteriormente se pueden procesar utilizando operaciones y funciones adecuadas a sus tipos En este punto se examinarán las expresiones y operaciones que se utilizan con datos numéricos. • Operadores aritméticos: +, −, *, / Los operadores aritméticos (+,−, *) pueden ser utilizados con tipos enteros o reales. Si ambos son enteros, el resultado es entero; si alguno de ellos es real, el resultado es real. 2+3 = 5 2+3.0 = 5.0 Operadores aritméticos div y mod Solo se pueden utilizar con enteros, la salida es otro entero. Div devuelve el valor de la división entera y Mod da el resto de la división entera. 17 DIV 5 ! 3 17 MOD 5 ! 2 Reglas de expresiones (prioridad) Se respeta las mismas prioridades del álgebra. OPERACIONES ENTRADA/SALIDA Los datos se pueden almacenar en memoria de tres formas diferentes: asociados con constantes, asignados a una variable con una sentencia de asignación o una sentencia de lectura. Ya se han examinado las dos primeras. El tercer método, la sentencia de lectura, es cl más indicado si se desea manipular diferentes datos cada vez que se ejecuta cl problema. Además. la lectura de datos permite asignar valores desde dispositivos hasta archivos externos (por ejemplo, un teclado o una unidad de disco) en memoria se denomina operación de entrada o lectura A medida que se realizan cálculos en un programa, se necesitan visualizar los resultados Esta operación se 43 conoce como operación de salida o de escritura En los algoritmos las instrucciones de entrada/salida escritas en pseudocódigo son: leer (listas de variables entrada) leer (v. z, x) escribir (listas de variables salida) escribir (a, b, c) En Pascal todas las operaciones de entrada/salida se realizan ejecutando unidades de programa especiales denominadas procedimientos de entrada/salida que forman parte del compilador Pascal y sus nombres son identificadores estándar: Procedimientos de entrada Read ReadLn procedimientos de salida Write WriteLn La escritura de resultados (salida) Los programas para ser útiles deben proporcionar información de salida (resultados) Esta salida toma información de la memoria y la sitúa (almacena) en: la pantalla, en un dispositivo de almacenamiento (disco duro o flexible), o en un puerto de E/S (puertos serie para comunicaciones o impresoras, normalmente paralelos) Procedimiento WriteLn El propósito de WriteLn es escribir (visualizar) información en la pantalla Formato WriteLn (ítem, ítem..): 1 ítem el objeto que desea visualizar: un valor literal (entero, real, un carácter una cadena, o un valor lógicotrue o false). una constante con nombre, una variable, o una llamada a función Cuando se ejecuta el procedimiento WriteLn, se visualizan todos los elementos en el orden dado y en la misma línea. Al terminar de visualizar toda la línea, el cursor avanza (salta) al comienzo de la siguiente línea. Procedimiento Write Como se ha dicho, después de ejecutar el procedimiento WriteLn, el cursor avanza (salta) al comienzo de la siguiente línea. Si se desea que el cursor quede en ;a misma línea se debe utilizar el procedimiento Write. Formatos de salida Turbo Pascal permiten controlar en cierta medida las instrucciones de salida que presentan resultados. Es posible especificar el número de posiciones del campo de escritura. Para los números reales es posible precisar el número de decimales deseado.Se pueden utilizar especificadores de formato de campo para definir dicha anchura.x := 265.7892 WriteLn(x :10 :4); 265.7892 WriteLn(x :10 :2); 265.79 WriteLn(x :6 :4); ********* 44 X := 14; WriteLn(x :4); 14 X := `AB' WriteLn(x :4); AB Lo anteriormente expresado es válido para el proceso WRITE Impresión de resultados (salidas a impresora) Las salidas a pantalla se obtienen mediante los procedimientos Write y WriteLn. Si se desea enviar resultados a otro dispositivo, es preciso especificar el nombre del archivo como primer argumento de las instrucciones Write y WriteLn. Para poder realizar la operación de enviar salidas a la impresora, en lugar de a la pantalla, se necesita la unidad Printer. Printer define un archivo llamado lst y asocia este archivo al puerto de comunicaciones LPTI (impresora) del DOS. Se pueden enviar datos a la impresora, incluyendo lst en las instrucciones Write y WriteLn. Es preciso, sin embargo, definir previamente en la sección uses la unidad printer. Ejemplo uses Printer var ......................... begin ......................... Write (Lst, 'el .......................... ) WriteLn (Lst, 'pl............ ) ......................... end. Este programa imprime en la impresora: Regla Siempre que desee escribir en impresora, deberá incluir en su programa la línea uses printer y luego añadir en cada sentencia Write/WriteLn la palabra lst 45 La entrada de datos (lectura) Los datos que se pueden leer son: enteros, reales, caracteres o cadenas. No se puede leer un boolean o un elemento de tipo enumerado. Los datos estructurados, arrays, registros o conjuntos, no se pueden leer globalmente y se suele recurrir a diseñar procedimientos específicos. Los procedimientos de lectura son Read y ReadLn. Formato Read (van, var2, ...); ReadLn (van, var2, ...); var igual que WRITE La entrada de datos desde el teclado se hace un valor cada vez. Las instrucciones ReadLn y Read esperan hasta que se pulsa la tecla INTRO (RETURN o ENTER) antes de asignar un valor a la variable. Ejemplo ReadLn (Nombre); ReadLn (Horas); Read (Tasas) El usuario debe introducir los datos de entrada en el orden en que aparecen las instrucciones read, Diferencias entre Read y ReadLn En Read, después de pulsar la tecla INTRO, el cursor permanece inmediatamente después del último carácter introducido. En ReadLn, el cursor se envía al principio de la siguiente línea, tras pulsar la tecla INTRO. No es aconsejable ingresar más de un dato por instrucción. OPERACIONES BASICAS DE UTILIDAD En este punto se describen dos utilidades: Clrscr limpieza o borrado de la pantalla GotoXY movimiento del cursor El borrado (limpieza) de la pantalla: Clrscr Las órdenes o procedimientos que podrá utilizar a partir de ahora: Clrscr y GotoXY, aunque posteriormente se volverán a mencionar. Ambos procedimientos pertenecen a la unidad Crt. La orden (procedimiento) Clrscr borra (limpia) la pantalla (ventana actual) y sitúa el cursor en la esquina 46 superior izquierda. Turbo Pascal considera las coordenadas de la esquina superior izquierda :1,1. Para poder utilizar Clrscr, deberá declarar en la cláusula uses la unidad Crt. Regla Es una buena costumbre utilizar en todos los programas la unidad Crt, mediante la cláusula uses; ello permite el uso de Clrscr y GotoXY, entre otras rutinas de utilidad. Movimiento del cursor La orden (procedimiento) GotoXY mueve el cursor a la posición x, y, donde x es la columna (contando de izquierda a derecha) e y es la fila (contando de arriba−abajo). GotoXY (x, y) La esquina superior izquierda es 1.1. GotoXY requiere el uso de la unidad Crt. EL ESTILO DE PROGRAMACIÓN El buen estilo de programación es, sin lugar a duda, una de las características más notables que debe tener un programador. Un programa con buen estilo es más fácil de leer, de corregir −si contiene un error− y de mantener. Aunque la experiencia proporciona el estilo, existen una serie de reglas que se recomiendan seguir desde el principio del aprendizaje en programación. Sangrado (indentación) Aunque los programas escritos en Pascal no exigen reglas estrictas en su escritura, es práctica habitual realizar sangrado en los bloques y unidades de programas fundamentales Comentarios La legibilidad de los programas aumenta considerablemente utilizando comentarios. Un comentario es un texto explicativo más o menos largo, situado en el programa e ignorado por el compilador. Los comentarios no se consideran (son invisibles) en la fase de compilación y ejecución, pero de importancia primordial en las fases de análisis, puesta a punto y mantenimiento. Los comentarios son una parte importante de la documentación de un programa, ya que ayudan al programador y a otras personas a la comprensión del programa. No es raro encontrar programas en los cuales los comentarios ocupan más sitio, incluso, que las propias instrucciones. Formato {comentario} (* comentario *) Cualquiera de los dos formatos pueden ser utilizados indistintamente. Los comentarios pueden aparecer en una sola línea de programa, al final de una línea después de una sentencia, o embebido en una sentencia. En general se debe incluir en las diferentes partes de un programa, pero con la condición de que sean significativos. Se deben evitar comentarios superfluos o redundantes, como 47 A := B−C (el valor de B−C se asigna a A) cuyo significado es evidente. Es conveniente situar comentarios en la cabeza que al menos especifiquen: • . el nombre del programador, • . la fecha de la versión actual, • . una breve descripción de lo que hace el programa El siguiente programa ilustra modos de especificar comentarios. program Prueba; {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} {programa escrito por : Juan Perez } {Fecha : } {Version : } {Nombre del archivo : } {Este programa permite listar direcciones postales} {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} const Es posible anidar comentarios con delimitadores de tipo diferentes, pero no es posible con delimitadores del mismo tipo. El programador puede tener libertad para los comentarios. { un comentario puede extenderse en varias líneas o paginas de programas} {comentarios anidados (* como este caso *)} Líneas en blanco Otro medio de hacer un programa más legible es dejar líneas en blanco entre partes importantes o que estén lógicamente separados. Es muy frecuente dejar líneas en blanco entre la cabecera y la sección de declaraciones, entre sus diferentes partes, así como entre los procedimientos y funciones, entre sí y con el programa principal, etc. Elección de nombres de identificadores significativos Las variables, constantes e incluso nombres de subprogramas y programas deben ser significativos para orientar al usuario sobre lo que representan: x, As, JJ no son identificadores significativos. 48 Salario := Horas * SalarioHoras; Nomina_Mayor >= 10000; Nombre_Apellidos = 'Mortimer'; Los nombres es conveniente que comiencen con una letra mayúscula, y si son largos es preferible utilizar palabras compuestas o con subrayado. Evitar puntos y comas superfluos Antes de las palabras end y until se puede suprimir el separador punto y coma. Los puntos y comas espurios pueden afectar al mal funcionamiento de un programa. Líneas de programa mayores de 80 caracteres El editor Turbo permite escribir líneas de hasta 126 caracteres de longitud, aunque en la panta lla sólo se ven 80 columnas a la vez. Utilizando las teclas HOME (Inicio), END (Fin) y de movimiento de cursor se puede desplazar el texto a izquierda y derecha. Alinear operaciones (o separadores) en líneas consecutivas Cuando diferentes líneas consecutivas contienen el mismo operador (o separador), es buena práctica alinear estos símbolos utilizando blancos si es necesario. for j := 1 to 10 do (operador =) begin Prueba := Random; Total := Total + Prueba; Valor [j]:= Prueba; WriteLn l'Estrella errante') end; Blancos no significativos • Poner un espacio en cada lado de un operador if A = B then representa un blaco Encontrado := true; • Incluir un espacio después de los signos de puntuación: coma, punto y coma, dos puntos. Otras reglas de escritura • Poner cada sentencia en una línea distinta. 49 • Las palabras reservadas program, const, var, procedure, function, uses, begin, end deben ir en líneas distintas. • Si una sentencia continúa en otra línea, se deben sangrar la(s) linea(s) siguientes. • Insertar lineas en blanco antes de la sección const, var, uses, procedure, function y el begin del programa principal; y en cualquier segmento o bloques de sentencias significativas. • Utilizar espacios entre los elementos de una sentencia para hacerla más legible. PUESTA A PUNTO DE PROGRAMAS En esta sección se incluirán: Técnicas de resolución de problemas y de programación (diseño de programas), errores típicos de programación y estilo de programación. Técnicas de programación (diseño de programas) • Los programas no pueden considerarse correctos hasta que han sido validados utilizando un rango amplio de datos de test. • Los programas deben ser legibles y comprensibles. • Utilizar comentarios significativos que describan el propósito de un programa o segmentos de programas, así como elementos importantes de programas, variables, funciones, etc. • Etiquetar todas las salidas producidas por un programa • Los programas deben ser eficientes. Por ejemplo, cálculos innecesarios: Se deben evitar calcular dos veces cualquier variable. • Programas generales y flexibles. Deben ser relativamente fáciles de modificar para solucionar un problema similar sin necesidad de cambiar mucho el programa. El uso de las constantes limita la flexibilidad. • Antes de utilizar variables, asegurarse de que son inicializadas por el programa. • En programación interactiva, incluya siempre una línea con un mensaje de aviso al usuario cuando desee introducir datos. • Los programas deben hacer −en general− siempre "eco" de la entrada. Antes de escribir un programa en Pascal se deben seguir los pasos: • Análisis del programa (entrada, salida, datos auxiliares y proceso). • Diseño del algoritmo (con preferencia pseudocódigo), siguiendo −esencialmente− el método descendente. Errores típicos de programación • Las constantes reales deben tener al menos un dígito antes y al menos un dígito después del punto decimal. • Las constantes de cadena deben estar encerradas entre apóstrofos (simples comillas). Un apóstrofo se representa con un par de apóstrofos 'Kant"s'. • Los paréntesis dentro de expresiones deben concordar. Tantos paréntesis a izquierda como a derecha. • La división entera se representa por div y la real por /. • Las multiplicaciones deben ser indicadas por *. • Puntos y comas (ausencia, exceso, superfluos). • Debe haber un punto detrás del end final de cada programa. • Todos los identificadores deben ser declarados. • Todas las variables están inicialmente indefinidas (Turbo Pascal no sigue esta regla −inicializa a cero o cadena vacia−, pero es conveniente la inicialización). • Un signo igual (=) se utiliza en declaraciones de constantes o como signo igual. El operador := se utiliza en sentencias de asignación. No confundir = con := (ojo, programadores de BASIC). • Los problemas que implican números de tipo real no pueden utilizar test/comparaciones para comprobar exactitud de igualdad o desigualdad (= o < > ). Como los números están aproximados en la computadora, 50 no tiene sentido la igualdad/desigualdad. • Es buena idea verificar errores tales como división por cero y raices cuadradas de números negativos dentro de un programa. Estilo de programación • Un programa Turbo Pascal se prepara con el editor. Después de teclear el programa completo se sale al menú principal y se compila el programa. Si hay errores, se vuelve al editor; en caso contrario, se guarda y ejecuta. • Los errores de un programa pueden ser: sintaxis, en tiempo de ejecución y lógicos. La planificación de un programa comienza con el análisis del problema [especificaciones de entrada y salida (E/S), el proceso necesario para producir la salida desde la entrada] y sigue con el algoritmo (pseudocódigo). Especialmente en programas grandes, seguir el diseño descendente y refinamiento sucesivo. A continuación debe realizarse la documentación externa, la escritura del programa con toda la documentación interna (comentarios) necesaria. Ejemplo: Se ingresan dos números enteros, obtener su suma. ANÁLISIS ¿Qué ingresa? Dos números enteros ¿Qué sale? Otro número entero ¿Qué vincula la entrada con la salida? La operación suma Pseudocódigo Inicio Leo A (entero) Leo B (entero) Obtengo C como suma de A y B Imprimo C Fin Diagrama N_S Inicio 51 Leo A Leo B C!A+B Imprimo C Fin Código Pascal program Sumas; {* Este es el primer programa en PASCAL *} {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *****} {* programa escrito por : Fernando Javier LAGE *} {* Fecha : 7 de abril de 1998 *} {* Version : 01 *} {* Nombre del archivo : progra01 *} {* Este programa permite sumar dos números enteros *} {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *−***} uses crt,dos; {* declaraciones de librerias *} const Enter = #13; {* declaraciones de constantes *} {* type *} {* en este programa no hay declaraciones de tipos *} var {* definici¢n de las variables *} A, B, C : Integer; begin {* Comienzo del programa *} ClrScr; {* Ingreso de datos *} Write ('Ingrese el primer valor '); ReadLn(A); Write ('Ingrese el segundo valor '); 52 ReadLn(B); {* Cálculo de los resultados *} C := A + B; {* Salida de la información *} WriteLn ('El resultado es = ', C:6); {* Esta estructura se verá en próximas clases *} Repeat Until Readkey = Enter end. {* Fin del programa *} Nota En el ejemplo tenemos una típica estructura secuencial sin condiciones, ni ciclos repetitivos, como se verán en el próximo ejemplo Las estructuras secuenciales son aquellas donde todas las instrucciones se ejecutan una después de la otra. En ellas no hay repetición ni ejecución de un grupo seleccionado. Un problema típico de este tipo de estructura es el siguiente. Ejemplo: Un comerciante requiere un programa que realice las siguientes tareas: Se ingrese el costo de un producto, a dicho costo le cargue un 30% y al valor así obtenido le incremente un 20% por IVA. El programa deberá sacar por pantalla el costo del producto, el precio final, y el valor del impuesto. Pseudocódigo Diagrama N−S Inicio Definir constantes Leer el costo Calcular el costo más el 30% Calcular el valor del impuesto Calcular el Precio Imprimir Costo Imprimir Impuesto Imprimir Precio Fin gan ! 30.0 iva ! 20.0 Leer el costo Costo1 ! costo * (1+gan/100) Impuesto ! costo1 * iva /100 Precio ! Costo1 + Impuesto Imprimir Costo Imprimir Impuesto Imprimir Precio Código Pascal program Primer_Ejemplo; 53 {* Este es el primer programa en PASCAL *} {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *****} {* programa escrito por : Fernando Javier LAGE *} {* Fecha : 7 de abril de 1998 *} {* Version : 01 *} {* Nombre del archivo : progra01 *} {* Este programa permite sumar dos números enteros *} {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *−***} uses crt,dos; {* declaraciones de librerias *} const gan = 30.0; iva = 20.0; {* declaraciones de las constantes *} var {* definición de las variables *} costo : real; costo1, impuesto, precio : real; begin {* Comienzo del programa *} clrscr; {* Limpieza de pantalla *} write ('Ingrese el costo: '); {* Salida de mensaje *} readln (costo); {* Ingreso del dato *} costo1 := costo * (1 + gan/100); {* Cálculo de la ganancia *} impuesto := costo1 * (iva /100); {* Cálculo del impuesto *} precio := costo1 + impuesto; {* Cálculo del precio final *} writeln ('Costo : ', costo); {* Salida de mensaje y variable *} writeln ('Impuesto : ', impuesto); {* Idem anterior *} writeln ('Precio : ', precio); {* Idem anterior *} 54 end. {* Fin del programa *} Documentación de un programa La documentación de un programa, es el conjunto de todos los pasos, documentos necesarios para la creación y mantenimiento de un programa. El primer documento que tiene que existir en un programa es la solicitud del mismo, quien, porqué y para que lo solicita. El segundo es el contrato, sin un contrato no existe ningún proyecto de nada. En el queda especificado, el quien solicita el proyecto, el quien se hace responsable de su ejecución, el porque solicita el proyecto, el cuanto va a costar ($), el cuando va a estar listo, el como se pagará, que lo que se va a entregar. La documentación se clasifica en documentación interna y externa • Documentación Interna: esta compuesta por los comentarios que le colocamos en el interior del programa fuente. Como dicho programa nunca se entrega (a menos que por contrato se especifique lo contrario), esta documentación es privada. • Documentación Externa: Como se dice comienza con la solicitud y continua con el contrato. Se subdivide esta documentación en pública y privada. • Privada: esta compuesta por todos aquellos documentos que solo esta en el dominio de la empresa que crea el programa. Esta compuesta por algoritmos matemáticos en que se basa el programas, diagramas de bloques, diagramas de estructuras, módulos, manuales internos. • Pública: esta compuesta por los manuales del usuario. Ejercitación • Escribir un programa que lea 2 valores y que los muestre por pantalla • Al problema anterior agréguele el título en pantalla "LECTURA" • Modifique el problema anterior para que obtenga la suma de los dos valores, cambie el título por "SUMA" el cual debe aparecer subrayado, y antes del resultado debe aparecer el mensaje "El valor de la suma es XXX" (XXX es el resultado de la operación) • Escriba un programa en donde por pantalla se pida que ingrese su nombre, y como salida tenga el siguiente mensaje "Su nombre es HHHHHH" (HHHHH es el nombre ingresado). • Modifique el programa anterior de manera que se solicite el nombre a dos personas y aparezca un cartel que diga "Buenos días XXXXX y YYYYY .... ¿Comenzamos a trabajar? • Escribir un programa al cual ingrese la velocidad de un móvil expresada en metros por segundo e imprima en pantalla la velocidad en kilómetros por hora. • Modifique el programa anterior de manera tal que por pantalla aparezca el siguiente cartel. "Los XXX m/s equivalen a YYY K/H" (Donde XXX es el valor ingresado e YYY es el resultado) • Un constructor sabe que necesita 0,5 metros cúbicos de arena por metro cuadrado de revoque a realizar. Hacer un programa donde ingrese las medidas de una pared (largo y alto) expresada en metros y obtenga la cantidad de arena necesaria para revocarla. • Desarrollar un programa que dado el largo y el ancho de un campo, permita determinar cuantos metros de alambre serán necesarios para colocar le al perímetro 5 hilos de alambrado. Y que cantidad de Soja se espera obtener, si el rendimiento de la misma es 145 quintales por hectárea. • Escriba un programa que pida el ingreso del valor de cada una de las raíces de una ecuación cuadrática. En función de ellos reconstruya la ecuación y la muestre por pantalla. • Escriba un programa donde se ingrese el tiempo necesario para un cierto proceso en horas, minutos y segundos. Se calcule el costo total del proceso sabiendo que el costo por segundo es 0,25$. (Debe salir por pantalla el tiempo expresado en horas, minutos y segundos, el costo por segundo y el costo total) • Una farmacia aplica al precio de los remedios el 10% de descuento. Hacer un programa que ingresado calcule el descuento y el precio final. Sacando por pantalla la siguiente imagen: Precio de producto XXX.XX 55 − Descuento YY.YY −−−−−−−−−−−− Valor a pagar RRR.RR • La misma farmacia para la obra social OSZOPAPA, realiza el siguiente descuento: 70% por la obra social, y sobre ese resultado le aplica el 40% por cuenta de la propia farmacia (lo que ellos denominan el 70% + 40%). Cree un programa que calcule el precio final que pagará un afiliado a esa obra social por un remedio, y diseñe una salida equivalente a la del problema anterior. • Se necesita un programa que permita conocer el resultado del diseño de un tanque en forma de cilindro. Los datos que debe pedir el programa es el radio de la base y la altura. En función del mismo se calculará. Volumen que puede almacenar. Cantidad de chapa necesaria, cantidad que se debe pedir (ya que chapa circular no viene, viene en chapas rectangulares o cuadradas y el costo de la chapa es 2,25$ el metro cuadrado. Deberá salir por pantalla la siguiente información: Radio XXX m Altura YYY m Volumen ZZZ m cúbicos Chapa base y techo RRR * UUU m Chapa lateral LLL * JJJ m Sup. Total de la chapa SSS.SS m cuadrados Costo CCCC.CC $ • Los propietarios de la pizzería "El Morón Binario" desean que se les haga un programa interactivo que solicite al usuario el diámetro de la pizza en centímetros y la cantidad de ingredientes extras que se quiere agregar. Como resultado de esto el programa deberá mostrar por pantalla el precio ce venta de la misma. Dicho precio se calcula de la siguiente manera. • El precio de venta de la pizza se obtiene recargando un 150% en costo total • El costo básico (pizza sin ingredientes extras) es de 0,016 $/cm2 • El costo de cada ingrediente agregado a la pizza base es de 0,003 $/cm2 Se hace notar que como es un programa de tipo comercial la pantalla deberá tener el nombre de la pizzería en la parte superior de la pantalla y un saludo genérico para el cliente como "Buenos días señor" (puede reemplazarse por uno que sea personalizado, solicitandole el nombre al cliente y luego usándolo), y se le deberá solicitar cada dato "el usuario no es adivino" y mostrar el costo final. TIPOS DE DATOS Los diferentes objetos de información con los que un programa Pascal trabaja se conocen colectivamente como datos. Todos las datos tienen un tipo asociado can ellos. Un dato puede ser un simple carácter, tal como 's', un valor entero tal como 35 o un número real tal como 1415,92. Una operación de suma no tiene sentido con caracteres, sólo con números. Por consiguiente, si el compilador detecta una operación de suma de dos caracteres, normalmente producirá un error. Incluso entre tipos numéricos, la operación de suma se almacena de modo distinto. Esto se debe a que números enteros y reales se almacenan de modos diferentes. A menos que el programa conozca el tipo de datos, si es un valor entero a real, no Puede ejecutar correctamente la operación de suma La asignación de tipos a los datos tiene dos objetivos principales. 1. Detectar errores de operaciones en programas 2. Determinar cómo ejecutar las operaciones Pascal se conoce como lenguaje "fuertemente tipeado" (strongly.typed) o de tipos fuertes. Esto significa que todos las datos utilizados deben tener sus tipos declarados explícitamente y el lenguaje limita la mezcla de 56 tipos en las expresiones. Pascal detecta muchos errores de programación antes que el programa se ejecute. La ventaja de los lenguajes de tipos fuertes (ricos en tipos de datos) es que se gasta menos esfuerzo en la depuración de programa, ya que el compilador detecta muchos de esos errores El tipo de un dato determina la naturaleza del conjunto de valores que puede tomar una variable. Otro concepto importante a tener en cuenta es la representación interna de los números, o al menos el espacio de memoria ocupado por una variable de un tipo dado. La unidad de medida de la capacidad de memoria, como ya hemos visto es el byte (octeto). Un byte se compone de ocho cifras binarias (bits) que Pueden tomar cada una el valor 0 ó 1. Ordinales Integer Boolean Char Enumerado Subrango No Ordinales Reales Tipos Simple Datos Estáticos Tipos Cadena String Tipos de Datos Array Registro Tipos Estructurado Conjunto Archivo Tipos procedimientos Datos Dinámicos Procesos Tipos Punteros Tipos Enteros Tipo byte integer longint shortint word Rango 0 .. 255 −32768 .. 32767 −247483648 .. 24748367 −128 .. 127 0 .. 65535 Formato 1 Byte 2 Bytes 4 Bytes 1 Byte 2 Bytes El tipo integer se almacena en memoria como 2 (dos) bytes, el bit de mayor peso de los dos bytes es el bit de signo. Se puede separar un entero en sus dos bytes utilizando las funciones internas Hi y Lo Hi devuelve el byte de mayor peso de los dos bytes de memoria Lo devuelve el byte de menor peso Números Reales Tipo real Rango 2.9x10−39 .. 1.7x1038 Cifras 11−12 bytes 6 57 single double extended comp 1.5x10−45 .. 3.4x1038 5.0x10−324 .. 1.7x10308 1.9x10−4932 .. 1.1x104932 −(263 +1) .. 263 +1 7−8 15−16 19−20 19−20 4 8 10 8 Tipos carácter (Char) El tipo char es un tipo de datos que puede contener un solo carácter. Cada uno de estos caracteres puede ser expresado gracias al código ASCII ampliado. Ejemplo `A' `a' `b' `*' `5' ` ` Se le puede asignar a una constante un carácter por medio de su código #65 equivale a chr(65) equivale A #26 o ^Z cierre del archivo #27 tecla ESC #13 tecla ENTER Tipos lógicos (boolean) El tipo lógico (boolean) es, al igual que el carácter, parte de ISO Pascal estándar. Los valores de tipa lógico pueden tomar sólo das valores posibles: true (verdadero) y false (falso). Al igual que el tipo char, el tipo boolean es un tipo ordinal, que significa que tiene un núméro fijo de posibles valores que existen en un orden definido. Una variable lógica ocupa sólo un byte en memoria. Los valores lógicas son de tipo ordinal, y sus relaciones son: faÍse < true Tipos de datos definidos por el usuario Todos los tipos de datos estudiados hasta ahora son de tipo simple, predefinidos por Turbo y listos para utilizar. Sin embargo, uno de los aspectos más potentes de Turbo Pascal es su capacidad para crear estructuras de datos a partir de estos datos simples. Los datos estructurados aumentan la legibilidad de los programas y simplifican su mantenimiento. Los tipos de datos definidas por el usuario se clasifican en: • Escalares definidos por el usuario (enumemdo y subrango) • Registros • Arrays • Conjunto (set). • Archivo (file). • Puntero • Procedimiento Estos tipos de datos se verán en sucesivas clases. 58 Tipo cadena (string) Un tipo string (cadena) es una secuencia de caracteres de cero o más caracteres correspondientes al código ASCII, escrito en una línea sobre el programa y encerrada entre apóstrofos. El tratamiento de cadenas es una característica muy potente de Turbo Pascal que no contiene ISO Pascal estándar, aunque tiene mucha similitud con el tipo packed array. Ejemplos 'Turbo' 'Estás de acuerdo' #13#10 `,' Notas Una cadena sin nada entre las apóstrofos se llama cadena nula o cadena vacía La longitud de una cadena es el número de caracteres encerrados entre los apóstrofos. CONSTANTES Una constante es un valor que no puede cambiar durante la ejecución del programa, recibe un valor en el momento de la compilación del programa y este valor no puede ser modificado. Las constantes pueden ser constantes literales constantes con nombres o declaradas constantes expresión (sólo en la versión 5.0) constantes de tipos (tipeadas) Las constantes deben ser declaradas antes de su utilización y pueden ser enteros o reales, caracteres o cadenas de caracteres, conjuntos o arrays, e inclusive de tipo enumerado • Constantes literales Una constante literal es un valor de cualquier tipo que se utiliza como tal. VolumenEsfera := 4/3 * Pi * Radio * Rádio * Rádio, 4 y 3 son constantes literales de valores 4 y 3. • Constantes con nombres Son constantes que se identifican por un nombre y el valor asignado. Formato const 59 identificador = valor, Ejemplos const Pi = 3.141592; {lee un valor real} DosPi = 2 * Pi; Direccion = $06; { representa valor hexadecimal } caracter = 'B'; { es un carácter } cuenta = 625; { lee un entero } Epsilon = 1E−4; { lee un real } Esc = #27; { carácter de control } CRLF = ^M^J; { secuencia CR/LF. retorno de carro/avance de lineal } En Pascal estándar, la declaración de constantes se sitúa inmediatamente después de la cabecera Program. En Turbo Pascal no es obligatoria la situación anterior, pero si recomendable. VARIABLES Las variables son objetos cuyo valor puede cambiar durante la ejecución del programa. El cambio se produce mediante sentencia ejecutables. Todas las variables de un programa Pascal deben ser declaradas antes de ser usadas Declaraciones var variable1 : tipo1; variable2 : tipo2; ......................... ......................... variableN : tipoN; Ejemplos NumeroEmpleado : Integer; { número de empleado } Horas : real; { horas trabajadas } 60 Tasas : real; { tasa horaria } Edad : Integer; { edad del empleado } Apellidos : string [30]; { apellidos del empleado } Letra1, Letra2, Letra3 : char; Num1, Num2 : integer; Notas Es buena práctica de programación utilizar nombres de variables significativas que sugieren lo que ellas representan, ya que esto hace al programa más legible y fácil de comprender, también es buena práctica incluir breves comentarios que indiquen cómo se utiliza la variable. Un comentario es cualquier frase encerrada entre llaves { } o bien entre signos (*, *) SENTENCIAS Las sentencias describen las acciones algorítmicas que pueden ser ejecutadas En general las sentencias se clasifican en, ejecutables (especifican operaciones de cálculos aritméticos y entradas/salidas de datos) y no ejecutables (no realizan acciones concretas, ayudan a la legibilidad del programa, pero no afectan en la ejecución del Programa). Las sentencias ejecutables aparecen en el cuerpo del programa a continuación de la palabra reservada Begin LA SENTENCIA DE ASIGNACION La sentencia de asignación se utiliza para asignar (almacenar) valores o variables. La asignación es una operación que sitúa un valor determinada en una posición de memoria. la operación de asignación se demuestra en pseudocódigo con el símbolo '!', para denotar que el valor situado a su derecha se almacena en la variable situada a la izquierda Formato Variable ! expresión variable identificador válido declarado anteriormente expresión variable, constante o una expresión o fórmula a evaluar En Pascal el operador '!−' se sustituye por el símbolo := , que se denomina operador de asignación Variable := expresión El valor de expresión se asigna a la variable. Precaución El tipo de expresión debe ser del mismo tipo que el de la variable. 61 Ejemplos A :=16 ; 16 se asigna a la variable A Inicial := 'LJ'; se asigna LJ a la variable Inicial Interruptor :=true; se asigna el valor true. (verdadero) a Interruptor N1 := N2; el valor de la variable N1 se cambia por el valor de la variable N2 N1 := N1 + 5; el valor de la variable N1 se incrementa en 5 Car := #70; se asigna a la variable Car el carácter 70 del código ASCII, es decir `F' Operaciones especiales de asignación Contador Un contador es una variable que se incrementa, cuando se ejecuta, en una unidad o en una cantidad constante. Contador .= 25 x: = 5 Contador := Contador + 1; x := x + 1; N = 15 N :=N + 1; Al ejecutar Las sentencias de asignación, los nuevos valores de Contador y N son 25+1=26 y 50+1 =51. Acumulador Es una variable que se incrementa en una cantidad variable. Suma := Suma + x; x es una vanable Si x vale 7 y Suma 40, el nuevo valor de Suma será 47 Las operaciones contador y acumulador son de gran utilidad en programación. EXPRESIONES Y OPERACIONES ARITMETICAS Las variables y constantes estudiadas anteriormente se pueden procesar utilizando operaciones y funciones adecuadas a sus tipos En este punto se examinarán las expresiones y operaciones que se utilizan con datos numéricos. • Operadores aritméticos: +, −, *, / Los operadores aritméticos (+,−, *) pueden ser utilizados con tipos enteros o reales. Si ambos son enteros, el resultado es entero; si alguno de ellos es real, el resultado es real. 2+3 = 5 2+3.0 = 5.0 62 Operadores aritméticos div y mod Solo se pueden utilizar con enteros, la salida es otro entero. Div devuelve el valor de la división entera y Mod da el resto de la división entera. 17 DIV 5 ! 3 17 MOD 5 ! 2 Reglas de expresiones (prioridad) Se respeta las mismas prioridades del álgebra. OPERACIONES ENTRADA/SALIDA Los datos se pueden almacenar en memoria de tres formas diferentes: asociados con constantes, asignados a una variable con una sentencia de asignación o una sentencia de lectura. Ya se han examinado las dos primeras. El tercer método, la sentencia de lectura, es cl más indicado si se desea manipular diferentes datos cada vez que se ejecuta cl problema. Además. la lectura de datos permite asignar valores desde dispositivos hasta archivos externos (por ejemplo, un teclado o una unidad de disco) en memoria se denomina operación de entrada o lectura A medida que se realizan cálculos en un programa, se necesitan visualizar los resultados Esta operación se conoce como operación de salida o de escritura En los algoritmos las instrucciones de entrada/salida escritas en pseudocódigo son: leer (listas de variables entrada) leer (v. z, x) escribir (listas de variables salida) escribir (a, b, c) En Pascal todas las operaciones de entrada/salida se realizan ejecutando unidades de programa especiales denominadas procedimientos de entrada/salida que forman parte del compilador Pascal y sus nombres son identificadores estándar: Procedimientos de entrada Read ReadLn procedimientos de salida Write WriteLn La escritura de resultados (salida) Los programas para ser útiles deben proporcionar información de salida (resultados) Esta salida toma información de la memoria y la sitúa (almacena) en: la pantalla, en un dispositivo de almacenamiento (disco duro o flexible), o en un puerto de E/S (puertos serie para comunicaciones o impresoras, normalmente paralelos) Procedimiento WriteLn El propósito de WriteLn es escribir (visualizar) información en la pantalla Formato WriteLn (ítem, ítem..): 1 63 ítem el objeto que desea visualizar: un valor literal (entero, real, un carácter una cadena, o un valor lógicotrue o false). una constante con nombre, una variable, o una llamada a función Cuando se ejecuta el procedimiento WriteLn, se visualizan todos los elementos en el orden dado y en la misma línea. Al terminar de visualizar toda la línea, el cursor avanza (salta) al comienzo de la siguiente línea. Procedimiento Write Como se ha dicho, después de ejecutar el procedimiento WriteLn, el cursor avanza (salta) al comienzo de la siguiente línea. Si se desea que el cursor quede en ;a misma línea se debe utilizar el procedimiento Write. Formatos de salida Turbo Pascal permiten controlar en cierta medida las instrucciones de salida que presentan resultados. Es posible especificar el número de posiciones del campo de escritura. Para los números reales es posible precisar el número de decimales deseado.Se pueden utilizar especificadores de formato de campo para definir dicha anchura.x := 265.7892 WriteLn(x :10 :4); 265.7892 WriteLn(x :10 :2); 265.79 WriteLn(x :6 :4); ********* X := 14; WriteLn(x :4); 14 X := `AB' WriteLn(x :4); AB Lo anteriormente expresado es válido para el proceso WRITE Impresión de resultados (salidas a impresora) Las salidas a pantalla se obtienen mediante los procedimientos Write y WriteLn. Si se desea enviar resultados a otro dispositivo, es preciso especificar el nombre del archivo como primer argumento de las instrucciones Write y WriteLn. Para poder realizar la operación de enviar salidas a la impresora, en lugar de a la pantalla, se necesita la unidad Printer. Printer define un archivo llamado lst y asocia este archivo al puerto de comunicaciones LPTI (impresora) del DOS. Se pueden enviar datos a la impresora, incluyendo lst en las instrucciones Write y WriteLn. Es preciso, sin embargo, definir previamente en la sección uses la unidad printer. Ejemplo uses Printer 64 var ......................... begin ......................... Write (Lst, 'el .......................... ) WriteLn (Lst, 'pl............ ) ......................... end. Este programa imprime en la impresora: Regla Siempre que desee escribir en impresora, deberá incluir en su programa la línea uses printer y luego añadir en cada sentencia Write/WriteLn la palabra lst La entrada de datos (lectura)Los datos que se pueden leer son: enteros, reales, caracteres o cadenas. No se puede leer un boolean o un elemento de tipo enumerado.Los datos estructurados, arrays, registros o conjuntos, no se pueden leer globalmente y se suele recurrir a diseñar procedimientos específicos. Los procedimientos de lectura son Read y ReadLn. Formato Read (van, var2, ...); ReadLn (van, var2, ...); var igual que WRITE La entrada de datos desde el teclado se hace un valor cada vez. Las instrucciones ReadLn y Read esperan hasta que se pulsa la tecla INTRO (RETURN o ENTER) antes de asignar un valor a la variable. Ejemplo ReadLn (Nombre); ReadLn (Horas); Read (Tasas) El usuario debe introducir los datos de entrada en el orden en que aparecen las instrucciones read, Diferencias entre Read y ReadLn 65 En Read, después de pulsar la tecla INTRO, el cursor permanece inmediatamente después del último carácter introducido. En ReadLn, el cursor se envía al principio de la siguiente línea, tras pulsar la tecla INTRO. No es aconsejable utilizar más de un dato por instrucción. OPERACIONES BASICAS DE UTILIDAD En este punto se describen dos utilidades: Clrscr GotoXY limpieza o borrado de la pantalla movimiento del cursor El borrado (limpieza) de la pantalla: Clrscr Las órdenes o procedimientos que podrá utilizar a partir de ahora: Clrscr y GotoXY, aunque posteriormente se volverán a mencionar. Ambos procedimientos pertenecen a la unidad Crt. La orden (procedimiento) Clrscr borra (limpia) la pantalla (ventana actual) y sitúa el cursor en la esquina superior izquierda. Turbo Pascal considera las coordenadas de la esquina superior izquierda :1,1. Para poder utilizar Clrscr, deberá declarar en la cláusula uses la unidad Crt. Regla Es una buena costumbre utilizar en todos los programas la unidad Crt, mediante la cláusula uses; ello permite el uso de Clrscr y GotoXY, entre otras rutinas de utilidad. Movimiento del cursor La orden (procedimiento) GotoXY mueve el cursor a la posición x, y, donde x es la columna (contando de izquierda a derecha) e y es la fila (contando de arriba−abajo). Formato GotoXY (x, y) La esquina superior izquierda es 1.1. GotoXY requiere el uso de la unidad Crt. EL ESTILO DE PROGRAMACIÓN El buen estilo de programación es, sin lugar a duda, una de las características más notables que debe tener un programador. Un programa con buen estilo es más fácil de leer, de corregir −si contiene un error− y de mantener. Aunque la experiencia proporciona el estilo, existen una serie de reglas que se recomiendan seguir desde el principio del aprendizaje en programación. Sangrado (indentación) 66 Aunque los programas escritos en Pascal no exigen reglas estrictas en su escritura, es práctica habitual realizar sangrado en los bloques y unidades de programas fundamentales ComentariosLa legibilidad de los programas aumenta considerablemente utilizando comentarios. Un comentario es un texto explicativo más o menos largo, situado en el programa e ignorado por el compilador. Los comentarios no se consideran (son invisibles) en la fase de compilación y ejecución, pero de importancia primordial en las fases de análisis, puesta a punto y mantenimiento. Los comentarios son una parte importante de la documentación de un programa, ya que ayudan al programador y a otras personas a la comprensión del programa. No es raro encontrar programas en los cuales los comentarios ocupan más sitio, incluso, que las propias instrucciones. Formato 1 . { comentario } 2. (* comentario *) Cualquiera de los dos formatos se pueden utilizar indistintamente. Los comentarios pueden aparecer en una sola línea de programa, al final de una línea después de una sentencia, o embebido en una sentencia. En general se debe incluir en las diferentes partes de un programa, pero con la condición de que sean significativos. Se deben evitar comentarios superfluos o redundantes, como A := B−C (el valor de B−C se asigna a A) cuyo significado es evidente. Es conveniente situar comentarios en la cabeza que al menos especifiquen: • . el nombre del programador, • . la fecha de la versión actual, • . una breve descripción de lo que hace el programador. El siguiente programa ilustra modos de especificar comentarios. program Prueba; {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} {programa escrito por : Juan Perez } {Fecha : } {Version : } {Nombre del archivo : } {Este programa permite listar direcciones postales} {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 67 const Es posible anidar comentarios con delimitadores de tipo diferentes, pero no es posible con delimitadores del mismo tipo. El programador puede tener libertad para los comentarios. { un comentario puede extenderse en varias líneas o paginas de programas} {comentarios anidados (* como este caso *)} Líneas en blanco Otro medio de hacer un programa más legible es dejar líneas en blanco entre partes importantes o que estén lógicamente separados. Es muy frecuente dejar líneas en blanco entre la cabecera y la sección de declaraciones, entre sus diferentes partes, así como entre los procedimientos y funciones, entre sí y con el programa principal, etc. Elección de nombres de identificadores significativos Las variables, constantes e incluso nombres de subprogramas y programas deben ser significativos para orientar al usuario sobre lo que representan: x, As, JJ no son identificadores significativos. Salario := Horas * SalarioHoras; Nomina_Mayor >= 10000; Nombre_Apellidos = 'Mortimer'; Los nombres es conveniente que comiencen con una letra mayúscula, y si son largos es preferible utilizar palabras compuestas o con subrayado. Evitar puntos y comas superfluos Antes de las palabras end y until se puede suprimir el separador punto y coma. Los puntos y comas espurios pueden afectar al mal funcionamiento de un programa. Líneas de programa mayores de 80 caracteres El editor Turbo permite escribir líneas de hasta 126 caracteres de longitud, aunque en la panta lla sólo se ven 80 columnas a la vez. Utilizando las teclas HOME (Inicio), END (Fin) y de movimiento de cursor se puede desplazar el texto a izquierda y derecha. Alinear operaciones (o separadores) en líneas consecutivas Cuando diferentes líneas consecutivas contienen el mismo operador (o separador), es buena práctica alinear estos símbolos utilizando blancos si es necesario. for j := 1 to 10 do (operador =) 68 begin Prueba := Random; Total := Total + Prueba; Valor [j]:= Prueba; WriteLn l'Estrella errante') end; Blancos no significativos • Poner un espacio en cada lado de un operador if A = B then representa un blaco Encontrado := true; • Incluir un espacio después de los signos de puntuación: coma, punto y coma, dos puntos. Otras reglas de escritura • Poner cada sentencia en una línea distinta. • Las palabras reservadas program, const, var, procedure, function, uses, begin, end deben ir en líneas distintas. • Si una sentencia continúa en otra línea, se deben sangrar la(s) linea(s) siguientes. • Insertar lineas en blanco antes de la sección const, var, uses, procedure, function y el begin del programa principal; y en cualquier segmento o bloques de sentencias significativas. • Utilizar espacios entre los elementos de una sentencia para hacerla más legible. PUESTA A PUNTO DE PROGRAMAS En esta sección se incluirán: Técnicas de resolución de problemas y de programación (diseño de programas), errores típicos de programación y estilo de programación. Técnicas de programación (diseño de programas) • Los programas no pueden considerarse correctos hasta que han sido validados utilizando un rango amplio de datos de test. • Los programas deben ser legibles y comprensibles. • Utilizar comentarios significativos que describan el propósito de un programa o segmentos de programas, así como elementos importantes de programas, variables, funciones, etc. • Etiquetar todas las salidas producidas por un programa • Los programas deben ser eficientes. Por ejemplo, cálculos innecesarios: Se deben evitar calcular dos veces cualquier variable. • Programas generales y flexibles. Deben ser relativamente fáciles de modificar para solucionar un problema similar sin necesidad de cambiar mucho el programa. El uso de las constantes limita la flexibilidad. • Antes de utilizar variables, asegurarse de que son inicializadas por el programa. • En programación interactiva, incluya siempre una línea con un mensaje de aviso al usuario cuando desee introducir datos. 69 • Los programas deben hacer −en general− siempre "eco" de la entrada. Antes de escribir un programa en Pascal se deben seguir los pasos: • Análisis del programa (entrada, salida, datos auxiliares y proceso). • Diseño del algoritmo (con preferencia pseudocódigo), siguiendo −esencialmente− el método descendente. Errores típicos de programación • Las constantes reales deben tener al menos un dígito antes y al menos un dígito después del punto decimal. • Las constantes de cadena deben estar encerradas entre apóstrofos (simples comillas). Un apóstrofo se representa con un par de apóstrofos 'Kant"s'. • Los paréntesis dentro de expresiones deben concordar. Tantos paréntesis a izquierda como a derecha. • La división entera se representa por div y la real por /. • Las multiplicaciones deben ser indicadas por *. • Puntos y comas (ausencia, exceso, superfluos). • Debe haber un punto detrás del end final de cada programa. • Todos los identificadores deben ser declarados. • Todas las variables están inicialmente indefinidas (Turbo Pascal no sigue esta regla −inicializa a cero o cadena vacia−, pero es conveniente la inicialización). • Un signo igual (=) se utiliza en declaraciones de constantes o como signo igual. El operador := se utiliza en sentencias de asignación. No confundir = con := (ojo, programadores de BASIC). • Los problemas que implican números de tipo real no pueden utilizar test/comparaciones para comprobar exactitud de igualdad o desigualdad (= o < > ). Como los números están aproximados en la computadora, no tiene sentido la igualdad/desigualdad. • Es buena idea verificar errores tales como división por cero y raices cuadradas de números negativos dentro de un programa. Estilo de programación • Un programa Turbo Pascal se prepara con el editor. Después de teclear el programa completo se sale al menú principal y se compila el programa. Si hay errores, se vuelve al editor; en caso contrario, se guarda y ejecuta. • Los errores de un programa pueden ser: sintaxis, en tiempo de ejecución y lógicos. La planificación de un programa comienza con el análisis del problema [especificaciones de entrada y salida (E/S), el proceso necesario para producir la salida desde la entrada] y sigue con el algoritmo (pseudocódigo). Especialmente en programas grandes, seguir el diseño descendente y refinamiento sucesivo. A continuación debe realizarse la documentación externa, la escritura del programa con toda la documentación interna (comentarios) necesaria. Ejemplo: Se ingresan dos números enteros, obtener su suma. Análisis ¿Qué ingresa? Dos números enteros 70 ¿Qué sale? Otro número entero ¿Qué vincula la entrada con la salida? La operación suma Pseudocódigo Inicio Leo A (entero) Leo B (entero) Obtengo C como suma de A y B Imprimo C Fin Diagrama N_S Inicio Leo A Leo B C!A+B Imprimo C Fin Código Pascal program Sumas; {* Este es el primer programa en PASCAL*} {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} {* programa escrito por : Fernando Javier LAGE *} {* Fecha : 7 de abril de 1998 *} {* Version : 01 *} {* Nombre del archivo : progra01 *} {* Este programa permite sumar dos números enteros *} {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 71 uses crt,dos; {* declaraciones de librerias *} const Enter = #13; {* declaraciones de constantes *} {* type *} {* en este programa no hay declaraciones de tipos *} var {* definici¢n de las variables *} A, B, C : Integer; begin {* Comienzo del programa *} ClrScr; {* Ingreso de datos *} Write ('Ingrese el primer valor '); ReadLn(A); Write ('Ingrese el segundo valor '); ReadLn(B); {* Cálculo de los resultados *} C := A + B; {* Salida de la información *} WriteLn ('El resultado es = ', C:6); {* Esta estructura se verá en próximas clases *} Repeat Until Readkey = Enter end. {* Fin del programa *} Nota En el ejemplo tenemos una típica estructura secuencial sin condiciones, ni ciclos repetitivos, como se verán en el próximo ejemplo Las estructuras secuenciales son aquellas donde todas las instrucciones se ejecutan una después de la otra. En ellas no hay repetición ni ejecución de un grupo seleccionado. 72 Un problema típico de este tipo de estructura es el siguiente. Ejemplo: Un comerciante requiere un programa que realice las siguientes tareas: Se ingrese el costo de un producto, a dicho costo le cargue un 30% y al valor así obtenido le incremente un 20% por IVA. El programa deberá sacar por pantalla el costo del producto, el precio final, y el valor del impuesto. Pseudocódigo Diagrama N−S Inicio Definir constantes Leer el costo Calcular el costo más el 30% Calcular el valor del impuesto Calcular el Precio Imprimir Costo Imprimir Impuesto Imprimir Precio Fin gan ! 30.0 iva ! 30.0 Leer el costo Costo1 ! costo * (1+gan/100) Impuesto ! costo1 * iva /100 Precio ! Costo1 + Impuesto Imprimir Costo Imprimir Impuesto Imprimir Precio program Primer_Ejemplo; {* Este es el primer programa en PASCAL *} uses crt,dos; {* declaraciones de librerías *} const gan = 30.0; iva = 20.0; {* declaraciones de las constantes *} var {* definición de las variables *} costo : real; costo1, impuesto, precio : real; begin {* Comienzo del programa *} clrscr; {* Limpieza de pantalla *} write ('Ingrese el costo: '); {* Salida de mensaje *} readln (costo); {* Ingreso del dato *} costo1 := costo * ( 1 + gan/100); {* Cálculo de la ganancia *} 73 impuesto := costo1 * (iva /100); {* Cálculo del impuesto *} precio := costo1 + impuesto; {* Cálculo del precio final *} writeln ('Costo : ', costo); {* Salida de mensaje y variable *} writeln ('Impuesto : ', impuesto); {* Idem anterior *} writeln ('Precio : ', precio); {* Idem anterior *} end. {* Fin del programa *} program Primer_Modulos; {* Este es el primer programa en PASCAL, con módulos *} uses crt,dos; {* declaraciones de librerias *} const gan = 30.0; iva = 20.0; {* declaraciones de las constantes *} var {* definición de las variables *} costo : real; costo1, impuesto, precio : real; procedure limpieza; begin {* Comienzo del procedimiento limpieza *} clrscr; {* Limpieza de pantalla *} end; {* Fin del procedimiento limpieza *} procedure ingreso; begin {* Comienzo del procedimiento de ingreso de datos *} write ('Ingrese el costo: '); {* Salida de mensaje *} readln (costo); {* Ingreso del dato *} end; {* Fin del procedimiento ingreso *} procedure calculos; 74 begin {* Comienzo del procedimiento de cálculo de valores *} costo1 := costo * ( 1 + gan/100); {* Cálculo de la ganancia *} impuesto := costo1 * (iva /100); {* Cálculo del impuesto *} precio := costo1 + impuesto; {* Cálculo del precio final *} end; {* Fin del procedimiento calculos *} procedure salidas; begin {* Comienzo del procedimiento de egreso de valores *} writeln ('Costo : ', costo); {* Salida de mensaje y variable *} writeln ('Impuesto : ', impuesto); {* Idem anterior *} writeln ('Precio : ', precio); {* Idem anterior *} end; {* Fin del procedimiento salidas*} begin {* Comienzo del programa *} limpieza; {* llamado a cada uno de los módulos (procedimientos) *} ingreso; calculos; salidas; end. {* Fin del programa *} Estructuras de Programación Todo programa puede ser escrito utilizando solamente tres tipos de estructuras de control • secuenciales • selectivas • repetitivas Las estructuras de tipo secuencial se han visto en el práctico anterior. En esta practica veremos los otros dos tipos de estructuras. Selectivas: Las estructuras selectivas se utilizan para tomar decisiones lógicas; de ahí que se suelan denominar estructuras de decisión o alternativas. Son dos la sentencia if y la sentencia case. If esta sentencia, es considerada de alternativa doble ( si se cumple cierta condición entonces ... , sino .... 75 / If ...... then ...... else..... ). Pseudocódigo en español Código se programa si <condición> if <condición> entonces < acción S1> then < acción S1> sino <acción S2 > else < acción S2> Su estructugrama tiene la siguiente forma if <condición> then < acción S1> else < acción S2> Ejemplos: a) Se leen dos valores enteros A, B. Si A es mayor que B se realiza la suma de ambos, caso contrario, se hace el producto. Pseudocódigo del programa nombre selección1(program); declaraciones (uses) Crt, Dos; variables (var); A (valor que ingresa) : entero; B (valor que ingresa) : entero; R (resultado de la oper.): entero funciones(function); procedimientos (procedure); inicio (begin); limpieza(limpia la pantalla); ingreso; alternativa (decisión A>B): resultado (salida resultados): fin(end.) Diagrama N−S nombre selección1 declaraciones Crt, Dos Variables A, B, R :enteros funciones y procedimientos comienzo (programa) limpieza ingreso alternativa resultado fin (programa) Estructura secuencial Como se puede ver tenemos varios procedimientos ya vistos. Por lo tanto solo se desarrollara el pseudocódigo y el estructurado de alternativa, y todo lo que de el dependa. algoritmo alternativa 76 Pseudocódigo del alternativa procedimiento alternativa inicio (begin); si A > B entonces R ! A + B sino R ! Prod (A, B) fin(end;) Diagrama N−S A>B R!A+B else R ! Prod (A, B) El código del procedimiento es: procedure alternativa; {* determina si A es o no mayor que B y hace los cálculos correspondientes *} begin {* comienzo de alternativa *} if A > B then R := A + B else R := Prod (A,B); {* llamado a la función *} end; {* fin de alternativa *} Nótese que se definió una función Prod (A, B), veremos como se trabaja con ellas. algoritmo Prod Pseudocódigo de Prod función Prod ( A, B : enteros)entero inicio (begin); Prod ! A * B fin(end;) Diagrama N−S función Prod ( A, B : entero ) entero comienzo (Prod) Prod ! A * B fin (Prod) 77 function Prod ( A, B: integer ): integer; {* obtiene el producto entre dos valores enteros *} begin {* comienzo de Prod *} Prod := A * B; end; {* fin de Prod *} Quedándonos el programa de la siguiente manera. Program Seleccion_1; {* Este es el primer programa con estructuras de selección y funciones *} uses crt, dos; {* declaraciones *} {const} {* no hay constantes *} var A, B : integer; {* valores que ingresan *} R: integer; {* salida de la operación *} function Prod ( A, B: integer ): integer; {* obtiene el producto entre dos valores enteros *} begin {* comienzo de Prod *} Prod := A * B; end; {* fin de Prod *} procedure limpieza; {* comienzo de limpieza de la pantalla *} begin ClrScr; end; {* fin de limpieza de la pantalla *} procedure ingreso; {* comienzo del ingreso de datos *} begin write ('Ingrese A '); {* ingreso de variable A *} readln (A); write ('Ingrese B '); {* ingreso de variable B *} readln (B); 78 end; {* fin del ingreso de datos *} procedure alternativa; {* determina si A es o no mayor que B y hace los cálculos correspondientes *} begin {* comienzo de alternativa *} if A > B then R := A + B else R := Prod (A,B); {* llamado a la función *} end; {* fin de alternativa *} procedure resultado; {* comienzo la impresión de los resultados *} Var H :char; begin writeln ( 'Resultado = ', R); writeln ( 'Presione cualquier tecla '); readln (H); {* esta instrucción y la anterior son para dar tiempo para ver resultados *} end; {* fin de la impresión de los resultados *} begin limpieza; {* llamado al procedimiento limpieza *} ingreso; {* llamado al procedimiento ingreso *} alternativa; {* llamado al procedimiento alternativa *} resultado; {* llamado al procedimiento resultado *} end. b) Se leen dos valores enteros A, B. Si A es mayor que B se realiza la suma de ambos y se imprime un cartel diciendo R es la suma de A y B = , caso contrario, se hace el producto y se imprime otro cartel que diga R . es el producto de A y B = Pseudocódigo del programa 79 nombre selección2program); declaraciones (uses); Crt, Dos; variables (var); A (valor que ingresa) : entero; B (valor que ingresa) : entero; R (resultado de la oper.): entero funciones(function); procedimientos (procedure); inicio (begin); limpieza (limpia la pantalla) ; ingreso (ingreso de datos); alternativa (decisión A>B e imp.); resultado ( para ver los resultados): fin(end.) Diagrama N−S nombre selección1 declaraciones Crt, Dos; Variables A, B, R :enteros funciones y procedimientos comienzo (programa) limpieza ingreso alternativa resultado fin (programa) Como se puede ver dentro de alternativa se colocó la impresión de resultados quedándonos este algoritmo 80 estructurado de la siguiente manera. algoritmo alternativa Pseudocódigo del alternativa procedimiento alternativa inicio (begin); si A > B entonces R ! A + B Imprimir cartel suma y resultados sino R ! Prod (A, B) Imprimir cartel producto y resultados fin(end;) Diagrama N−S A>B R!A+B Imp. cartel y resultados Else R ! Prod (A, B) Imp. cartel y resultados El código del procedimiento es: procedure alternativa; {* determina si A es o no mayor que B y hace los cálculos correspondientes *} begin {* comienzo de alternativa *} if A > B then begin {* comienzo del then *} R := A + B; writeln ( 'R es la suma de A y B = ', R); end {* fin del then *} 81 else begin {* comienzo del else *} R := Prod (A,B); {* llamado a la función *} writeln ( 'R es el producto de A y B = ', R); end; {* fin del else *} end; {* fin de alternativa *} Quedándonos el programa de la siguiente manera. Program Seleccion_2; {* Este es el primer programa con estructuras de selección y funciones *} uses crt, dos; {* declaraciones *} {const} {* no hay constantes *} var A, B : integer; {* valores que ingresan *} R: integer; {* salida de la operación *} function Prod ( C, D: integer ): integer; {* obtiene el producto entre dos valores enteros *} begin {* comienzo de Prod *} Prod := C * D; end; {* fin de Prod *} procedure limpieza; {* comienzo de limpieza de la pantalla *} begin ClrScr; end; {* fin de limpieza de la pantalla *} procedure ingreso; {* comienzo del ingreso de datos *} begin write ('Ingrese A '); {* ingreso de variable A *} readln (A); 82 writeln ('Ingrese B '); {* ingreso de variable B *} read (B); end; {* fin del ingreso de datos *} procedure alternativa; {* compara A con B y hace los cálculos e imprime resultados *} begin {* comienzo de alternativa *} if A > B then begin {* comienzo del then *} R := A + B; writeln ( 'R es la suma de A y B = ', R); {* imprime resultados *} end {* fin del then *} else begin {* comienzo del else *} R := Prod (A,B); {* llamado a la función *} writeln ( 'R es el producto de A y B = ', R); {* imprime resultados *} end; {* fin del else *} end; {* fin de alternativa *} procedure resultado; {* comienzo la muestra de los resultados *} Var H :char; begin writeln ( 'Preione cualquir tecla '); readln (H); {* esta instrucción y la anterior son para dar tiempo para ver resultados *} end; {* fin de la muestra de los resultados *} begin limpieza; {* llamado al procedimiento limpieza *} ingreso; {* llamado al procedimiento ingreso *} alternativa; {* llamado al procedimiento alternativa *} 83 resultado; {* llamado al procedimiento resultado *} end. Hay varias cosas para tomar en cuenta cuando en alguna de las opciones tiene más de una instrucción dicha opción deberá llevar un begin con su correspondiente end. Debe notarse que el end del then no tiene puntuación en cambio el del else si lleva punto y coma (;) esto se debe que este end es el último del if. También debe notarse que las variables del llamado de la función son distintas a las de la función en si. R := Prod (A,B); function Prod ( C, D: integer ): integer; Tanto en funciones como en procedimientos esto es posible ya que el lenguaje vincula automáticamente la primera variable del llamado con la primera de la declaración, la segunda con la segunda y así sucesivamente. Esto nos permite llamar a una función (o procedimiento), con distintos juegos de variables. Sin que tengamos que atenernos a nombres específicos. Solo debemos tener en cuenta que las variables sean del mismo tipo. Mútiples salidas : Si se tiene más de dos posibles salidas, aquí aparecen dos soluciones similares al problema. IF anidado : en esta solución se utiliza un if dentro de otro. Siempre se anida por la salida Else (sino). Ejemplo : Se pide un programa donde ingresa un número entre 1 y 5 incluidos ambos y se imprime en pantalla su expresión de caracteres ( ingresa 2 ! imprime Dos). En este caso tenemos cinco salidas probables (uno, dos, tres, cuatro o cinco), esto indica que deberemos tener 4 if anidados. Si a = 1 Entonces impre = Uno Sino Si a = 2 Entonces impre = Dos Sino Si a = 3 Entonces impre = Tres Sino Si a = 4 Entonces impre = Cuatro Sino impre = Cinco fin_si {* fin_si no tiene equivalente en Pascal *} 84 fin_si fin_si fin_si if <condición> then < acción S1> else if <condición> then < acción S2> Else If <condición> then < acción S3> Else If <condición> then < acción S3> Else < acción S4> El código del procedimiento es: procedure alternativa; {* determina el valor de A y lo expresa en letras *} begin {* comienzo de alternativa *} if A = 1 then {* pregunta por uno *} writeln ( 'U n o ') {* salida por uno *} else if A = 2 then {* pregunta por dos *} writeln ( 'D o s ') {* salida por dos *} else if A = 3 then {* pregunta por tres *} writeln ( 'T r e s ') {* salida por tres *} else if A = 4 then {* pregunta por cuatro *} writeln ( 'C u a t r o ') {* salida por cuatro *} else writeln ( 'C i n c o '); {* salida por cinco *} end; {* fin de alternativa *} Quedándonos el programa de la siguiente manera. 85 Program Seleccion_3; {* If anidados *} uses crt, dos; {declaraciones} {const} {* no hay constantes *} var A : integer; {* valor que ingresa *} procedure limpieza; {* comienzo de limpieza de la pantalla *} begin ClrScr; end; {* fin de limpieza de la pantalla *} procedure ingreso; {* comienzo del ingreso de datos *} begin write ('Ingrese un numero de 1 a 5 : '); {* ingreso de variable A *} readln (A); end; {* fin del ingreso de datos *} procedure alternativa; {* determina el valor de A y lo expresa en letras *} begin {* comienzo de alternativa *} if A = 1 then {* pregunta por uno *} writeln ( 'U n o ') {* salida por uno *} else if A = 2 then {* pregunta por dos *} writeln ( 'D o s ') {* salida por dos *} else if A = 3 then {* pregunta por tres *} writeln ( 'T r e s ') {* salida por tres *} else if A = 4 then {* pregunta por cuatro *} 86 writeln ( 'C u a t r o ') {* salida por cuatro *} else writeln ( 'C i n c o '); {* salida por cinco *} end; {* fin de alternativa *} procedure resultado; {* se utiliza para dejar en pantallas los resultados *} Var H :char; begin writeln ( 'Preione cualquir tecla '); readln (H); {* esta instrucci¢n y la anterior son para dar tiempo para *} {* ver resultados *} end; {* fin de resultado *} begin limpieza; ingreso; alternativa; resultado; end. Select : esta solución se utiliza en reemplazo del if anidado. Es más práctica y eficiente. su pseudocódigo genérico es: según...sea E hacer E1: sentencia 1 E2: sentencia 2 E3: sentencia 3 ......................... ......................... En: sentencia n [sino sentencia x ] 87 fin...según Case <variable> of Opción1 < acción S1> Opción2 < acción S2> Opción n < acción n> ........ < acción .......> else < acción S m> Para el problema anterior su pseudocódigo será: según...sea A hacer 1: Imprimir U n o 2: Imprimir D o s 3: Imprimir T r e s 4: Imprimir C u a t r o sino Imprimir C i n c o fin...según y su diagrama N − S es: Case A of 1 Imprimir UNO 2 Imprimir DOS 3 Imprimir TRES 4 Imprimir CUATRO else Imprimir CINCO El código del procedimiento es: procedure seleccion; 88 {* determina el valor de A y hace su valor a letras *} begin {* comienzo de alternativa *} case A of {* comienza seleccion *} 1 : writeln ( 'U n o '); {* salida por uno *} 2 : writeln ( 'D o s '); {* salida por dos *} 3 : writeln ( 'T r e s '); {* salida por tres *} 4 : writeln ( 'C u a t r o '); {* salida por cuatro *} else writeln ( 'C i n c o '); {* salida por cinco *} end; {* fin del case *} end; {* fin de alternativa *} Quedándonos el programa de la siguiente manera. Program Seleccion_4; {* Uso de selectores *} uses crt, dos; {declaraciones} {const} {* no hay constantesr *} var A : integer; {* valor que ingresa *} procedure limpieza; {* comienzo de limpieza de la pantalla *} begin ClrScr; end; {* fin de limpieza de la pantalla *} procedure ingreso; {* comienzo del ingreso de datos *} begin write ('Ingrese un numero de 1 a 5 : '); {* ingreso de variable A *} readln (A); 89 end; {* fin del ingreso de datos *} procedure seleccion; {* determina el valor de A y hace su valor a letras *} begin {* comienzo de alternativa *} case A of {* comienza seleccion *} 1 : writeln ( 'U n o '); {* salida por uno *} 2 : writeln ( 'D o s '); {* salida por dos *} 3 : writeln ( 'T r e s '); {* salida por tres *} 4 : writeln ( 'C u a t r o '); {* salida por cuatro *} else writeln ( 'C i n c o '); {* salida por cinco *} end; {* fin del case *} end; {* fin de alternativa *} procedure resultado; {* se utiliza para dejar en pantallas los resultados *} Var H :char; begin writeln ( 'Preione cualquir tecla '); readln (H); {* esta instrucci¢n y la anterior son para dar tiempo para *} {* ver resultados *} end; {* fin de resultado *} begin limpieza; ingreso; seleccion; resultado; end. Resumen: 90 Existen tres tipos de estructuras selectivas • If • If anidado • case Cada uno tiene su aplicación específica y se debe tener cuidado si se tiene por salida una o más sentencias. (Si hay más de una sentencia por salida colocar Begin End ). Condicionales • Ingresar valores numéricos enteros A, B, C, D, E y decir si su promedio es mayor que o igual a 10. • Ingresar valores numéricos reales A, B, C, y decir si su promedio es mayor que o igual a 10. • Ingresar valores numéricos reales a, b, c, que son coeficientes de una ecuación cuadrática y obtener los valores X1 y X2 reales. Si la operación dentro de la raíz diera como resultado un valor negativo, imprimir un cartel que diga La solución son dos números complejos conjugados. • Ingresar valores numéricos reales a, b, c, que son coeficientes de una ecuación cuadrática y obtener los valores X1 y X2 reales. Si la operación dentro de la raíz diera como resultado un valor negativo, imprimir el resultado como m + n i; m − n i . • Hacer un programa que permita ingresa un número de 1 a 7 y salga el correspondiente día de la semana ( Ej: 1 ! Lunes; 2 ! Martes; ...). Si ingresa un valor que no este comprendido entre 1 y 7 deberá imprimir un cartel que diga ERROR ... valor fuera de rango • Hacer un programa que permita ingresa dos números reales y el símbolo de la operación. Obteníendose el correspondiente resultado. Si el símbolo no es correcto, deberá imprimir un mensaje que indique Error en símbolo Estructuras de Programación Hasta ahora hemos visto dos tipos de estructuras de control • secuenciales • selectivas En esta practica veremos el tipo de estructura que nos queda. Repetitivas: Las estructuras repetitivas (llamadas también bucles, lazo o ciclo) se utilizan para realizar varias veces el mismo conjunto de operaciones. Dentro de ellas encontramos aquellas donde la cantidad repeticiones se manejan por un número, las que se realizan hasta que se cumple cierta condición. Son tres la sentencia for y la sentencia while y la sentencia repeat For esta sentencia, es un bucle controlado por un contador, denominado variable de control o índice. Pseudocódigo en español Código se programa desde variable (v) = vi hasta vf hacer for variable (v) = vi to vf do < acción S1> begin <acción S2 > < acción S1> ....................... < acción S2> 91 fin desde ...................... end Su estructugrama tiene la siguiente forma desde v = vi hasta vf < acción S1> <acción S2 > ...................... Ejemplos: a) Hacer un programa que imprima los números de 5 hasta 28. Pseudocódigo del programa nombre repetición1(program); declaraciones (uses) Crt, Dos; constantes(const) A = 5; B = 28; variables (var) R (resultado de la oper.): entero funciones(function)(NO hay); procedimientos (procedure); inicio (begin); limpieza(limpia la pantalla); ciclo (hace ciclo e imprime); salida fin(end.) Diagrama N−S nombre selección1 declaraciones Crt, Dos Constantes A, B Variables R :entero funciones y procedimientos comienzo (programa) limpieza ciclo fin (programa) Como se puede ver tenemos varios procedimientos ya vistos. Por lo tanto solo se desarrollara el pseudocódigo y el estructurado de ciclo, y todo lo que de el dependa. algoritmo ciclo Pseudocódigo del ciclo 92 procedimiento ciclo inicio (begin); desde R= A hasta B hacer imprimo R fin(end;) Diagrama N−S desde R = A hasta B imprimir R El código del procedimiento es: procedure ciclo; {* comienzo el ciclo *} begin for R := A to B do {* se define el ciclo A *} writeln ('Numero ',R ); {* imprime salida *} end; {* fin del ciclo *} Quedándonos el programa de la siguiente manera. Program Repeticion_1; {* Este es el primer programa con estructuras de repeticion *} uses crt, dos; {declaraciones} const {* constantesr *} A = 5; B = 28; var R: integer; {* controla el ciclo *} procedure limpieza; {* comienzo de limpieza de la pantalla *} begin 93 ClrScr; end; {* fin de limpieza de la pantalla *} procedure ciclo; {* comienzo el ciclo *} begin for R := A to B do {* se define el ciclo A *} writeln ('Numero ',R ); {* imprime salida *} end; {* fin del ciclo *} procedure salida; {* comienzo del procedimiento salida *} {*solo sirve para ver los resultados *} Var H :char; begin writeln ( 'Preione cualquir tecla '); readln (H); {* esta instrucci¢n y la anterior son para dar tiempo para *} {* ver resultados *} end; {* fin del procedimiento salida *} begin limpieza; ciclo; salida; end. b) Hacer un programa que calcule e imprima el factorial de los números 1 a 7 Pseudocódigo del programa nombre repetición2(program); declaraciones (uses) Crt, Dos; constantes(const) A = 1; B = 7; Diagrama N−S nombre selección1 declaraciones Crt, Dos Constantes A, B Variables R, Fac :entero 94 variables (var) R, Fac (resultado de la oper.): entero procedimientos (procedure); inicio (begin); limpieza(limpia la pantalla); ciclo2 (hace ciclo e imprime); salida fin(end.) funciones y procedimientos comienzo (programa) limpieza ciclo2 salida fin (programa) pseudocódigo y el estructurado de ciclo, y todo lo que de el dependa. algoritmo ciclo Pseudocódigo del ciclo procedimiento ciclo inicio (begin); desde R= A hasta B hacer Fac ! Fac * R imprimo Fac fin_desde fin(end;) Diagrama N−S desde R = A hasta B Fac ! Fac * R imprimir Fac . Como se puede ver dentro del ciclo se hace dos procesos, el cálculo del factorial y la impresión del resultados quedándonos este algoritmo estructurado. El código del procedimiento es: procedure ciclo; {* comienzo el ciclo *} 95 begin Fac := 1; for R := A to B do {* se define el ciclo A *} begin Fac := Fac * R; {* Calcula factorial *} writeln ('Numero : ',R, ' Factorial : ',Fac ); {* imprime salida numero y factorial *} end end; {* fin del ciclo *} Como se puede observar el se necesitó colocar un begin y un end para definir comienzo y fin del ciclo, ya que el mismo tiene más de una instrucción. Fac se define igual a uno, porque sino el producto nos daria siempre 0 (cero). Quedándonos el programa de la siguiente manera. Program Repeticion_2; {* Este es el segundo ejemplo de For *} uses crt, dos; {declaraciones} const {* constantesr *} A = 1; B = 7; var R, Fac : integer; {* controla el ciclo *} procedure limpieza; {* comienzo de limpieza de la pantalla *} begin ClrScr; end; {* fin de limpieza de la pantalla *} Procedure ciclo; {* comienzo el ciclo *} 96 begin Fac := 1; for R := A to B do {* se define el ciclo A *} begin Fac := Fac * R; {* Calcula factorial *} writeln ('Numero : ',R, ' Factorial : ',Fac ); {* imprime salida numero y factorial *} end end; {* fin del ciclo *} procedure salida; {* comienzo del procedimiento salida *} {* solo sirve para ver resultados *} Var H :char; begin writeln ( 'Preione cualquir tecla '); readln (H); {* esta instrucci¢n y la anterior son para dar tiempo para *} {* ver resultados *} end; {* fin del procedimiento salida *} begin limpieza; ciclo; salida; end. Hay que tomar en cuenta que los ciclos cumplen con las mismas reglas que las opciones tiene más de una instrucción el ciclo deberá llevar un begin con su correspondiente end cuando se tenga más de una instrucción.. Si fuera B > A el for seria for K = A donwto B do 97 Bucles controlados por una bandera (While − Repeat) Estos bucles no se repiten una cantidad definida de veces, sino se realizan hasta que se cumple una cierta condición. La diferencia entre ambos bucles (While y Repeat) es cuando se realiza la pregunta de la condición. While : en este ciclo la pregunta de condición se hace cada vez antes de comenzar el ciclo. Ejemplo : Se pide un programa donde ingresan una serie de números, el último es un valor negativo. Se pide calcular el promedio de los valores positivos (no incluir el último valor), e imprimir los valores y su promedio. En este caso tenemos que pautar si el último valor lo imprimimos o no. (si optamos por imprimirlo), esto implicará el siguiente pseudocódigo. Pseudocódigo del ciclo procedimiento ciclo inicio (begin); N!0 S!0 leo A imprimo A mientras A >= 0 hacer comenzar S!S+A N!N+1 leo A imprimo A terminar fin(end;) Diagrama N−S N!0 S!0 98 Leo A Imprimo A mientras A >= 0 hacer S!S+A N!N+1 Leo A Imprimo A . Como se puede ver dentro del ciclo se hace dos procesos, el cálculo del factorial y la impresión del resultados quedándonos este algoritmo estructurado. El código del procedimiento es: procedure ciclo; {* comienzo de ciclo *} begin S := 0; N := 0; write ( 'Ingrese un valor '); read (A); {* esta instrucci¢n y la anterior son el ingreso de datos *} writeln ( 'El valor es : ',A ); {* esta instrucci¢n imprime el valor *} WHILE A >= 0 DO {* se define el ciclo *} begin {* comienzo de While *} S := S + A; {* Calcula la suma de valores *} N := N + 1; {* Calcula la cantidad de valores *} writeln ; {* Salta una linea *} write ( 'Ingrese un valor '); read (A); {* esta instruccion y la anterior son el ingreso de datos *} writeln ( 'El valor es : ',A ); {* esta instrucci¢n imprime el valor *} end {* fin de While *} end; {* fin de ciclo *} 99 Quedándonos el programa de la siguiente manera. Program Repeticion_3; {* Este es el ejemplo de While *} uses crt, dos; {declaraciones} {const} {* constantes no hay*} var A, N, S : integer; {* controla el ciclo *} Prom :real; procedure limpieza; {* comienzo de limpieza de la pantalla *} begin ClrScr; end; {* fin de limpieza de la pantalla *} procedure ciclo; {* comienzo de ciclo *} begin S := 0; N := 0; write ( 'Ingrese un valor '); read (A); {* esta instrucción y la anterior son el ingreso de datos *} writeln ( 'El valor es : ',A ); {* esta instrucción imprime el valor *} WHILE A >= 0 DO {* se define el ciclo *} begin {* comienzo de While *} S := S + A; {* Calcula la suma de valores *} N := N + 1; {* Calcula la cantidad de valores *} writeln ; {* Salta una linea *} write ( 'Ingrese un valor '); 100 read (A); {* esta instrucci¢n y la anterior son el ingreso de datos *} writeln ( 'El valor es : ',A ); {* esta instrucci¢n imprime el valor *} end {* fin de While *} end; {* fin de ciclo *} procedure promedia; {* comienzo de promedia *} begin Prom := S / N; {* Calcula el promedio *} writeln ; {* Salta una linea *} writeln ; {* Salta una linea *} writeln ( 'Promedio es = ', Prom:5:2 ); {* Imprime el promedio *} end; {* fin de promedia *} procedure salida; {* comienzo del procedimiento salida *} {* solo sirve para ver resultados *} Var H :char; begin writeln ( 'Preione cualquir tecla '); readln (H); {* esta instrucci¢n y la anterior son para dar tiempo para *} {* ver resultados *} end; {* fin del procedimiento salida *} begin limpieza; ciclo; promedia; salida; end. En el procedimiento promedia en la escritura del promedio, aparece 101 writeln ( 'Promedio es = ', Prom:5:2 ); {* Imprime el promedio *} donde Prom:5:2 significa que la variable Prom será escrita en un formato de 5 caracteres, de los cuales 2 corresponden a los decimales, se necesita un carácter para el punto decimal. Repeat : esta solución se utiliza cuando el ciclo debe incluir el último valor ingresado. Ya que la pregunta se hace al final del ciclo. Ejemplo : Se ingresan una serie de números distintos, el último es el valor 12. Se pide un programa que calcule el promedio de los valores (incluir el último valor), e imprimir los valores y su promedio. Pseudocódigo del ciclo procedimiento ciclo inicio (begin); N!0 S!0 repetir leo A imprimo A S!S+A N!N+1 hasta_que A = 12 fin(end;) Diagrama N−S N!0 S!0 Leo A Imprimo A S!S+A N ! N + 1. hasta_que A = 12 102 El código del procedimiento es: procedure ciclo; {* comienzo el ciclo *} begin S := 0; N := 0; repeat {* comienza ciclo *} write ( 'Ingrese un valor '); read (A); {* esta instrucci¢n y la anterior son el ingreso de datos *} writeln ( 'El valor es : ',A ); {* esta instrucci¢n imprime el valor *} writeln ; {* Salta una linea *} S := S + A; {* Calcula la suma de valores *} N := N + 1; {* Calcula la cantidad de valores *} until A = 12; {* definicion al final del ciclo *} end; {* fin del ciclo *} Quedándonos el programa de la siguiente manera. Program Repeticion_4; {* Este es el ejemplo de Repeat − Until *} uses crt, dos; {declaraciones} {const} {* constantesr no hay*} var A, N, S : integer; {* controla el ciclo *} Prom :real; procedure limpieza; {* comienzo de limpieza de la pantalla *} begin ClrScr; 103 end; {* fin de limpieza de la pantalla *} procedure ciclo; {* comienzo el ciclo *} begin S := 0; N := 0; repeat {* comienza ciclo *} write ( 'Ingrese un valor '); read (A); {* esta instrucci¢n y la anterior son el ingreso de datos *} writeln ( 'El valor es : ',A ); {* esta instrucci¢n imprime el valor *} writeln ; {* Salta una linea *} S := S + A; {* Calcula la suma de valores *} N := N + 1; {* Calcula la cantidad de valores *} until A = 12; {* definicion al final del ciclo *} end; {* fin del ciclo *} procedure promedia; {* comienzo de promedia *} begin Prom := S / N; {* Calcula el promedio *} writeln ; {* Salta una linea *} writeln ; {* Salta una linea *} writeln ( 'Promedio es = ', Prom:5:2 ); {* Imprime el promedio *} end; {* fin de promedia *} procedure salida; {* comienzo del procedimiento salida *} {* solo sirve para ver resultados *} Var H :char; begin writeln ( 'Preione cualquir tecla '); 104 readln (H); {* esta instrucci¢n y la anterior son para dar tiempo para *} {* ver resultados *} end; {* fin del procedimiento salida *} begin limpieza; ciclo; promedia; salida; end. Como se puede observar esta estructura (repeat−until) carece de begin y end, ya que los dos extremos están definidos por el propio ciclo. Anidación Se pueden colocar un ciclo dentro de otro (anidar), esto quiere decir que una estructura contiene en su interior a otra. Las estructuras pueden ser de igual o de distinto tipo. Siempre que se cumpla con las condiciones que aparecen en la siguientes figuras. anidado anidado incorrecto Resumen: Existen tres tipos de estructuras repetitivas • For • While 105 • Repeat − until Cada uno tiene su aplicación específica y se debe tener cuidado cuando se anidan. Repetitivas • Leer una lista de 10 valores enteros. Calcular e informar: a) La suma de los valores positivos. b) El producto de los valores negativos. (Ignorar los valores nulos) • a) Ingresar 5 juegos de cuatro valores cada uno. Calcular y emitir. El promedio de cada juego. b) Ingresar N juegos de cuatro valores cada uno. Calcular y emitir. El promedio de cada juego. El proceso finaliza al encontrarse un juego cuyo primer valor es 0. • Ingresar dos números enteros positivos y calcular el producto de los mismos por sumas sucesivas. • Leer una lista de números positivos que finaliza en 0 y emitir el valor mínimo de la lista. • Leer una lista de números enteros que finaliza en 0 y emitir el valor máximo de la lista. • Ídem 5, emitiendo además la ubicación del máximo dentro de la lista. (Suponer un único máximo). • Leer 4 juegos de N valores enteros cada uno, donde N se informa al comienzo de cada juego, y emitir el valor máximo de cada grupo. (Suponer un único máximo ). • Dada una lista de valores numéricos positivos, finalizada en 0, indicar si esta ordenada en forma ascendente. • Una empresa nos informa para cada uno de sus 20 vendedores: código de vendedor : 3 dígitos importe de ventas del mes : real Se desea emitir el importe máximo de ventas del mes y cuántos vendedores alcanzaron dicho importe. • En una Central Telefónica se procesan los llamados realizados en la siguiente forma: Por cada llamada se ingresa: código de llamada : 3 dígitos (0 al finalizar el proceso) tipo de día : 1 hábil, 2 feriado duración de la llamada : entero > 0. Siendo los importes Primeros 3' Minuto Adicional Días hábiles a 10 a 2 Feriados a 15 a 3 Se deberá emitir: a) El importe a abonar por cada llamada (código − importe). b) La cantidad de llamadas que superen los 3' c) El % de llamados que superan los 3' (sobre el total de llamadas informadas). • Se leen 30 valores enteros (comprendidos entre 5 y 40), que representan la temperatura máxima de cada uno de los días de un mes. Se pide hallar e informar : − La temperatura máxima del mes y el día que se produjo. (Se supone única) − Cuántos días la temperatura supero los 25º C. − El promedio de las temperaturas máxima del mes. • Se ingresan los resultados de la evaluación de un curso de Programación ; por cada alumno se informa: número de matricula : 4 dígitos (1−9999) asistencia : 1, presente; o, ausente calificación : 2 dígitos (0−10). A partir de esta información se debe calcular e informar: 106 a) Cantidad y % de alumnos presentes. b) Promedio de calificaciones de alumnos presentes. c) % de alumnos aprobados (sobre el total de alumnos presentes). d) Numero de matricula del alumno de mayor calificación. (Si hay varios alumnos con esa calificación: numero de matricula y cantidad de alumnos en esa situación). Estructura de datos (arreglos) Vectores y Matrices Hasta aquí se han visto distintos tipos de estructuras de control. A partir de este punto se verá la aplicación de las mismas a distintos tipos de problemas. Estructura de datos: Una estructura de datos es una colección de datos que pueden ser caracterizados por su organización y las operaciones que se definen en ella. Dentro de ellas encontramos distintos tipos, los tipos de datos más frecuentes en los diferentes lenguajes son: Tipos de datos estándar simples entero (integer) real (real) carácter (char) lógico (boolean) definidos por el programador (no estándar) subrango (subrange) enumerativo (enumerated) simples o estáticos arrays (vectores/matrices) registros ficheros conjuntos cadenas (string) estructurados compuestos o dinámicos listas (pilas/colas) listas enlazadas árboles grafos Las estructuras estáticas son aquellas en las que el tamaño de memoria ocupado se define antes de que el programa se ejecute y no puede modificarse durante la ejecución Las estructuras dinámicas son aquellas en las que no se debe definir previamente el tamaño de memoria Los datos simples tienen en común que cada variable representa un elemento, en los estructurados un identificador puede representar múltiples datos individuales, pudiendo cada uno de estos ser referenciados independientemente. ARRAY UNIDIMENSIONALES: VECTORES 107 ARRAY (ARREGLO): Es un conjunto finito y ordenado de elementos homogéneos. • Ordenado : cada elemento del arreglo puede ser identificado • Homogéneo : son del mismo tipo de dato El tipo más simple de arreglo es el unidimensional o vector (matriz de una dimensión). Por ejemplo podría ser un vector denominado NOTAS NOTAS[1] 5 NOTAS[2] 8 .......... NOTAS[k] 7 ...... NOTAS[j] 3 Los subíndices 1, 2, k, n, indican la posición del elemento, en Pascal van entre corchetes. El primer elemento es el 5, el segundo es el 8, el elemento k es 7 y el enésimo es 3. Un array puede ser declarado de dos formas distintas que son: Declaraciones Tipo Array En las declaraciones del tipo array usaremos los siguientes pasos.: • La estructura del arreglo se describe en Type. • Se le asigna ese tipo a una o más variables. Type XX = array [1..3000] of real; Var: Alfa : XX; array y of son obligatorias [1...3000] indica los valores que toman los índices del vector, son del tipo subrango. real identifica que tipo de elementos almacena el vector. Variables Tipo Array En las declaraciones de variable tipo array se hará de la siguiente forma.: • En la declaración se describe la variable. Var: Alfa : array [1..3000] of real;; Los elementos cumplen la misma función que en el caso anterior. Dentro de los distintos tipos que un array puede almacenar en sus posiciones, puede ser un tipo Array como el del siguiente tipo: 108 Type Linea = array [1..40] of char; Hoja = array [1..30] of Linea; Libro = array [1..30] of Linea; Las operaciones que se pueden hacer con un vector son: • asignación • lectura/escritura • recorrido (acceso secuencial) • actualizar (añadir, borrar, insertar) • ordenación • búsqueda Asignación: Es darle un valor a un elemento de un vector Pseudocódigo en español Código se programa A[3] ! 5 A[3] := 5; Para la asignación como para otro procesos se debe recurrir a estructuras repetitivas (desde, mientras o repetir). Ejemplo: A cada uno de los 55 elementos del vector CARGA se le debe asignar el valor 0 Algoritmo de asigna Pseudocódigo en español Código se programa desde I = 1 hasta 55 hacer for I = 1 to 55 do CARGA[I] ! 0 CARGA[I] := 0; fin desde Su estructugrama tiene la siguiente forma desde I = 1 hasta 55 CARGA[I] ! 0 Pseudocódigo del programa nombre vector1(program); declaraciones (uses) Diagrama N−S nombre selección1 declaraciones Crt, Dos 109 Crt, Dos; constantes(const) A = 1; Constantes A, B tipos B = 55; tipo (type) matriz = array [1..55] de enteros variables (var) I entero CARGA matriz funciones(function)(NO hay); procedimientos (procedure); inicio (begin); limpieza(limpia la pantalla); asigna (hace ciclo y asigna); salida fin(end.) matriz [55] Variables Y CARGA funciones y procedimientos comienzo (programa) limpieza asigna salida fin (programa) Como se puede ver tenemos la definición del vector en tipo o type. El código del procedimiento es: procedure asigna; {* comienzo de la asignación *} begin for I := A to B do {* se define el ciclo de 1 a 55*} CARGA[I] := 0; {* asigna los valores *} end; {* fin del ciclo *} Quedándonos el programa de la siguiente manera. Program Vector_1; {* Este es el primer programa con vectores *} uses Crt, dos; {declaraciones} const {* constantes *} 110 A = 1; B = 55; type matriz = array [1..55] of integer; var I: integer; {* controla el ciclo *} CARGA: matriz; procedure limpieza; {* comienzo de limpieza de la pantalla *} begin ClrScr; end; {* fin de limpieza de la pantalla *} procedure asigna; {* comienzo de la asignación *} begin for I := A to B do {* se define el ciclo de 1 a 55 *} CARGA[I] := 0; {* asigna la valores *} end; {* fin de la asignación *} procedure salida; {* comienzo del procedimiento salida *} {* solo sirve para ver resultados *} Var H :char; begin writeln ( 'Presione cualquier tecla '); readln (H); {* esta instrucción y la anterior son para dar tiempo para *} {* ver resultados *} end; {* fin del procedimiento salida *} begin 111 limpieza; asigna; salida; end. Lectura/escritura: Es una operación de entrada salida sobre un vector. Manejado por estructuras repetitivas. Ejemplo: Ingresar por teclado cada uno de los 5 elementos de un vector de nombre vec. Y luego leerlos y presentarlos por pantalla en orden inverso al que entraron (de 5 a 1) Algoritmo de escribe Pseudocódigo en español Código se programa desde I = 1 hasta 5 hacer comienzo imprimo mensaje leo y escribo en vec[I] for I = 1 to 5 do begin write (` `); read (vec[I] ); end; fin desde Su estructugrama tiene la siguiente forma desde I = 1 hasta 5 imprimo mensaje leo vec[I] El código del procedimiento es: procedure escribir; {* escribe en el vector *} begin for I := A to B do {* se define el ciclo de 1 a 5 *} begin write ('Ingrese vec(',I:1,') : '); readln(vec[I]); {* escribe en el vector *} 112 end; end; {* fin de escritura *} Algoritmo de lee Pseudocódigo en español Código se programa desde I = 1 hasta 5 hacer leo vec[I] for I = 1 to 5 do read (vec[I] ); fin desde Su estructugrama tiene la siguiente forma desde I = 1 hasta 5 imprimo vec[I] El código del procedimiento es: procedure leer; {* lee el vector *} begin for I := B downto A do {* se define el ciclo de 5 a 1 *} writeln ('vec(',I:1,') = ',vec[I]:2); {* lee el vector y lo saca por pantalla *} end; {* fin de lectura *} Pseudocódigo del programa Nombre vector2(program); Declaraciones (uses) Crt, Dos; Constantes(const) A = 1; B = 5; tipo (type) Matriz = array [1..5] de enteros variables (var) I entero vec matriz Funciones(function)(NO hay); Diagrama N−S nombre selección1 declaraciones Crt, Dos Constantes A, B tipos matriz [5] Variables I vec funciones y procedimientos comienzo (programa) 113 Procedimientos (procedure); inicio (begin); limpieza(limpia la pantalla); escribir (escribe en el vector) leer (lee del vector y saca por pantalla) salida fin(end.) limpieza escribe lee salida fin (programa) Program Vector_2 {* Este es el segundo programa con vectores *} uses crt, dos; {declaraciones} const {* constantes *} A = 1; B = 5; type matriz = array [1..5] of integer; var I: integer; {* controla el ciclo *} vec: matriz; procedure limpieza; {* comienzo de limpieza de la pantalla *} begin ClrScr; end; {* fin de limpieza de la pantalla *} procedure escribir; {* escribe en el vector *} begin for I := A to B do {* se define el ciclo de 1 a 5 *} begin write ('Ingrese vec(',I:1,') : '); 114 readln(vec[I]); {* escribe en el vector *} end; end; {* fin de escritura *} procedure leer; {* lee el vector *} begin for I := B downto A do {* se define el ciclo de 5 a 1 *} writeln ('vec(',I:1,') = ',vec[I]:2); {* lee el vector y lo saca por pantalla *} end; {* fin de lectura *} procedure salida; {* comienzo del procedimiento salida *} {* solo sirve para ver resultados *} Var H :char; begin writeln ( 'Presione cualquier tecla '); readln (H); {* esta instrucción y la anterior son para dar tiempo para *} {* ver resultados *} end; {* fin del procedimiento salida *} begin limpieza; escribir; leer; salida; end. Recorrer: Esta operación se realiza cuando uno lee el vector, y se aplica tanto cuando se busca un elemento de un vector o cuando se desea listar el mismo, como lo vimos en el ejemplo anterior. Actualizar 115 Añadir: Se denomina así a la operación de agregar un nuevo, elemento al final del vector. la única condición necesaria para esta operación consiste en la comprobación de espacio libre en memoria. Ejemplo: Dado el vector U de 7 elementos añadir un elemento más al vector Algoritmo de añade Código se programa Pseudocódigo en español I!0 repetir I ! I +1 I := 0; repeat I := I + 1; until U[I] = 0 or i >q hasta que U[I] = 0 o i > k si i es menor o igual a k entonces leo nuevo U[I] sino imprimo No más lugar fin_si if I <= k then read (U[I] ) else writeln(No mas lugar) Su estructugrama tiene la siguiente forma I ! I +1 U[I] = 0 o i > k I es menor o igual a k leo nuevo U[I] imprimo No más lugar El código del procedimiento es: procedure agrega; {* agrega un elemento al vector *} begin I:=0; repeat I := I + 1; until (U[I]=0) or (I> 7); {* Se repite hasta que se encuentre una bandera o se termine el vector *} if I<= 7 then 116 begin writeln ('Ingrese un nuevo elemento al vector'); read ( U[I]) end else writeln ('No hay mas lugar en el vector'); end; {* fin de agrega *} Borrar: Es eliminar un elemento de un vector se puede hacer de dos maneras una es reemplazar el elemento por el utilizado como señal. Puede servir pero no es recomendado en proyectos pequeños. Pero no así en grandes. El otro método consiste en mover los elementos que se encuentran debajo de él una posición hacia arriba, colocando una bandera en la última celda. Ambos métodos tienen el paso de búsqueda en común utilizado en añadir, lo que varían son los pasos posteriores al Si. (Solo representaremos estos pasos) Ejemplo: Dado el vector U de 7 elementos eliminar un elemento al vector Método rudimentario Algoritmo de elimina (rudimentario) Código se programa Pseudocódigo en español Y!0 I := 0; repeat I := I + 1; repetir I ! I +1 until U[I] = 0 or I >q hasta que U[I] = 0 o I > k si I es menor o igual a k entonces U[I] ! 0 if I <= k then U[I] := 0; sino imprimo No existe el elemento fin_si else writeln(No existe el elemento) Su estructugrama tiene la siguiente forma I ! I +1 U[I] = 0 o I > k 117 I es menor o igual a k imprimo No existe el elemento U[I] ! 0 Método Optimo Algoritmo de elimina (optimo) Pseudocódigo en español Código se programa I!0 I := 0; Lee Aux Readln(Aux); repetir repeat I ! I +1 hasta que U[i] = Aux o I > k si i es menor o igual a k I := I + 1; until U[i] = Aux or I >q if I <= k then entonces repeat repetir U[I] := U[I+1]; U[I] ! U[I + 1] I := I + 1; I ! I +1 hasta que U[i] = 0 o I > k until U[I] = 0 or I >q ; else sino imprimo No existe el elemento fin_si writeln(No existe el elemento) Su estructugrama tiene la siguiente forma I!0 Lee Aux I ! I +1 U[I] = Aux o I > k I es menor o igual a k U[I] ! U[I+1] I ! I +1 imprimo No existe el elemento U[I] = 0 o I > k 118 Insertar: Se debe trabajar sobre un vector ordenado. Consiste en introducir un nuevo elemento al vector sin que este pierda el orden. Para ello se debe comprobar que haya lugar libre en el vector, luego de lo cual se deberá desplazar hacia bajo los elementos necesarios como para generar un espacio libre en la posición adecuada sin que se pierda el orden. Algoritmo de inserta (Ordenado creciente) Código se programa Pseudocódigo en español I!0 I := 0; Read(Aux); Lee Aux repeat repetir I := I + 1; I ! I +1 until U[i] = 0 or I >B hasta que U[i] = 0 o I > B si i es menor o igual a B entonces if I <= B then begin I := I − 1; I ! I −1 while U[I] > Aux mientras U[i] > Aux begin U[I+1] ! U[I] U[I+1] := U[I]; I ! I −1 I := I − 1; fin mientras end; U[I+1] ! Aux U[I+1] = Aux; sino end imprimo No hay lugar fin_si else writeln(No hay lugar) Su estructugrama tiene la siguiente forma I!0 Lee Aux I ! I +1 119 U[I] = Aux o I > k I es menor o igual a k I ! I −1 U[I] > Aux U[I+1] ! U[I] I ! I −1 U[I+1] ! Aux imprimo No hay lugar Ordenación: La ordenación o clasificación es, el proceso de clasificar datos en algún orden o secuencia específica como creciente o decreciente. Existen varios métodos de ellos elegiremos el de intercambio (decantación). Algoritmo de ordena (Ordenado creciente) Pseudocódigo en español I!0 Código se programa repetir I := 0; I ! I +1 repeat hasta que U[i] = 0 o I > B I := I + 1; P!I−1 until U[i] = 0 or I > B desde I ! 1 hasta P −1 hacer P := I − 1; desde J ! 1 hasta P − I hacer for I = 1 to P−1 do si U[J] > U[J +1] for J = 1 to P− I do entonces (intercambiar) if U[J] > U[J +1] then Aux ! U[J] begin U[J] ! U[J +1] Aux := U[J]; U[J +1] ! Aux U[J] := U[J +1]; fin si U[J +1] := Aux ; fin desde end; fin desde Su estructugrama tiene la siguiente forma 120 I!0 I ! I +1 U[I] = 0 o I > k P ! I −1 I ! 1 hasta P −1 J ! 1 hasta P − I U[J] > U[J +1] Aux ! U[J] U[J] ! U[J +1] U[J +1] ! Aux Búsqueda: La búsqueda de un dato dentro de un array consiste en determinar si un elemento N pertenece o no al conjunto de datos y posición que el ocupa en el conjunto. Los distintos tipos de búsqueda se pueden clasificar en: búsqueda secuencial búsqueda binaria búsqueda por transformación de claves (hash) En este curso solo se verá el primer tipo, ya que las dos siguientes están fuera del alcance del mismo. Búsqueda Secuencial: Compara cada elemento del vector con el valor deseado. Si se encuentra es el método que ofrece menor eficiencia pero el más sencillo. Esto se puede ver en el ejemplo anterior. Ejemplo general Hacer un programa que permita operar con un vector de siete posiciones, que opere con números naturales. Pudiendo agregar, eliminar o insertar un valor, también se podrá listar todos los valores que tiene el vector. Usaremos como centinela el número 0 (cero) por lo cual lo primero que deberá hacer el programa deberá asignarle a todos los elementos del vector dicho valor . El programa cuenta con tres llamados. begin limpieza; {* limpia la pantalla *} asigna; {* asigna los 0 al vector *} 121 menu; {* llama al módulo menú *} end. Los módulos limpieza y asigna ya se han detallado. En cuanto a menu es un selector. Algoritmo de menu Código se programa Pseudocódigo en español repeat repetir repeat repetir limpieza; llama a Limpieza writeln (' M E N U '); escribir Titulos writeln ( ' 1. Ingresar un valor al vector '); escribir Opciones writeln; leer valor elegido (H) write ( ' Elija una opción '); hasta que H > 0 y H < 7 readln (H); {* lee la opción *} según sea H hacer until (H > 0) and (H < 7); 1: llama a Agrega case H of 2: llama a Lista 1 : Agrega; 3: llama a Borra 2 : Lista; 4: llama a Ordena 3 : Borra; 5: Inserta 4 : Ordena; sino limpia pantalla 5 : Inserta; fin según else clrscr; mientras H > 6 end; until H = 6; En el procedimiento borra, lo que realiza el algoritmo es desplazar cada uno de los elementos posteriores al que queremos eliminar a una posición anterior a la que teníamos. Este procedimiento cuenta con dos partes. • encuentra el elemento a borrar 122 • desplaza los elementos posteriores a una posición anterior, el centinela nos sirve para optimizar el proceso. program vectores; {* Programa de subrutinas de vectores *} uses crt, dos; {*declaraciones*} const {* constantes *} NL = ·#13#10; {* Nueva Línea Carrige Return, Line Feed*} A = 1; B = 7; type vector = array [1..7] of integer; var I: integer; {* controla el ciclo *} U: vector; procedure limpieza; {* comienzo de limpieza de la pantalla *} begin ClrScr; end; {* fin de limpieza de la pantalla *} procedure salida; {* comienzo del procedimiento salida *} {* solo sirve para ver resultados *} Var H :char; begin writeln ( 'Presione cualquir tecla '); readln (H); {* esta instrucci¢n y la anterior son para dar tiempo para *} {* ver resultados *} end; {* fin del procedimiento salida *} 123 procedure Lugar; {* determina cuantos lugares están ocupados del vector *} begin I:=0; repeat I := I + 1; until (U[I]=0) or (I> 7); {* Se repite hasta que se encuentre una bandera o se termine el vector *} end; {* fin de lugar *} procedure asigna; {* comienzo de la asignación *} begin for I := 1 to 7 do {* se define el ciclo de 1 a 7 *} U[I] := 0; {* asigna *} end; {* fin de la asignación *} procedure Ordena; {* ordena el vector *} var J, P, Aux : integer; begin I := 0; repeat I := I + 1; until (U[I]=0) or ( I>B ); {* Determina cuantos valores validos hay en el vector *} P := I − 1; for I := 1 to P − 1 do {* se define el ciclo hasta el anteúltimo valor cargado *} for J := 1 to P − I do if U[J] > U[J+1] then begin {* Intercambia *} 124 Aux := U[J]; U[J] := U[J+1]; U[J+1] := Aux; end end; {* fin del ordenamiento *} procedure lista; {* lee y lista el vector *} begin I := 1; while (U[I] <> 0) and (I<= B ) do {* se lee hasta encontrar *} begin {* un centinela o el final del vector *} writeln ('U(',I:1,') = ',U[I]:3); {* lee el vector y lo saca por pantalla *} I := I + 1; end; Salida; end; {* fin de lectura y listado *} procedure Borra; {* borra un elemento del vector *} var J : integer; H : char; begin I := 1; write ('Ingrese el valor a borrar : '); read (J); while (U[I] <> 0) and (I<= B ) and (U[I] <> J) do {* se hace la búsqueda *} I := I + 1; 125 if U[I] <> J then begin {* No se encontró el valor *} write (' Elemento no encontrado '); readln(H); end else begin while U[I] <> 0 do {* Se borra el valor *} begin U[I] := U[I+1]; I := I + 1; end; write (' Elemento borrado '); readln(H); end; end; {* fin de borrado *} procedure agrega; {* agrega un elemento al vector *} var H:char; begin Lugar; if I <= 7 then repeat write ('Ingrese un nuevo valor al vector : '); readln ( U[I]); I := I + 1; 126 until (U[I−1] = 0) or (I > B) else begin write ('No hay mas lugar en el vector'); Read (H); end end; {* fin de agrega *} procedure inserta; {* inserta un elemento al vector ordenado *} var H:char; K, Aux : integer; begin Lugar; if I <= B then begin K := I; write ('Ordeno el vector ? (S/N) '); Read (H); if (H = 'S') or (H = 's') then Ordena; write ('Ingrese el valor a insertar : '); Read (Aux); I := K − 1; while U[I] > Aux do begin U[I+1] := U[I]; I := I − 1; 127 end; U[I+1] := Aux; end else begin write ('No hay mas lugar en el vector'); Read (H); end end; {* fin de agrega *} procedure menu; {* comienzo del procedimiento menu *} {* genera y maneja un menu de opciones *} Var H :integer; begin repeat repeat limpieza; writeln (' M E N U '); writeln (' −−−−−−−−−−−', NL, NL, NL); writeln ( ' 1. Ingresar un valor al vector ', NL); writeln ( ' 2. Listar el vector ', NL); writeln ( ' 3. Borrar un valor ', NL); writeln ( ' 4. Ordenar el vector ', NL); writeln ( ' 5. Insertar un valor ', NL); writeln ( ' 6. Salir del programa ', NL, NL); write ( ' Elija una opcion '); 128 readln (H); {* lee la opción *} until (H > 0) and (H < 7); case H of 1 : Agrega; {* Llamada al procedimiento de agregar *} 2 : Lista; {* Llamada al procedimiento de listar *} 3 : Borra; {* Llamada al procedimiento de borrar *} 4 : Ordena; {* Llamada al procedimiento de ordenar *} 5 : Inserta; {* Llamada al procedimiento de insertar *} else clrscr; {* Llamada a la salida del programa *} end; until H = 6; end; {* fin del procedimiento menu *} begin {* Comienzo del programa *} limpieza; {* limpia la pantalla *} asigna; {* asigna los 0 al vector *} menu; {* llama al módulo menú *} end. {* Fin del programa *} Copia de un array: Un array puede ser asignado a otro array, si y solo si, ambos tienen el mismo tipo y el mismo tamaño. Lo que implica que ambos fueron declarados por el mismo identificador o por identificadores equivalentes. Ejemplo: Type XX = array [1..30] of byte; YY = array [1..30] of byte; Var: Alfa, Gama: XX; Beta: YY; 129 Alfa := Gama; {única expresión válida}. Beta := Alfa; Gama := Beta;. Parámetros de valor y de variable: Los arrays pueden ser utilizados como parámetros en funciones y procedimientos; sin embargo, el valor de una función no puede ser un array. Las variables tipo array pueden ser utilizadas como parámetros en la comunicación entre funciones y procedimientos. El array local se inicializa de modo que contiene los mismos valores que el array real correspondiente. El procedimiento manipula el array local y cualquier cambio que se haga en el array local no se refleja en el array real. type Vector = array [1..10] of real; var M, N, P : Vector; R : boolean; function Identidad (A, B : Vector) : boolean; var end; procedure Suma (A; B: Vector; var C: Vector); end; R := Identidad(M,N); Suma (M,N,P); Pasaje de elementos individuales: En lugar de pasar todos los elementos del array, se pasan de uno por vez. Para el ejemplo anterior se puede decir: function Identidad (A, B : real) : boolean; var end; R := Identidad(M[3], N[3]); Array bidimensionales (Tablas) Un array bidimensional (tabla o matriz) es un array con dos índices, al igual que los vectores que deben ser 130 ordinales o tipo subrango. Para localizar o almacenar un valor en el array se deben especificar dos posiciones (dos subíndices), uno para la fila y otro para la columna. Los elementos se referencian con el formato: T [3,A] elemento de la fila 3 y columna 4 Los diferentes tipos de índices no necesitan ser subrango del mismo tipo. Declaración de los arrays bidimensionales Al igual que en los arrays de una dimensión (los vectores), los arrays multidimensionales (tablas) se crean con declaraciones type y var cuando un programa se codifica en Pascal. type Tabla = array [1..10,4..25] of real; type Tabla = array [1..10] of array [4..25] of real; var M, : array [1..10,4..25] of real; Manejo de tablas Para el manejo de tablas, no debemos olvidarnos que las celdas de las mismas se identifican por dos subíndices. Por lo tanto cualquier proceso que queramos realizar sobre la misma, involucrará a ambos subíndices. Por ejemplo cuando se desea leer un array se podrá hacer por filas, según se puede ver. var M, : array [1..10,4..25] of real; For Fila := 1 to 10 For Columna := 4 to 25 Writeln(A[Fila, Columna]); Por columnas. For Columna := 4 to 25 For Fila := 1 to 10 Writeln(A[Fila, Columna]); Array multidimensionales Pascal no tiene límite para el número de dimensiones. Pero al usuario corriente no se le recomienda superar 131 las 3 dimensiones, ya que se vuelve complejo su manejo. Declaración de los arrays multidimensionales Al igual que en los arrays de bidimensionales (las tablas), los arrays multidimensionales se crean con declaraciones type y var cuando un programa se codifica en Pascal. type Matriz = array [1..10,4..25,´A¨..¨Z¨] of byte; type Vector = array [1..10] of byte; Matriz = array [4..25,´A¨..¨Z¨] of Vector; type Vector = array [1..10] of byte; Tabla = array [4..25] of Vector; Matriz = array [´A¨..¨Z¨] of Tabla; var M, : array [1..10] of array [4..25,] of array [´A¨..¨Z¨] of byte; CONSTANTES DE TIPO ARRAY (TIPEADAS) Turbo Pascal permite que las constantes con tipo (tipeadas) puedan ser de casi cualquier tipo. Las constantes con tipo, no son constantes en el estricto sentido, sino variables inicializadas, es decir, variables que tienen un valor inicial específico en la cabecera del programa. Ejemplos const A : array [1..5] of integer = (10,20,30,40,50); const ( vectores ) Dias Por Mes : array [l..l2] of integer = (31,28,31,30,31,30,31,31,30,31,30,31); Práctica Nº 7 • Leer una lista de 10 valores enteros. Listarlos por pantalla en sentido inverso al que ingresaron. • Dado un vector 15 valores, hacer un programa que pueda obtener, y sacar por pantalla • el mayor de los valores • el menor de los valores 132 • el más próximo al promedio • Suponiendo que los valores del problema anterior fueran mediciones. Se pide modificarlo de forma tal que sin uso de vectores auxiliares. Se pueda calcular la desviación media y ña desviación estándar Donde Xj, es cada uno de los valores X es el promedio de los valores, y N la cantidad de valores. • Se lee las letras de una palabra carácter a carácter. El último carácter que ingresa es la barra de dividir(/), que indica que la palabra ha finalizado. Escribir un programa que imprima la palabra en el orden que se ingresó y en sentido inverso (pera arep, la palabra podrá tener hasta 20 caracteres). • Diseñar un algoritmo recursivo, que permita invertir el contenido de un vector. Como indica el ejemplo: Vector original: 28 35 12 43 56 77 Vector invertido: 77 56 43 12 35 28 El algoritmo no podrá usar un vector auxiliar. • Hacer un programa que permita realizar la suma y el producto de dos vectores. • El usuario puede elegir el tamaño del vector (entre 2 y 10 valores) • El usuario elige la operación a realizar. • Dado un vector de 20 posiciones (números enteros). Genere un programa que permita realizar las siguientes operaciones. • Ingresar un elemento en el final de la cola (primera posición libre del vector). Comprobando antes del ingreso que existe una posición libre, sino colocar un mensaje de aviso. • Sacar el elemento que se encuentra en la primera posición (si hay, sino colocar un mensaje de aviso), corriendo luego los demás en la cola una posición hacia delante. • Listar en cualquier momento el contenido de la cola del primero al último. • Dado un vector de 20 posiciones (números enteros). Genere un programa que permita realizar las siguientes operaciones. • Ingresar un elemento en la última posición de la pila (primera posición libre del vector). Comprobando antes del ingreso que existe una posición libre, sino colocar un mensaje de aviso. • Sacar el elemento que se encuentra en la última posición (si hay, sino colocar un mensaje de aviso). • Listar en cualquier momento el contenido de la pila del primero al último. • Dado un vector de 20 posiciones (números enteros). Genere un programa que permita realizar las siguientes operaciones. • Ingresar un elemento en la posición que le corresponda de la lista, de manera que la misma se mantenga en orden creciente. (para lo cual desplaza los demás elementos una posición para atrás).Comprobando antes del ingreso que existe una posición libre, sino colocar un mensaje de aviso. • Sacar de la lista el elemento que indica el usuario (si se encuentra, sino colocar un mensaje de aviso). • Listar en cualquier momento el contenido de la cola del primero al último. • Pascal como otros lenguajes operan con números enteros 2,148 109, estos no tienen errores por redondeo. Para valores más grandes se trabajan con reales, pero ellos si tienen errores de redondeo. Se le pide a Ud.. Haga un programa que opere con números que poseen entre 10 y 20 cifras, que puedan hacer: 133 • Suma • Resta • Multiplicación Sin errores, asegurando todas las cifras ** Se recomienda hacer todos los problemas de esta práctica. Tratamiento de Cadenas de Caracteres Una cadena de caracteres (string), es una serie de caracteres cuya longitud puede variar entre 1 y 255 caracteres. A este tipo se lo define tipo string, para declarar este tipo de variable se puede hacer de cualquiera de las siguientes formas: Ejemplo type cadena50 = string [50]; var nombre : cadena50; var mensaje : string [80]; Longitud de una cadena: La longitud de una cadena es igual al número de caracteres (contando como tales también los espacios en blanco), pero ocupara en memoria un byte más. Por ejemplo: Nombre : string [10]; Si en nombre utilizo Murcielago, ocupará en memoria 11 bytes, 1 por letra y uno más por la longitud. Número de byte 0 10 1 M 2 u 3 r 4 c 5 i 6 e 7 l 8 a 9 g 10 o En Turbo Pascal existen para una cadena dos longitudes: Longitud física: Es la cantidad de memoria que se le reserva a la cadena al comienzo del programa, 10 bytes en el caso de Nombre del ejemplo anterior. Longitud lógica: Es la cantidad el número de caracteres que se tienen almacenados en esa variable en un cierto momento. Por ejemplo: si durante el programa hago Nombre := `Ada'; La longitud lógica será igual a 3. Se puede acceder a cualquier elemento de una cadena: para ello hay que indicar el número del carácter al cual se quiere acceder. 134 Ejemplo Var Carac : char; Nombre : string[10]; begin Nombre := `Murcielago' Carac := Nombre [6]; A partir de aquí la variable Carac toma el valor e OPERACIONES CON CADENAS Dos cadenas pueden sumarse. `Papá de ` + `Pepe' ! `Papa de Pepe' Dos cadenas pueden compararse. `Papá' < `Pepe' porque `a' < `e' Lo que compara es el ASCII que le corresponde a los caracteres. Comienza comparando el primero con el primero, si son iguales lo hace con el segundo y así sucesivamente hasta encontrar la desigualdad. Procedimientos y funciones con cadenas Función Concat: Es equivalente a la suma de string, si la cantidad de caracteres supera los 255 corta el excedente del string. Concat(S1, S2, S3) " S1 + S2 + S3 Función Length(s): Devuelve un entero que es la longitud lógica del string s Length(nombre) ! 10 Procedimiento Delet: Delet(s, posición, número) Delet(nombre,3,4) ! Mulago Elimina a partir del tercer carácter, 4 caracteres (rcie). Procedimiento Insert: 135 Insert(cad1,s, posición) Insert(nombre, 'ju', 4) ! Murjucielago Inserta el string s o en nuestro caso los caracteres entre apóstrofos en cad1, a partir del carácter posición. Función Pos: Pos(S1, S2) devuelve la posición donde S1 = S2 Pos(nombre, 'ci', ) ! 4 Devuelve la posición de un string dentro de la cadena. Función Copy: Copia parte de un string y lo almacena en otro. S2 := Copy(S1, posición, número) S2 := Copy(Nombre, 5, 4) ! "iela" Procedimiento Str: Str(valor,cad1) Convierte un número en un string. Str(1573, S1) ! "1" "5" "7" "3" Procedimiento Val: Val(S1,número, código) Ingresa un string S1 y devuelve un valor, si lo puede convertir el código será 0, caso contrario indica la posición del carácter que no pudo convertir. Str(S1, V1, C1) si S1 = "1" "5" "." "7" "3" ! V1 =15.73 y C1 = 0 Str(S1, V1, C1) si S1 = "1" "5" "a" "7" "3" ! V1 = 0 y C1 = 3 Función Upcase: Convierte minúsculas a mayúsculas. Upcase (char) Upcase (a) ! A Upcase (A) ! A Upcase (4) ! 4 136 FUNCIONES PARA MANEJO DE PANTALLA y TECLADO La unidad Crt posee una serie de rutinas de salida a pantalla y otras sin salida a pantalla como Delay, Sound, NoSound, ClrEol Borra todos los caracteres desde la posición actual del cursor hasta el final de la línea sin mover el cursor. ClrScr Borra todos los caracteres de la pantalla y coloca el cursor en la esquina superior izquierda. Si se esta trabajando en una ventana, borrará los caracteres de la ventana y coloca el cursor en la esquina superior izquierda de la ventana. DelLine Borra la línea donde se halla el cursor. Las líneas que se hallan por debajo son desplazadas hacia arriba. GotoXY Coloca el cursor en la coordenada x y. X le indica la columna 1 a 80, e Y el número de línea de 1 a 25. El ángulo superior izquierdo tiene coordenadas (1,1). Si se opera en una ventana, las coordenadas son relativas a la ventana. GotoXY(x, y) x e y son de algún tipo entero. InsLine Inserta una línea vacía donde se halla el cursor. Desplazando las demás una hacia abajo. HighVideo Selecciona caracteres de alta intensidad. LowVideo Selecciona caracteres de baja intensidad. NormalVideo Fija el atributo del texto al valor que tenía inmediatamente antes que el programa fuera ejecutado. TextBackground (Color :Byte) Define el color de fondo. Color toma valores de 0 a 7. TextColor (Color : Byte) Define el color del texto 0 a 15, y 128 (parpadeo). 137 WhereX : byte Devuelve la columna donde se halla el cursor. WhereY : byte Devuelve la línea donde se halla el cursor. Window : (x1, y1, x2, y2 :byte) Define una ventana de texto, dando las coordenadas del vértice superior izquierdo y del vértice inferior derecho. Sound (Frec : word) Emite un sonido de una frecuencia (Frec en herzios) NoSound Interrumpe la emisión de sonido. Delay (ms : word) Detiene la ejecución del programa durante ms milisegundos. ReadKey char Lee un carácter del teclado. El carácter no se visualiza en pantalla. Key Pressed : boolean. Devuelve el valor verdadero si se pulsa una tecla, y falso en caso contrario. SUBRANGO ENUMERADOS CONJUNTOS SUBRANGO: Un tipo subrango se define a partir de un tipo ordinal, especificando dos valores constantes de ese tipo, que a partir de aquí serán el límite inferior y superior del conjunto de datos de esa clase. Un tipo subrango es un por ser un subconjunto de un tipo ordinal es también ordinal, y sus valores se ordenan de la misma forma que están ordenados en el tipo patrón del cual derivan. Ejemplos 1 ..10 este tipo subrango consta de los elementos 1,2,3,4,5,6,7,8,9,10 'F' .. 'I' este subrango consta de los caracteres 'F', 'G', 'H', 'l' 'a' .. 'z' este subrango consta de los caracteres 'a' hasta 'z' '0' .. '9' este subrango consta de los caracteres '0' a '9' 138 Para operar con el tipo subrango, se pueden hacer de dos maneras distintas. • Creando un tipo y luego asignándolo a una variable type • Definiéndolo directamente en la declaración de variables IntervaloEnteros = −100..100; var var Grande : integer; Grande : integer; Reducido : −100..100; Reducido : IntervaloEnteros; El tipo subrango es esencialmente utilizado para dos fines: • Mejorar la legibilidad y la comprensión • Aumentar la fiabilidad de los programas, ya que Pascal detecta si un valor recibe un valor fuera del intervalo declarado. El tipo subrango puede ser leído de teclado como cualquier otra tipo de variable (Read o ReadLn), y presentado a través de pantalla por medio de los procedimientos correspondientes (Write, WriteLn). Compatibilidad de tipos: Los tipos subrangos y los tipos de donde proceden, son compatibles, en el sentido de que cualquier tipo de subrango pertenece al patrón. En el ejemplo anterior es legítima la sentencia: Grande := Reducido; También es legítimo el código de programa ReadLn (Grande); Reducido := Grande; Sin embargo, si al leer con Readln (Grande) se toma para Grande un valor de 500 (fuera del rango IntervaloEnteros), la sentencia de aplicación Reducido := Grande produce un mensaje de error. Como ya se ha dicho un uso importante de los tipos subrangos es detectar ciertos errores de programación o carga de datos. Si se espera que una variable tome valores siempre en un cierto rango, entonces se debe declarar esa variable que adopte el tipo subrango. De este modo, si la variable de tipo subrango toman un valor fuera del rango especificado, se producirá un mensaje de error. 10.3.4. La directiva del compilador R 139 Turbo Pascal no siempre produce un mensaje de error cuando el valor de un tipo subrango está fuera de su rango definido. Sin embargo, puede tener la posibilidad de visualizar dichos mensajes de error, insertando la siguiente línea en el archivo que contenga su programa: ($R+) Esta línea se denomina directiva del compilador. Su valor por defecto (desactivada) es $R−, que no realiza la verificación de los índices del subrango, pero que por el contrario aumenta la velocidad de ejecución. Durante la fase de depuración y puesta a punto de un programa es aconsejable utilizar la directiva $R+, insertándola al principio del programa. ENUMERADOS: Pascal permite otro tipo de dato ordinal denominado tipo enumerado. Estos tipos de datos son definidos por el usuario. Un tipo enumerado se compone de un conjunto de valores referenciados por identificadores. Estos valores constituyen una lista de identifica− dores de constantes que el programador debe indicar en la parte del programa reservada a las declaraciones. Eligiendo adecuadamente nombres significativos para los identificadores se pueden hacer programas más fáciles de leer. Ejemplos type Vehiculos = (avion, barco, tren, automovil, moto, colectivo); Frutas = (frutillas, manzana, pera, naranja, duraznos); Estos tipos pueden ser asignados a variables. Así, por ejemplo, se puede declarar Var Transporte : Vehiculos; Postre : Frutas; Características • Un tipo de dato enumerado es un tipo ordinal cuyo orden se indica por la disposición de los valores en la definición. • El número de orden de cada elemento comienza en 0 para el primer elemento. type Arcoiris = (Verde, Amarillo, Rojo, Azul, Verde); Verde es el elemento número 0. Amarillo es el elemento número 1. Miércoles es el elemento tercero (3). • Las variables de tipo enumerado sólo pueden tomar valores de estos tipos. type Dia (lunes, martes, miercoles, jueves, viernes, sabado, domingo); 140 var Semana : dia; Las sentencias siguientes son válidas: Semana := miercoles; while Semana = jueves do • Los únicos operadores que pueden acompañar a los enumerados son los operadores de relación y de asignación. lunes < martes verdadera jueves < viernes verdadera La expresión Colegio < martes produce un error de sintaxis, ya que los valores mostrados se asocian con dos tipos diferentes. El operador de asignación puede definir el valor de una variable cuyo tipo es un tipo enumerado. Dado que están ordenados los valores de un tipo enumerado, pueden ser comparados con la ayuda de operadores relacionales. Mediante las sentencias selectivas y repetitivas es posible dar gran flexibilidad a su lenguaje. Ejemplo a) Ejemplo b) if hoy < sabado then While hoy <> domingo do Write ('Dia laborable') Ejemplo c) Else For hoy := lunes to viernes do Write ('Fin de semana'); • Los procedimientos de entrada/salida no pueden leer o escribir datos de tipo enumerado. Write (jueves); producirá un error ReadLn (jueves); producirá un error Si se desea obtener una salida se debe utilizar una sentencia Case Case hoy of lunes : Write ("Lunes"); martes : Write ("Martes"); 141 miercoles : Write ("Miércoles"); jueves : Write ("Jueves"); viernes : Write ("Viernes"); sabado : Write ("Sábado") else Write ("Domingo") end; • Un valor no puede figurar en dos tipos enumerados diferentes. • Los tipo enumerado no pueden leerse o escribirse en los archivos de texto. Subrangos de tipo enumerados Se pueden declarar subrangos de tipo enumerado Por ejemplo type mes = (enero, febrero, marzo, abril, mayo, junio, julio, agosto, septiembre, octubre, noviembre, diciembre); primavera = octubre .. diciembre; verano = enero.. marzo; otonio = abril .. junio; invierno = julio .. septiembre; var mensual : mes; vendimia : otonio; vendimia := abril; sentencia válida vendimia := julio; sentencia no válida Funciones Ordinales Los tipos de datos ordinales como ya nos hemos referido, cada valor tiene un único predecesor (excepto el primero) y un único sucesor (excepto el último). Basándose en esta propiedad Pascal incorpora tres funciones predefinidas. Ord, Pred y Succ. Ord 142 Determina la posición relativa de un elemento en la serie, las series no numéricas comienzan por la posición 0 (cero). Por ejemplo: type mes = (enero, febrero, marzo, abril, mayo, junio, julio, agosto, septiembre, octubre, noviembre, diciembre); var {* definición de las variables *} A : Integer; begin {* Comienzo del programa *} ...... A := ord(junio); Writeln ('El ordinal de Junio es: ',A); {* Salida del resultado *} A debe ser de tipo ordinal (byte o integer), el resultado de esta carrera es 5. Pred y Succ Pred devuelve el predecesor del argumento y Succ devuelve el sucesor del argumento. Pred (marzo) ! febrero Succ (marzo) ! abril Pred (enero) ! indefinido Succ (diciembre) ! indefinido Aunque no se vea a simple vista su utilidad estas funciones pueden ser aplicadas para ejemplos como el siguiente. While mensual <= diciembre do begin A := Ord (mensual); mensual := Succ(mensual); end; CONJUNTOS Es otro tipo de datos estructurado con el que se puede operar en Pascal. es el conjunto (set). Una variable de tipo set se denomina conjunto. El concepto es idéntico al matemático, y con este tipo de datos se puede 143 realizar las mismas operaciones que las vistas en matemática (unión, intersección, etc.). En Pascal el conjunto de elementos se representan entre corchetes y separados por comas El máximo número de elementos de un conjunto es 256. Como en el álgebra existe el conjunto vacío, es aquel que no contiene ningún elemento. Declaraciones de tipos de datos conjuntos Para declarar o definir variables tipo conjunto, se deberá definir en función de un tipo base que deberá ser ordinal. Ejemplos type mes = (enero, febrero, marzo, abril, mayo, junio, julio, agosto, septiembre, octubre, noviembre, diciembre); meses = set of mes; digitos = set of byte; (no acepta otro tipo de enteros) caracteres = set of char; var Periodo, Cuatrimestre, Trimestre : meses; Posicion: digitos; El conjunto como cualquier otra variable parte de una condición de vacío. Los elementos pueden ser colocados en los conjuntos utilizando una sentencia de asignación. Periodo := [ ]; Posicion := [3, 5, 6, 8] Cuatrimestre := [abril..julio]; En el primer caso se le asignó será un conjunto vacío, en el segundo de los casos estará compuesto por esos cuatro elementos (3, 5, 6, 8), y en el último de los casos serán los meses (abril, mayo, junio, julio). Dos tipos de conjuntos son compatibles, si tienen los tipos base compatibles. En este caso sus variables representativas se pueden utilizar en sentencias de asignación. Periodo := Trimestre := [ ]; Una variable de tipo conjunto se suele inicializar al conjunto vacío o al conjunto universal. Include A partir de la versión 7 de Pascal. Una de las formas para agregar un elemento a un conjunto es a través del procedimiento include. 144 Exclude También es una modificación de la versión 7. Exclude es un procedimiento para eliminar un elemento a un conjunto. Ejemplos Posicion :=[3, 5, 6, 8]; A := 15; include(Posicion, 22); include(Posicion, A); exclude(Posicion, 22); exclude(Posicion, A); En ambos casos se da como parámetros el conjunto (Posicion) y el elemento a agregar o quitar. El mismo puede darse como valor o como una variable, de esta última forma la variable debe ser de igual tipo que el tipo base del conjunto. La relación In Determina si un elemento pertenece o no a un conjunto. El resultado de evaluar la expresión relacional puede ser true o false. El tipo de datos de elemento y la lista de elementos deben ser compatibles. Ejemplo if A in Posicion then if 15 in Posicion then La variable A y los elementos de Posicion deben ser compatibles. OPERACIONES CON CONJUNTOS En Pascal es posible realizar tres operaciones binarias sobre ellos que son: unión, intersección y diferencia. Unión (+) Las tres operaciones cumplen estrictamente las reglas del álgebra de conjuntos. Por lo tanto la unión de dos conjuntos da como resultante otro conjunto que tiene por elementos a los elementos comunes y no comunes de ambos conjuntos. La unión de conjunto se representa por el símbolo de la suma. Alfa := [3, 5, 8, 14]; Beta := [2, 5, 9, 14, 22]; Capa := Alfa + Beta; ! Capa = [2, 3, 5, 8, 9, 14, 22] La unión es el segundo método para ingresar un elemento a un conjunto 145 Ejemplo ReadLn(A); Posicion := Posicion + [A] Diferencia (−) La diferencia entre dos conjuntos da otro conjunto que tiene por elementos, todos los elementos del primer conjunto que no pertenecen al segundo. Se representa por el símbolo de la diferencia. Capa := Alfa − Beta; ! Capa = [3, 8] Capa := Beta − Alfa; ! Capa = [2, 9, 22] La diferencia es el segundo método para sacar un elemento a un conjunto Ejemplo ReadLn(A); Posicion := Posicion − [A] Intersección (*) La intersección entre dos conjuntos da otro conjunto que tiene por elementos, todos los elementos comunes a ambos conjuntos. Se representa por el símbolo del producto. Capa := Alfa * Beta; ! Capa = [5, 14] COMPARACIÓN DE CONJUNTOS Los conjuntos se pueden comparar entre sí mediante el uso de los operadores relacionales (=, <> , < =, > =). Los operandos deben ser del mismo tipo base. El resultado de la comparación es un valor lógico: true o false. Igualdad de Conjuntos Dos conjuntos son iguales, cuando sus tipos de base son equivalentes, y además todo elemento del primer conjunto pertenece al segundo y todo elemento del segundo conjunto pertenece al primero. Sub y Superconjunto Un conjunto Alfa es subconjunto (esta incluido) de otro Beta, si todo elemento de Alfa pertenece a Beta, pero no todo elemento de Beta pertenece a Alfa. En dicho caso Beta será un superconjunto de Alfa LOS CONJUNTOS COMO PARÁMETROS Los conjuntos se pueden utilizar como parámetros de funciones y procedimientos. En el caso de una función, se debe recordar que la misma devuelve un único valor, por lo tanto su tipo deberá ser un dato simple y no puede ser un conjunto. Ejemplo 146 Realizar un programa que determine los números primos de entre 1 y N elegido por el usuario (menor que 65536). Utilizando la Criba de Eratóstenes. La idea de la criba es la siguiente: Dado una serie ordenada de valores, por ejemplo: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 se prueba cuales son múltiplos de dos y se los elimina de la serie 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 se busca el siguiente de la serie (3) y se elimina los múltiplos de él 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 y así sucesivamente. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 El último valor con que se prueba es con R el cual es la parte entera de la raíz cuadrada del mayor de los valores de la serie. program Criba_de_Eratostenes; {* Ejemplo de conjuntos *} {* Desarrollo del Ing. Fernando J. LAGE *} {* Septiembre 1998*} uses wincrt,windos; {* declaraciones de librerias, para correr bajo Windows *} {* crt,dos;*} {* declaraciones de librerias, para correr bajo DOS *} const Enter = #13; Ln = #13#10; {* Indica un salto de renglón *} type Valores = set of byte; {* Tipo conjunto *} var {* definición de las variables *} Criba : Valores; 147 N, S: Byte; h : char; procedure ingresos; begin {* Comienzo del procedimiento de ingreso de valores *} repeat Write ('Ingrese un valor mayor que 0 y menor o igual 255 '); Readln (N); until (N>0) and (N<255) end; {* Fin del procedimiento ingreso*} function Extremo(A:Byte):Integer; {función que devuelve la parte entera de la raíz cuadrada } var Raiz : Real; begin {* Comienzo de la función Extremo *} Raiz := Sqrt(A); Extremo := Trunc(Raiz); end; {* Fin de la función Extremo *} procedure Llenado(var Alfa : Valores; {* tipo conjunto *} Beta : Byte); var i : Byte; begin {* Comienzo del procedimiento de llenado de valores *} WriteLn (Ln,Ln,'Elementos del conjunto original : '); For i := 1 to Beta do begin Write (i,' '); Alfa := Alfa + [i] {* Agrega un elemento al conjunto *} 148 end end; {* Fin del procedimiento Llenado *} function Multiplo(A,B:Byte):Boolean; {* Función que devuelve si un número es múltiplo o no *} var Mul : Byte; begin {* Comienzo de la función Extremo *} Mul := ((B div A)*A); Multiplo := Mul=B end; {* Fin de la función Extremo *} procedure Primos(var Alfa : Valores; {* tipo conjunto *} Beta, Gama: Byte); var i,j : Byte; begin {* Comienzo del procedimiento de búsqueda de valores no primos*} WriteLn (Ln, Ln, 'Elementos del conjunto original : '); For i := 2 to Gama do If i in Alfa Then For j := i+1 to Beta do If j in Alfa then If Multiplo(i,J) then Alfa := Alfa − [j]; end; {* Fin del procedimiento Primos *} procedure salidas (Beta :Valores); {* tipo conjunto *} var i : byte; begin {* Comienzo del procedimiento de egreso de valores *} 149 Writeln (' ',LN); {* Se deja renglones en blanco *} For i := 1 to N do if i in Beta then begin Write (' ',i); {* Salida del resultado *} exclude (Beta,i) end; Writeln (' son primos'); {* Salida del resultado *} Writeln (' ', Ln, Ln, Ln, Ln); {* Deja cinco renglones en blanco *} writeln ('Presione un tecla para terminar'); {* Salida de mensaje *} read(h); ClrScr; end; {* Fin del procedimiento salidas*} begin {* Comienzo del programa *} {* Se limpia la pantalla *} ClrScr; {* Declaro al conjuto vacio *} Criba := []; {* Ingreso del extremo superior *} Ingresos; {* Llenado del conjunto *} Llenado(Criba, N); {* Cálculo de el extremo de búsqueda *} S := Extremo(N); {* Obtención de los números primos *} Primos(Criba,N,S); 150 {* Salida de resultados *} Salidas(Criba); end. {* Fin del programa *} ORDENACIÓN, BÚSQUEDA E INTERCALACIÓN Los procesos que consumen más tiempo durante la operación de un ordenador, son ordenación, búsqueda e intercalación. La ordenación se clasifica en interna (matrices), y externa (archivos). Las técnicas ordenación, mezcla e intercalación deben ser dominados por el alumno. ORDENACIÓN Es un proceso para clasificar los elementos de un array en un orden particular. Por ejemplo, clasificar un conjunto de números en orden creciente o una lista de nombres por orden alfabético. La clasificación es una operación tan frecuente en programas de computadora que una gran cantidad de algoritmos han sido diseñados para clasificar listas de elementos con eficacia y rapidez. La elección de un determinado algoritmo depende del tamaño del vector o array a clasificar, el tipo de datos y la cantidad de memoria disponible. La ordenación o clasificación es el proceso de organizar datos en algún orden o secuencia específica tal como creciente o decreciente para datos numéricos o alfabéticamente para datos de caracteres. Los métodos de ordenación se dividen en dos categorías: • ordenación interna (vectores, tablas, matrices) • ordenación externa (archivos) La ordenación de arrays se maneja en la memoria RAM, por lo tanto se hace a gran velocidad y acceso aleatorio. La ordenación de archivos se suele hacer sobre soportes de almacenamiento externo, discos, cintas, etc.. Estos dispositivos son más lentos en las operaciones de entrada− salida, pero pueden contener mayor cantidad de información. Los métodos de ordenación que desarrollaremos podrán ser explicados a vectores, pueden ser extendidos a matrices o tablas, ya que toda ordenación de tabla o matriz se basa en la ordenación de una fila o columna, que no es otra cosa que un vector. Los más populares son: • Intercambio • Selección • Inserción MÉTODO DE INTERCAMBIO O DE BURBUJEO El algoritmo de clasificación de intercambio o de la burbuja, debería ser denominado de decantación y se basa en el principio de comparar pares de elementos adyacentes e intercambiarlos entre sí hasta que estén todos ordenados. Partamos que poseemos el siguiente vector y se desea ordenar en forma ascendente(el menor en la posición V(1) y el último en V(9)): V(1) 64 151 V(2) V(3) V(4) V(5) V(6) V(7) V(8) V(9) 28 13 23 79 54 25 18 41 Los pasos a dar son: • Comparar V(1) y V(2). Si están en orden, se mantienen como están; caso contrario se intercambian entre sí. • A continuación se comparan los elementos 2 y 3; de nuevo si no están en orden, se intercambian sino no. • Y así sucesivamente, hasta que cada elemento del vector ha sido comparado con sus elementos adyacentes y se han realizado los intercambios necesarios. El método se expresa así: Pseudicódigo desde I = 1 hasta 8 hacer si elemento (I) > elemento (I + 1) entonces intercambiar elementos (I, I+ 1) fin si fin desde N−S I = 1 hasta 8 elemento (I) > elemento (I + 1) intercambiar elementos (I, I+ 1) Intercambiar es un procedimiento para trocar los valores de dos elementos A(I), A(I + l), es una acción compuesta que contiene las siguientes acciones: AUX ! A(I) A(I) ! A(I + 1) A(I + 1) ! AUX El valor más grande rápidamente baja al último lugar, mientras el más pequeño sube posición a posición hacia el comienzo de la lista al igual que las burbujas de aire en una botella de gaseosa. Tras realizar un recorrido completo por todo el vector, el elemento más grande habrá llegado a ocupar la última posición. En el segundo recorrido, el segundo elemento llegará a la penúltima, y así sucesivamente. Ahora veremos como funciona esta idea en el ejemplo anterior. Número de paso El pseudo código de este algoritmo de ordenación, es el que desarrollamos en los siguientes pasos Pseudocódigo algoritmo burbuja1 152 lNlClO para I ! 1 hasta N − 1 hacer para J ! 1 hasta N − 1 hacer si X(J) > X(J + 1) entonces {intercambiar} AUX ! X(J) X(J) ! X(J + 1) X(J+ 1) ! AUX fin si fin para fin para El diagrama N−S del algoritmo de burbuja1: I ! 1 hasta N − 1 J ! 1 hasta N − 1 X(J) > X(J + 1) {intercambiar} AUX ! X(J) X(J) ! X(J + 1) X(J+ 1) ! AUX Si se efectúa n−1 veces la operación sobre un vector de n valores se tiene ordenada el vector. Cada operación requiere n−1 comprobaciones o test y como máximo n−1 intercambios. La ordenación total exigirá un máximo de (n − 1) *(n − l) = (n − 1)2 intercambios de elementos. Las sucesivos situaciones de los elementos del vector se ve en el listado anterior. Si observamos en detalle notamos, que en le segundo paso no es necesario llegar a la última posición del vector ya que en el se encuentra el mayor valor, en el tercer paso los dos últimos valores ya están ordenados. Y así sucesivamente. Por lo cual en esta ordenación hay un máximo de cambios igual: (n − 1) + (n − 2) + (n − 3) + ... + 3 + 2 + 1 = n * (n − 1) / 2 intercambios de elementos. Para optimizar este algoritmo su pseudocódigo deberá ser el siguiente. Pseudocódigo algoritmo burbuja2 INICIO para I ! 1 hasta N − 1 hacer 153 para J ! 1 hasta N − I hacer si X(J) > X(J + 1) entonces {intercambiar} AUX ! X(J) X(J) ! X(J + 1) X(J+ 1) ! AUX fin si fin para fin para Como se puede notar el único cambio que sufrió el pseudocódigo es N−I en lugar de N−1 en el segundo para, este cambio no alterará el diseño del diagrama N−S por lo cual no lo repetiremos. Segunda mejora Esta segunda mejora toma el caso cuando aun no cumplidos todos los ciclos el vector ya se encuentra ordenado. En este caso es posible que estemos realizando ciclos innecesarios, los que consumen tiempo de procesador sin beneficio. Para evitar este problema lo que se hará es colocar una bandea. Su función es que cuando en un ciclo no se haga ningún cambio (lo que implica que el vector ya esta ordenado), la bandera indique esto y se detenga el proceso. Pseudocódigo algoritmo burbuja3 lNlClO Bandera ! F (falso) I!1 mientra Bandera = F y I < N hacer Bandera ! V (verdadero) para J ! 1 hasta N − I hacer si X(J) > X(J + 1) entonces {intercambiar} AUX ! X(J) X(J) ! X(J + 1) X(J+ 1) ! AUX Bandera ! F fin si 154 Incrementa I fin para fin para El diagrama N−S del algoritmo de burbuja3: Bandera ! F (falso) I ! 1 Bandera = F y I < N Bandera ! V (verdadero) J ! 1 hasta N − I X(J) > X(J + 1) {intercambiar} AUX ! X(J) X(J) ! X(J + 1) X(J+ 1) ! AUX Bandera ! F Incremente I Código en Pascal del procedimiento para el algoritmo de burbuja3: program Ordenamiento_Burbuja; {* Ejemplo del ordenamiento por el método de burbujeo *} {* Burbujeo mejorado con bandera *} {* Archivo BurbujaB.Pas *} {* Desarrollo del Ing. Fernando J. LAGE *} {* Octubre 1998*} uses wincrt,windos; {* declaraciones de librerias, para correr bajo Windows *} {* crt,dos;*} {* declaraciones de librerias, para correr bajo DOS *} const Enter = #13; Ln = #13#10; type {* Definición de tipos *} Numeros = 1..3200; Vector = array[1..256]of Numeros; 155 Var Dato : Vector; Filas : Byte; procedure IntercambioE (var Capa, Omega : Numeros); {* IntercambioE produce el intercambio de dos valores del vector *} var Aux : Numeros; {* elemento auxiliar *} begin {* Comienzo del procedimiento IntercambioE *} Aux := Capa; Capa := Omega; Omega := Aux End; {* Fin del procedimiento IntercambioE*} procedure BurbujaB (var Alfa: Vector; Elementos: integer); {* BurbujaB produce el ordenamiento usando el método de la burbuja *} {* Optimizado por el uso de una Bandera *} var Bandera : Boolean; Iteracion, Contador : Integer; {* Iteracion reemplaza I del pseudocódigo *} {* Contador a J del pseudocódigo *} begin {* Comienzo del procedimiento BurbujaB *} Bandera := False; Iteracion := 1; While (Bandera = False) and (Iteracion < Elementos) do begin Bandera := True; For Contador := 1 to Elementos − Iteracion do 156 If Alfa[Contador] > Alfa[Contador + 1] then Begin Intercanbio (Alfa[Contador],Alfa[Contador + 1]); Bandera := False End; {* Fin del If*} Inc(Iteración) End {* Fin del While*} End; {* Fin del procedimiento BurbujaB*} begin {* Comienzo del programa *} {* Se limpia la pantalla *} ClrScr; ........................ {* Llamado al procedimientos BurbujaB *} BurbujaB(Dato,Filas); ........................ end. {* Fin del programa *} MÉTODO POR INSERCIÓN I Este método consiste en insertar un elemento en el vector en una parte ya ordenada de este vector y comenzar de nuevo con los elementos restantes. Por ser utilizado generalmente por los jugadores de cartas se le conoce también por el nombre de método de la baraja. Este método, para usarlo en forma optima, debe aplicarse a medida que se carga el vector. Así, por ejemplo, supongamos el caso del ejemplo anterior. Inserción mientras se carga el vector 157