Subido por jgonzalezlopez047

Informatica libro

Anuncio
CONTENIDOS
PRÓLOGO.............................................................................................. VIII
1. CONCEPTO DE COMPUTADOR.........................................................1
1.1. UNA PRIMERA APROXIMACIÓN AL COMPUTADOR ........................1
1.1.1 OPERACIONES BÁSICAS DEL PROCESADO DE DATOS ......................2
1.1.2 ALGORITMOS Y PROGRAMAS ..................................................................3
1.2. ANTECEDENTES HISTÓRICOS .................................................................5
1.3. ORGANIZACIÓN DE UN COMPUTADOR................................................9
1.3.1 LA ARQUITECTURA DE VON NEUMANN ...............................................9
1.3.2 UNIDADES FUNCIONALES.......................................................................10
1.4. EL CONCEPTO DE PROGRAMA ALMACENADO ...............................16
1.4.1 TIPOS DE INSTRUCCIONES......................................................................17
1.4.2 LENGUAJE MÁQUINA Y LENGUAJE ENSAMBLADOR.......................18
1.4.3 EJECUCIÓN DE UN PROGRAMA .............................................................20
1.5. CONCEPTO ACTUAL DEL COMPUTADOR..........................................24
1.5.1 DEFINICIÓN ACTUAL................................................................................24
1.5.2 PARÁMETROS BÁSICOS DE LA MÁQUINA ..........................................25
1.6. DEL COMPUTADOR A LA PROGRAMACIÓN .....................................26
1.6.1 LOS DATOS..................................................................................................27
1.6.2 LENGUAJES DE PROGRAMACIÓN DE ALTO NIVEL...........................27
1.6.3 ELEMENTOS BÁSICOS DE UN LENGUAJE DE ALTO NIVEL .............31
1.6.4 ORGANIZACIÓN DE UN PROGRAMA.....................................................35
1.6.5 TRADUCCIÓN DE PROGRAMAS..............................................................36
1.7. SISTEMA OPERATIVO Y PROGRAMAS DEL SISTEMA....................37
1.8. TIPOS DE COMPUTADORES ....................................................................39
1.9. COMUNICACIÓN DE DATOS Y REDES .................................................40
1.9.1 TRANSMISIÓN DE DATOS DENTRO DEL COMPUTADOR .................40
1.9.2 COMUNICACIÓN DE DATOS A LARGA DISTANCIA...........................42
1.9.3 REDES DE ORDENADORES ......................................................................43
III
IV
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
2. SOPORTE LÓGICO DE UN COMPUTADOR ................................. 45
2.1. CONCEPTO DE SOPORTE LÓGICO........................................................45
2.2. AYUDAS PARA LA PROGRAMACIÓN....................................................47
2.2.1 TRADUCTORES ...........................................................................................47
2.2.2 TIPOS DE LENGUAJES DE ALTO NIVEL ................................................52
2.2.3 UTILIDADES Y FASES EN LA EJECUCIÓN DE UN PROGRAMA........53
2.3. PROGRAMA DE ARRANQUE....................................................................55
2.4. SISTEMAS OPERATIVOS (SO)..................................................................57
2.4.1 FUNCIONES DE LOS SISTEMAS OPERATIVOS.....................................57
2.4.2 LA ESTRUCTURA DE UN SISTEMA OPERATIVO TÍPICO ...................58
2.4.3 ADMINISTRACIÓN DEL HARDWARE.....................................................60
2.4.4 ADMINISTRACIÓN DEL SISTEMA DE ARCHIVOS...............................62
2.4.5 APOYO A LA EJECUCIÓN DE PROGRAMAS DE APLICACIÓN ..........63
2.4.6 MÓDULOS PARA LA GESTIÓN DE REDES ............................................64
2.4.7 EJEMPLOS DE SISTEMAS OPERATIVOS................................................64
2.5. SOPORTE LÓGICO DE LAS REDES DE COMPUTADORES ..............72
2.5.1 SOPORTE LÓGICO BÁSICO.......................................................................72
2.5.2 RELACIONES EN UNA RED ......................................................................77
2.5.3 PROGRAMAS DE APLICACIONES DE LAS COMUNICACIONES .......78
3. ALGORITMOS Y PROGRAMAS....................................................... 81
3.1. CONCEPTO DE ALGORITMO ..................................................................81
3.2. LA RESOLUCIÓN DE PROBLEMAS Y EL USO DEL ORDENADOR 82
3.2.1 ANÁLISIS DEL PROBLEMA ......................................................................83
3.2.2 DISEÑO DEL ALGORITMO........................................................................84
3.2.3 PROGRAMACIÓN DEL ALGORITMO ......................................................88
3.3. REPRESENTACIÓN DE ALGORITMOS .................................................89
3.3.1 PSEUDOCODIGO .........................................................................................89
3.3.2 ORGANIGRAMAS .......................................................................................90
3.4. ESTRUCTURAS DE CONTROL.................................................................91
3.4.1 ESTRUCTURAS SECUENCIALES .............................................................92
3.4.2 ESTRUCTURAS SELECTIVAS...................................................................93
3.4.3 ESTRUCTURAS REPETITIVAS .................................................................99
3.5. PROGRAMACIÓN MODULAR................................................................111
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
V
3.5.1 FUNCIONES ...............................................................................................112
3.5.2 PROCEDIMIENTOS O SUBRUTINAS .....................................................115
3.5.3 ÁMBITO DE LAS VARIABLES................................................................117
3.5.4 PASO DE PARÁMETROS .........................................................................120
3.6. CONCEPTO DE PROGRAMACIÓN ESTRUCTURADA .....................126
3.7. RECURSIVIDAD.........................................................................................128
3.8. DESARROLLO Y GENERACIÓN DEL SOFTWARE...........................131
3.8.1 INGENIERÍA DEL SOFTWARE ...............................................................132
3.8.2 CICLO DE VIDA DEL SOFTWARE .........................................................133
4. ARITMÉTICA Y REPRESENTACIÓN DE LA INFORMACIÓN
EN EL COMPUTADOR ..........................................................................137
4.1. SISTEMAS DE NUMERACIÓN EN INFORMÁTICA...........................137
4.1.1 DEFINICIÓN DEL SISTEMA BINARIO...................................................139
4.1.2 TRANSFORMACIONES ENTRE BASES BINARIA Y DECIMAL ........139
4.1.3 CÓDIGOS INTERMEDIOS ........................................................................141
4.2. OPERACIONES ARITMÉTICAS Y LÓGICAS......................................143
4.2.1 OPERACIONES ARITMÉTICAS CON NÚMEROS BINARIOS.............143
4.2.2 VALORES BOOLEANOS Y OPERACIONES LÓGICAS........................144
4.2.3 PUERTAS LÓGICAS..................................................................................145
4.2.4 ARITMÉTICA CON PUERTAS LÓGICAS...............................................147
4.3. REPRESENTACIÓN DE INFORMACIÓN EN EL COMPUTADOR ..150
4.3.1 LA CODIFICACIÓN EN INFORMÁTICA................................................151
4.3.2 REPRESENTACIÓN INTERNA DE DATOS............................................154
4.3.3 REPRESENTACIÓN INTERNA DE PROGRAMAS ................................166
4.4. EL CONCEPTO DE TIPO DE DATO.......................................................167
5. ESTRUCTURAS DE DATOS .............................................................171
5.1. EL CONCEPTO DE DATOS ESTRUCTURADOS. ................................171
5.2. TIPOS DE DATOS ESTRUCTURADOS ..................................................172
5.3. ESTRUCTURAS DE DATOS CONTIGUAS............................................173
5.3.1 CADENAS...................................................................................................173
5.3.2 ARRAYS......................................................................................................175
5.3.3 REGISTROS ................................................................................................187
VI
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
5.4. ESTRUCTURAS DINÁMICAS Y PUNTEROS .......................................187
5.5. ESTRUCTURAS LINEALES .....................................................................188
5.5.1 LISTAS ENLAZADAS................................................................................189
5.5.2 VECTORES VS LISTAS ENLAZADAS....................................................198
5.5.3 PILAS...........................................................................................................198
5.5.4 COLAS.........................................................................................................201
5.6. ESTRUCTURAS NO LINEALES (ÁRBOLES)........................................202
5.6.1 ÁRBOLES BINARIOS ................................................................................203
5.6.2 ÁRBOL BINARIO DE BÚSQUEDA ..........................................................206
6. ARCHIVOS Y BASES DE DATOS ................................................... 213
6.1. ARCHIVOS: DEFINICIONES Y CONCEPTOS .....................................213
6.2. SOPORTE Y ACCESO A LOS ARCHIVOS ............................................216
6.3. EL SISTEMA OPERATIVO Y LA GESTIÓN DE ARCHIVOS ............218
6.4. ORGANIZACIÓN DE ARCHIVOS...........................................................218
6.5. OPERACIONES SOBRE ARCHIVOS......................................................220
6.5.1 APERTURA Y CIERRE DE UN ARCHIVO..............................................221
6.5.2 LECTURA Y ESCRITURA EN UN ARCHIVO ........................................222
6.6. PROCESAMIENTO DE ARCHIVOS .......................................................223
6.6.1 PROCESAMIENTO DE ARCHIVOS SECUENCIALES ..........................224
6.6.2 PROCESAMIENTO DE FICHEROS SECUENCIALES INDEXADOS ...230
6.6.3 PROCESAMIENTO DE FICHEROS DE ORGANIZACIÓN DIRECTA ..230
6.7. TIPOS DE ARCHIVOS ...............................................................................234
6.8. BASES DE DATOS ......................................................................................237
6.8.1 CONCEPTO DE BASE DE DATOS...........................................................240
6.8.2 ESTRUCTURA GENERAL DE UNA BASE DE DATOS.........................241
6.8.3 TIPOS DE BASES DE DATOS...................................................................242
6.8.4 SISTEMA DE GESTIÓN DE LA BASE DE DATOS ................................244
7. ALGORITMOS Y SU COMPLEJIDAD ........................................... 245
7.1. MEDIDA DE LA EFICIENCIA Y DE LA COMPLEJIDAD
ALGORITMICA .................................................................................................245
7.1.1 ORDEN DE COMPLEJIDAD .....................................................................247
7.1.2 ANÁLISIS DE LOS ALGORITMOS DE BÚSQUEDA .............................249
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
VII
7.2. ALGORITMOS DE ORDENACIÓN Y SU COMPLEJIDAD ................250
7.2.1 ORDENACIÓN POR INSERCIÓN ............................................................250
7.2.2 ORDENACIÓN POR INTERCAMBIO ......................................................252
7.2.3 ALGORITMO DE SHELL ..........................................................................256
7.2.4 ALGORITMO DE ORDENACIÓN RÁPIDA (“QUICKSORT”) ..............258
7.3. EVALUACIÓN DE UN POLINOMIO ......................................................267
7.3.1 EVALUACIÓN DIRECTA .........................................................................267
7.3.2 ALGORITMO DE HORNER ......................................................................267
7.3.3 MÉTODO DEL ÁRBOL .............................................................................268
7.4. ALGORITMOS PARA LA BÚSQUEDA DE CADENAS DE
CARACTERES ...................................................................................................272
7.4.1 ALGORITMO DE COMPARACIÓN .........................................................272
7.4.2 ALGORITMO DE BOYER-MOORE .........................................................274
7.5. NOTAS FINALES SOBRE COMPLEJIDAD...........................................276
7.5.1 ALGORITMOS NO-DETERMINISTAS....................................................276
7.5.2 PROBLEMAS DE CLASE P Y NP.............................................................277
7.5.3 INTRODUCCION A LAS MAQUINAS DE TURING Y A LOS
PROBLEMAS ALGORITMICAMENTE IRRESOLUBLES ..............................278
ANEXO: SOPORTE FÍSICO DE UN COMPUTADOR......................285
ARQUITECTURA DE COMPUTADORES ....................................................285
PERIFÉRICOS DE LOS COMPUTADORES.................................................294
REDES Y CONEXIONES ENTRE COMPUTADORES................................308
BIBLIOGRAFÍA ......................................................................................317
PRÓLOGO
Con la puesta en marcha de los nuevos planes de estudios, en la
Universidad española, han aparecido nuevas materias incorporadas a los curricula
universitarios, que en los viejos planes de estudio no existían, o su contenido
quedaba difuminado en el temario de otras asignaturas. Entre estas materias hay
que situar el tema de los Fundamentos de la Informática y la Programación, que
bajo distintos sinónimos, aparece en un gran número de Planes de Estudios, bien
sea en forma de materia troncal, obligatoria u optativa. Este carácter de nueva
materia, hace que, aunque en el mercado, exista una gran cantidad de excelentes
textos, que cubren este material introductorio, el curso dirigido al estudiante de
primer ciclo de los nuevos planes de estudio, esté por desarrollar, en parte, como
tal material de apoyo a la tarea docente.
Posiblemente, la constatación de esta carencia resulte sorprendente al
lector acostumbrado a visitar los poblados anaqueles de la sección de informática
de nuestras librerías; el libro de informática aparentemente está en plena fase de
explosión; pero un análisis más cuidadoso indica que la mayor parte de nuevos
títulos, se centran mucho más en la explicación más o menos profunda de los
diversos paquetes o sistemas que cada temporada causan furor en el mundo del
usuario del PC, que en el desarrollo metódico y detallado que toda disciplina
científico-técnica merece. Nada más alejado de nuestra intención, criticar tal
explosión de información en manos del público, al contrario, nos sentimos
orgullosos de que nuestra especialidad profesional, sea la más abierta de todas las
ramas científicas a la hora de transferir sus últimos conocimientos, para que sean
utilizados por toda la ciudadanía, sin embargo queremos recordar que muchos
productos informáticos, en su época considerados como sinónimos de alta
especialidad, han pasado al olvido, barridos por otros que los superaban; con ellos
muchos conocimientos y esfuerzos de aprendizaje han resultado obsoletos, ya que
muchas veces, sólo se dominaba un determinado procedimiento, no una ciencia, ni
siquiera una tecnología. Saltar de un paquete informático a otro, o de un procesador
a otro, tiene poco sentido y mucho riesgo, sin una mínima, aunque sólida cultura
informática. De ayudar a transferir cultura y conocimientos se trata y ésta es una de
nuestras misiones, desde la universidad.
A la hora de redactar el texto hemos pensado en dos tipos de posibles
lectores. Por un lado el estudiante de Ingeniería Informática y por otro el estudiante
VIII
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
IX
de otras titulaciones científicas. El primero, en sus primeras incursiones en su
nueva carrera, tiende a identificar el aprendizaje de la informática, con el dominio
de un lenguaje de programación y un conocimiento más o menos profundo de la
estructura interna de la máquina. El segundo, sin embargo, aspira a que le enseñen
el manejo del ordenador y la utilización de algunos paquetes de software que le
vayan a resultar útiles para su futura profesión, además de alguna introducción
elemental a la programación. Para ambos en este texto, hay un mensaje común: la
Informática es mucho más que una serie de paradigmas ó filosofías de la
programación y hay que aceptar que con su advenimiento, al árbol luliano de la
ciencia, le ha brotado una nueva rama que con una cierta influencia anglosajona
venimos llamando Ciencias de la Computación y con este nuevo bagaje tiene que
iniciar su formación universitaria.
Desde el punto de vista del estudiante de Informática, la filosofía de este
texto esta en la línea de proporcionar un texto introductorio, que adapte los
conocimientos de un estudiante español de primer ciclo, a las ideas desarrolladas
por el Comité que elaboro el “ACM/IEEE Joint Curriculum”, que constituye uno
de los esfuerzos más saludables que existen, de enlazar las necesidades
profesionales, con los contenidos académicos. Para el universitario que ha elegido
otra rama científica, este libro aspira a proporcionarle una cultura informática
básica, que le permita por un lado poderla aplicar en su respectivo campo de
conocimiento y por otro, al conocer sus principios básicos, poder hacer frente a las
posibilidades que nos ofrecen los ordenadores, conociendo tanto sus fantásticas
potencialidades, como sus limitaciones.
Para tratar de cumplir, estos objetivos un tanto generalistas, apresurémonos
a indicar, que este libro ha sido escrito, intentando abstraernos de cualquier
lenguaje de programación concreto y en la medida de lo posible de cualquier
máquina o sistema operativo de los que utilizamos diariamente. Esta tarea ha sido
especialmente difícil, pues los autores tienen sus propias preferencias y
profesionalmente están marcados, como todo el mundo, por sus experiencias
personales. Esperamos que esta profilaxis haya sido fructífera, ya que estamos
convencidos de que la única manera de introducir a un estudiante en la Informática,
es tratando de separar constantemente lo que hay de contingente, en materia de
útiles informáticos en el mercado en cada momento y lo que hay de nuevo para
permanecer, por un cierto tiempo, en el acervo de la cultura informática. A pesar de
lo anterior, es evidente que la programación debe probarse y experimentarse, mas
allá de su cuerpo teórico, y para ello es necesario, que el estudiante maneje una
máquina concreta, un sistema operativo determinado, adquiera ciertas habilidades
de programación con un lenguaje de alto nivel razonablemente actual y maneje los
últimos paquetes de software que le resulten útiles; esto tendrá lugar en el
Laboratorio. Por ello no queda otro remedio que tomar decisiones en la
planificación del curso; así el estudiante podrá trabajar sobre una terminal de un
gran ordenador o moverse en al campo de la informática de PC o de Apple,
X
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
manejar DOS, UNIX u otro sistema, aprender C, Pascal, Fortran, Modula ó C++.
Sin embargo, el libro si ha conseguido sus objetivos debe ser igual de útil para
cualquiera que sea la decisión tomada.
SUGERENCIAS PARA USAR ESTE LIBRO
Este texto se ha elaborado pensando en un curso introductorio de nivel de primer
ciclo, para estudiantes de Ciencias o Ingeniería. El material que aquí se presenta ,
asume que el estudiante va a recibir en paralelo un curso de carácter práctico, en el
que se le explicará y ejercitará en un lenguaje de programación de alto nivel. Ello
supone que en el laboratorio y frente al ordenador, el interesado acabará
habituándose a una cierta máquina, a un sistema operativo, a un lenguaje y
seguramente a un entorno de programación, que debe ser el complemento práctico
de los conceptos aquí desarrollados.
El material que aquí presentamos está dividido en 7 Capítulos y un anexo. El
Capítulo 1 trata de recoger los conceptos que se consideran imprescindibles para
poder enfrentarse a un ordenador y al proceso de programación. En nuestra opinión
todo el contenido allí desarrollado tiene la vitola de fundamental y en consecuencia
estos conceptos no deberían ser orillados en un curso de introducción.
El Capítulo 2 dedicado al Soporte Lógico de la máquina puede considerarse como
una profundización de los aspectos relacionados con el software, vistos en el
Capítulo anterior; por tanto este capítulo puede evitarse si el número de créditos
asignados al curso no fuera suficiente. Sin embargo el capítulo puede ser de
utilidad como referencia durante las clases prácticas donde constantemente se
usarán y practicarán módulos pertenecientes a este soporte lógico.
El Capítulo 4 está dedicado a la representación interna de información en el
ordenador, éste es un tópico que debe ser tratado en cualquier curso, sin embargo la
profundidad con la que ello se haga, dependerá de la orientación que se pretenda
dar en cada caso. En consecuencia queda al criterio del profesor la selección del
material que considere oportuno para sus objetivos finales.
Los Capítulos 3 (Algoritmos y Programas) y Capítulo 5 (Estructuras de Datos)
constituyen el núcleo de un curso de Introducción a la Programación. De hecho, el
texto se mueve constantemente bajo el principio de Programación = Algoritmo +
Estructuras de Datos y de esta forma se ha estructurado el material con la intención
que el estudiante termine su lectura habiendo conseguido una cierta destreza en las
técnicas y metodología de la programación estructurada. Es posible que se
considere que algunas de las estructuras descritas superen los niveles de algunos
cursos, especialmente en lo que se refiere a las estructuras dinámicas. No existe
ninguna dificultad en evitar este material, en una primera lectura, aunque
consideramos que los recursos que el uso de punteros proporciona no deben ser
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
XI
ocultados al estudiante teniendo en cuenta las posibilidades de los modernos
lenguajes de programación.
El Capítulo 6 complementa las estructuras de datos, analizando la forma como se
organiza y maneja la información que reside en un periférico de almacenamiento.
De nuevo el material aquí presentado, puede ser objeto de una determinada
selección en función de los objetivos y del tiempo con que se cuente.
El Capítulo 7 trata de culminar el curso, desde la óptica de la complejidad
algorítmica y de la comparación de algoritmos. Este es un capítulo que pasa de los
temas más prácticos, como la ordenación, a las cuestiones más teóricas como las
clases de algoritmos y la máquina de Turing en un intento de abrir a los ojos del
estudiante, las cuestiones computables que existen más allá de la capacidad del
computador.
Ante el hecho de que, por un lado, estaba fuera de lugar en este libro un capítulo
que profundizara en cuestiones de hardware y que por otro, se tiene que tener una
cierta información acerca de dispositivos, redes, etc, hemos decidido incluir un
Anexo con los términos más significativos del Soporte Físico del ordenador. Este
Anexo trata de ser más que un simple glosario, de forma que, cada término
desarrollado se pueda comprender con suficiente amplitud.
Una nota final, es que en ningún caso el libro sustituye a curso alguno, de hecho,
no se ha puesto especial énfasis en los ejemplos, ni se han incluido ejercicios
(esperamos que se disculpen estas carencias); ya que éstas son decisiones que
dependen de cada profesor y de cada curso.
AGRADECIMIENTOS
Este libro no sería pensable sin la existencia del LISITT (Laboratorio Integrado de
Sistemas Inteligentes y Tecnologías de la información en Transporte) y de la Unitat
Docent d’Informàtica del Departament d’Informàtica i Electrònica de la Universitat
de València. Sin el especial espíritu de estos hombres y mujeres, muchos proyectos
no habrían visto la luz y este libro es sólo un ejemplo más. Hay que dar las gracias
tanto a los que han puesto su pluma cuando ha sido necesaria como a los que han
expresado sus críticas o comentarios. La relación sería excesivamente extensa y
esperamos que los amigos nos disculpen el que sólo nombremos a la única persona
que ha trabajado todo el libro y seguramente nunca lo tendrá que explicar desde
una pizarra: Cristina Roda, un ejemplo de lo que una mujer puede hacer con un
procesador de textos y un corazón de no sabemos cuántos Megas.
XII
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Valencia, Septiembre de 1995
LOS AUTORES
CAPÍTULO 1
CONCEPTO DE COMPUTADOR
La Informática, definida por la Real Academia como el conjunto de conocimientos
científicos y técnicos que hacen posible el tratamiento automático de la
información por medio de computadoras, requiere previamente contestar a
determinadas preguntas sobre el funcionamiento de estas máquinas.
En este primer capítulo se pretende dar los conceptos mínimos e imprescindibles,
para que el lector tenga una visión panorámica del contenido del libro, de forma
que cuando se adentre en los próximos capítulos sepa enmarcar el sentido e
importancia de cada uno de ellos.
3030" WPC"RTKOGTC"CRTQZKOCEKłP"CN"EQORWVCFQT
De forma genérica y en una primera aproximación, un computador puede
definirse como una “máquina digital, electrónica, programable para el
procesamiento de información”. Notemos por tanto, que el computador1, en
cuanto a “máquina” se refiere, está en la categoría de los molinos de vientos,
telares, etc., que pueden funcionar correcta e incorrectamente. “Digital” significa
que estas máquinas trabajan almacenando información, en forma de códigos, que
representan las letras o dígitos de los números. “Electrónica” sugiere que está
construida usando componentes electrónicos de estado sólido, conocidos por
circuitos integrados. Programable significa que admite la posibilidad de ejecutar
instrucciones a demanda de una sucesión de órdenes preestablecidas. Un ejemplo
de máquina programable, son las lavadoras automáticas actuales ó los más
tradicionales carrillones.
1
Al definir computador como un tipo de máquina (femenino), podríamos utilizar la palabra
computadora, como se hace en Sudamérica. Por las funcionalidades de la máquina, el término “computador/a”, que
proviene del latín computare, debería ser preferido al más popular de ordenador (ordenar es sólo una de las
múltiples funciones que la máquina es capaz de llevar a cabo). En este libro usaremos libremente cualquiera de
estos tres sinónimos.
1
2
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
El concepto “procesamiento de información”, es menos obvio. Información es
un término general que abarca hechos y representaciones que pueden estar o no
relacionadas entre sí. A dichas entidades codificadas, en condiciones de ser
introducidas en el computador, los llamaremos datos que pueden usarse de forma
individual o como grandes conjuntos, dotados de una estructura (por ejemplo una
matriz); de hecho los datos son significativos en sí y en relación con la estructura a
la que pertenecen (un número de teléfono no es de gran utilidad si no se sabe a
quien pertenece).
La unidad más elemental de información es una variable binaria, conocida como
BIT (contracción de las palabras BInary y digiT), que toma el valor 0 ó 1. El bit
representa la mínima información posible, ya que corresponde a la ocurrencia de un
suceso, de entre dos posibilidades distintas. Por ejemplo, un bit es la cantidad de
información correspondiente a un mensaje anunciando si determinado caballo ha
ganado (1) o perdido (0) una carrera.
30303" QRGTCEKQPGU"DıUKECU"FGN"RTQEGUCFQ"FG"FCVQU
Procesar los datos, consiste en someterlos a un conjunto de operaciones
tales como ordenación, selección, ejecución de cálculos, etc. de forma que nos
permita extraer conclusiones de los datos que manipulamos. Por tanto, procesar
información es transformar datos primarios en información organizada,
significativa y útil, que a su vez está compuesta de datos (Ver Figura 1.1.)
Gpvtcfc
(Datos)
Rtqegucfqt
Fig. 1.1.
Ucnkfc
(Información)
Proceso de datos
En el concepto de procesar, entran ejemplos tan diversos como la obtención de las
raíces de un polinomio a partir de los datos de los valores de sus coeficientes, o el
control de un cohete en vuelo, a partir de todos los datos físicos del sistema.
Nótese, que el concepto de procesador es más amplio que el de computador, ya que
existen procesadores que no son computadores: Un termostato a partir del dato de
la temperatura tiene como salida el control del aire acondicionado y nuestro propio
sistema cardiovascular, a partir de los datos sensoriales reacciona adaptándose a las
distintas circunstancias.
De acuerdo con lo anterior, para procesar datos, el computador debe ser capaz de
realizar ciertos tipos de operaciones:
CONCEPTO DE COMPUTADOR
3
• Entrada de datos: Suministrar información al computador desde su entorno
exterior (ej. pulsar el teclado, o leer un código de barras).
• Salida de datos: Obtener información de un computador. (ej. visualizar los
resultados en una pantalla o impresora).
• Almacenamiento: Hacer una copia permanente de la información con el
objetivo, que el computador pueda emplearla de nuevo (ej. copiar en cintas y
discos magnéticos).
• Recuperación: Leer de nuevo la información almacenada (en cinta o discos
magnéticos).
• Transmisión: Transferir la información a otro computador a través de una red de
comunicación de datos.
• Recepción: Recibir la información enviada por otro computador.
• Tratamiento: Operaciones sobre datos, tales como la ordenación, selección,
combinación, reclasificación, así como la ejecución de cálculos, que permita
obtener la información deseada.
30304" CNIQTKVOQU"["RTQITCOCU
Llamaremos algoritmo a un conjunto de pasos y acciones, que especifican
de forma no ambigua y finita, la secuencia de operaciones a realizar para procesar
datos con un determinado objetivo. (Este concepto abarca, desde un método de
resolución de ecuaciones, hasta la ejecución de una receta de cocina). Hagamos dos
aclaraciones previas: a) La algorítmica existe con anterioridad al desarrollo de los
computadores actuales (el propio origen de la palabra proviene de un matemático
árabe que describió en el siglo VIII el método manual con el cual dividimos dos
números). b) Una vez encontrada este conjunto de instrucciones que resuelven el
problema, éstas se pueden ejecutar sin que sea necesaria la comprensión de los
principios en los que se basa el algoritmo. Así cuando dividimos dos números o
construimos una pajarita a partir de una cuartilla, nos limitamos a ejecutar una serie
de acciones en un determinado orden, sin preocuparnos demasiado por sus
correspondientes bases teóricas.
Para el caso en que el procesador sea un computador, la forma de expresión de este
algoritmo se llama programa. Cada paso del algoritmo se expresa en el programa,
por medio de un conjunto de instrucciones escritas en un determinado lenguaje.
Uno de los aspectos más llamativos de los computadores es el hecho de que con un
reducido número de instrucciones básicas, pueda llevarse a cabo una gran cantidad
de tareas.
El conjunto de pasos que constituyen el programa debe escribirse de forma muy
precisa. La ambigüedad inmanente a los lenguajes naturales (español, inglés, etc.)
los invalida para expresar algoritmos, por ello existe un cierto tipo de lenguajes que
4
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
reúne la suficiente precisión como para expresar algoritmos: son los llamados
lenguajes de programación. Estos lenguajes tienen, como todo lenguaje una
sintaxis (cómo agrupar las símbolos y elementos propios del lenguaje para formar
frases válidas) y una semántica (qué significa cada frase válida de este lenguaje)
diferenciándose de los lenguajes naturales en cuatro características:
1) Su vocabulario y su sintaxis son sencillos y limitados. Esto los hace,
inadecuados para describir cualquier tipo de prosa no algorítmica.
2) El vocabulario de un lenguaje de programación contiene solamente aquellos
tipos de acciones básicas que puede ejecutar un ordenador (operaciones
aritméticas, lógicas, entrada/salida, etc.) y no otras.
3) La sintaxis es muy rígida y no permite excepciones ni muchas variaciones.
Por ejemplo para calcular una división de “X” por “A”, hay que escribir
obligatoriamente “X/A”.
4) Su semántica es estricta y la ambigüedad no tiene cabida en ellos.
Un mismo algoritmo puede expresarse en diferentes lenguajes y ejecutarse en
distintos ordenadores. Contar con un algoritmo es una condición necesaria para la
obtención de un programa, aunque no es suficiente, ya que su realización requiere
además, creatividad y conocimientos sobre los recursos físicos y lógicos del
ordenador. La fase de conversión del algoritmo a programa se denomina
codificación, ya que el algoritmo escrito en un lenguaje específico de
programación se denomina código.
Para que se puedan procesar los datos por medio de un programa, el conjunto de
instrucciones que lo constituyen debe ser accesible para la máquina y en
consecuencia, ésta debe tener la capacidad de almacenarlo internamente, al objeto
que pueda efectuar el control de las operaciones que constituyen el algoritmo.
Aunque todavía no hayamos profundizado en el concepto de computador, sí que
podemos deducir que éste tiene que ser capaz de trabajar y reconocer
simultáneamente tanto las instrucciones, que determinan lo que hay que hacer,
como los datos que se van a procesar. Este requisito es tan fundamental, que la
forma como éste se ha venido plasmando, conceptual y técnicamente a lo largo de
la historia, permite rastrear los orígenes de la informática.
3040" CPVGEGFGPVGU"JKUVłTKEQU
En 1982, la revista TIME nombró “hombre del año” a la computadora. La
noticia supuso un impacto cultural importante y oficializó el hecho de que esta
máquina es un personaje más de la historia de la humanidad. Aunque considerada
como un paradigma de la etapa moderna y con sólo 30 años de verdadera historia
CONCEPTO DE COMPUTADOR
5
(hasta mediados de los años 60 las computadoras eran caras y para usos muy
específicos que sólo las grandes instituciones y universidades podían permitirse) su
consecución, de una u otra forma, ha ocupado y preocupado a muchas de las
cabezas que jalonan la historia de la ciencia. El hecho de que nuestro estado actual
de avance tecnólogico haya permitido su construcción, no debe ocultar los
esfuerzos hechos desde los inicios del pensamiento científico.
Ábacos
La necesidad de contar con un elemento mecánico que ayude a las
personas en sus tareas de manipulación numérica, o lo que es lo mismo una
máquina que ejecute algoritmos de forma más o menos automática es realmente
antigua. Todos los historiadores coinciden en citar como antecedente de lo que hoy
llamamos computador al ábaco; instrumento utilizado para la suma y la resta, desde
hace 4000 años. Este consiste en un conjunto de alambres que llevan ensartados
unas cuentas móviles, colocadas en un marco rectangular cruzado por una barra
horizontal que atraviesa los alambres (Figura 1.2).
Cada una de las cuentas situadas por encima de la barra horizontal vale cinco, y
cada cuenta situada bajo la barra vale uno. Si comenzamos por la parte de la
derecha y nos vamos moviendo hacia la izquierda, el primer alambre representa el
dígito de las unidades; el segundo, el de las decenas; y sucesivamente las centenas,
los millares, etc. Borramos o ponemos a cero el ábaco separando todas las cuentas
de la barra horizontal. Introducimos los números moviendo las cuentas
correspondientes hacia esa barra, comenzando por el dígito situado más hacia la
derecha, y moviéndonos hacia la izquierda.
Este artilugio resulta de especial interés para ayudar a sumar o restar dos números.
La entrada de datos se hace a través de una persona, que también se encarga de la
ejecución y control del algoritmo de suma o resta correspondiente, la salida de
datos es consecuencia de la observación de las cuentas, por lo que esta máquina
seria un sistema de almacenamiento, que necesita de un experto humano para
procesar información (suma y resta).
6
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Fig. 1.2 Representación en un ábaco del número 1610
Calculadoras mecánicas
A medida que las distintas otras ramas científicas se desarrollaron, se puso
en evidencia la necesidad de optimizar la capacidad de cálculo habida cuenta de lo
dificultoso de las operaciones que se tenían que llevar a cabo. Ello hizo que
muchos matemáticos se plantearan el desarrollo de instrumentos que facilitaran al
menos teóricamente esta labor. Así, John Napier, que recordamos por los
logaritmos neperianos, publicó un estudio en 1617 que describía la utilización de
cuentas con una marca especial, para realizar multiplicaciones y divisiones (la obra
matemática de Napier condujo mucho más adelante al desarrollo de la regla de
cálculo, venerable instrumento que durante muchos años fue para algunos de
nosotros la “máquina” primaria para llevar a cabo cálculos complejos). En 1642,
Blaise Pascal inventó la primera “sumadora” real, parecida a las calculadoras
mecánicas que se popularizarian en nuestros años sesenta. Se trataba de una
compleja combinación de ruedas, engranajes y ventanas a través de las cuales
aparecían los números. A finales del siglo XVII, otro famoso matemático, Gottfried
Leibnitz, desarrolló una máquina parecida, pero más avanzada; podía sumar, restar,
multiplicar y dividir mecánicamente, e incluso sacar raíces cuadradas.
CONCEPTO DE COMPUTADOR
7
A pesar de la ingeniosidad de estos planteamientos mecánicos, hasta 1820 no se
pudo disponer de la tecnología que permitiera la aparición de las primeras
máquinas comerciales capaces de efectuar las cuatro operaciones matemáticas
básicas. Esta es una constante en la historia de las máquinas de calcular, el decalaje
existente entre los diseños originales y las disponibilidades tecnológicas para
llevarlos a la práctica. En la máquina de Leibnitz, se produce un avance respecto al
ábaco, puesto que el algoritmo esta ya incorporado en la propia estructura de la
máquina y además respecto a la de Pascal supone un incremento en flexibilidad,
pues el usuario puede seleccionar, la operación que desea llevar a cabo. Sin
embargo, en su tiempo no pasaron de ser meras curiosidades, sin posibilidad de
aplicación práctica.
Las tarjetas perforadas y los computadores mecánicos
A comienzos del siglo XIX se producen aportaciones, curiosamente ligadas
a la resolución de problemas de naturaleza no numérica. En 1801, Joseph Jacquard,
inventó un telar controlado mediante instrucciones almacenadas según un código
representado en tarjetas perforadas; de esta forma, el algoritmo que segue la
máquina podrá cambiarse fácilmente para conseguir un dibujo distinto sobre la tela.
La máquina de Jacquard incorporó varios elementos básicos que constituyen los
computadores actuales.
La idea de usar en tarjetas perforadas, para guardar tanto números como
instrucciones datos indujo, en 1835, a Charles Babbage, a inventar un computador
digital matemático de tipo mecánico que recibió el nombre de máquina analítica.
Babbage utilizó las tarjetas perforadas para programar su máquina, que podía
utilizar los resultados de un cálculo como entrada del siguiente y que era capaz de
manejar cálculos repetitivos, que más adelante llamaremos bucles. Un logro, aun
más significativo, de la máquina analítica fue que, en vez de seguir las
instrucciones del programa en la secuencia prefijada, podía saltar de una a otra (los
programadores actuales hablamos de bifurcaciones condicionales). Aunque los
computadores actuales están basados en muchos de los principios que Babbage
utilizó, en su tiempo no existía ningún procedimiento que pudiera mover su cada
vez más complejo artilugio mecánico. Una vez más, la tecnología no era la
adecuada para el desarrollo teórico propuesto y el trabajo de Babbage se saldó con
un fracaso, sólo mitigado por el apoyo de Ada Lovelace, hija de Lord Byron,
considerada como la primera programadora de la historia y en cuyo honor el
lenguaje de programación ADA lleva su nombre.
El concepto de la tarjeta perforada para almacenar programas y datos llegó a
prender, y Herman Hollerith para procesar el censo de 1890 en EEUU la recuperó
con notable éxito (consiguió un ahorro de tiempo de varios meses) al incorporarla a
máquinas alimentadas eléctrica y no mecánicamente. Hollerith puso las bases de
8
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
una de las empresas que más adelante se integraría en la International Business
Machines (IBM).
En paralelo, George Boole (1815-1864), el fundador de la teoría de la lógica
matemática, nos legó un álgebra para representar cantidades lógicas e investigó las
operaciones que se pueden realizar con estas variables (álgebra de Boole). La
lógica booleana es la base teórica tanto para el diseño de circuitos electrónicos
como para muchas técnicas de programación, aunque difícilmente, pudo ser Boole
consciente de la trascendencia práctica de su teoría.
Los computadores electromecánicos
Coincidiendo con la aparición de las máquinas eléctricas y bajo le presión
del esfuerzo bélico de la Segunda Guerra Mundial (resolución de claves secretas,
etc, ) se desarrollaron computadores electromecánicos, como elMark I (1944) de la
Universidad de Harvard. Se trataba de una máquina de grandes dimensiones, 15,5
metros de largo por 2,4 metros de altura, en la que las instrucciones se introducían
mediante cinta de papel, y los datos mediante tarjeta perforada y un teletipo iba
escribiendo los resultados. El Mark I podía multiplicar dos números en unos tres
segundos. En 1947, su sucesor el Mark II podía llevar a cabo la misma
multiplicación en un cuarto de segundo aproximadamente. Era doce veces más
rápido y suponía, un gran avance; sin embargo su obsolescencia fue inmediata,
como veremos a continuación, con el advenimiento de la electrónica.
Computadores electrónicos
La electrónica empieza con la válvula o tubo de vacío (un bulbo de vidrio,
donde una placa de metal calentada por un filamento emite electrones que se
desplazan en el vacío debido a una diferencia de potencial entre el cátodo y el
ánodo). El primer computador digital electrónico utilizaba tubos de vacío y podía
realizar una multiplicación en unos 2,8 milisegundos. Fue desarrollado en 1946 por
un equipo de la Universidad de Pennsylvania. Esta máquina recibió el nombre de
ENIAC, (Electronic Numerical Integrator and Computer) su primera aplicación, a
pesar de la finalización de la guerra, fue el cálculo de las tablas de tiro de la
artillería. El ENIAC se programaba cambiando manualmente los conectores y
manipulando conmutadores, lo que, como podemos imaginar, requería gran
cantidad de tiempo, por lo que su uso casi no traspasó el ámbito académico.De
hecho, éstas máquinas no tuvieron ningún impacto comercial, aunque sentaron
claramente las bases del diseño de los computadores actuales. Cuando en 1947
tiene lugar, en los laboratorios Bell, la invención del transistor (más pequeño que
la válvula, menor consumo y mayor fiabilidad) se posibilita el paso del
computador, de pieza experimental de laboratorio, a dispositivo con ciertas
posibilidades comerciales.
CONCEPTO DE COMPUTADOR
9
Otro avance tecnológico posterior, los circuitos integrados, permitieron integrar
en un único sustrato de silicio cientos de transistores (actualmente esta integración
es ya del orden de millones, en los llamados chips2), con lo que quedaron sentadas
las bases de los computadores actuales. A pesar de que quedaban muchos
problemas por resolver, a principios de los años sesenta, las ideas y las tecnologías
estaban ya maduras y se trataba de seguir una evolución, cuyos resultados no han
dejado de sorprendernos hasta ahora. El computador es uno de los elementos claves
de la actual revolución científico-industrial y su papel, en la historia de la
humanidad, no será menor que el que jugaron en su día, la rueda, el motor de
explosión o la energía nuclear.
3050" QTICPK\CEKłP"FG"WP"EQORWVCFQT
30503" NC"CTSWKVGEVWTC"FG"XQP"PGWOCPP
John von Neumann3 (1903-1957), que había colaborado en el diseño
varios computadores durante la Segunda Guerra Mundial, publica en 1946
artículo que esboza los principios generales de diseño de un computador en
sentido actual:
- La máquina es controlada por un conjunto de instrucciones, con
pequeño número de elementos centrales de proceso.
de
un
su
un
- El programa se almacena en el computador de forma que en su
representación interna no se hacen distinciones entre datos e instrucciones,
ambos almacenados en código binario.
De esta forma el programa pasa a estar “dentro” del computador, y así el cambio de
un programa a otro sólo implica un cambio en el valor de posiciones de memoria,
en contraposición con lo hecho hasta la fecha que requería cambios manuales de
clavijas. Estos principios, enriquecidos con importantes aportaciones tecnológicas,
2
. La forma que adoptan estos circuitos encapsulados con sus conectores, los asemeja a las pulgas (chip en inglés),
por lo que esta denominación es la que ha terminado por imponerse.
3
Von Neumann y sus colaboradores describieron una máquina constituida por dos órganos, uno constituido por
las unidades de control, de aritmética y de entrada salida y otro formado por la memoria. En esta máquina la
memoria ocupaba 4096 palabras o posiciones de memoria cada una de 40 bits. Cuando una palabra se interpretaba
como dato, estos 40 bits representaban un número en notación binaria y cuando lo hacía como instrucción, cada
palabra contenía 2 instrucciones de 20 bits. Los datos eran todos enteros y las operaciones aritméticas que podía
efectuar eran suma, resta, multiplicación, división y valor absoluto, de forma que el resultado de cualquiera de
ellas se situaba en un registro llamado acumulador. A cada posición de memoria podía asignársele el valor
contenido en el acumulador, de forma que se reemplazaba el valor anterior almacenado en esta posición de
memoria. El flujo de control del programa era el de pasar de una instrucción a la siguiente, pudiendo ser
interrumpida esta secuencialidad a través de un salto incondicional (goto) de forma que la siguiente instrucción a
ser ejectuada era la de la palabra de memoria que se mencionaba en la instrucción del salto incondicional.
10
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
se han mantenido vigentes hasta nuestros días en lo que llamamos máquina de von
Neumann, y cuyo esquema general es el de la Figura 1.3.
30504" WPKFCFGU"HWPEKQPCNGU
Las unidades funcionales de una máquina de von Neumann son cinco:
Unidad de Control (UC), Unidad Aritmético-Lógica (ALU), Unidad de
Entrada, Unidad de Salida y Memoria (principal y secundaria). Por su
disposición y función, se llama unidad de central de proceso (CPU = Central
Process Unit) al conjunto formado por la UC y la ALU, donde reside la
‘inteligencia’ de la máquina, es decir, la capacidad de procesamiento de la
información. La memoria es el lugar donde se almacenan los datos y las
instrucciones de forma permanente o transitoria. Un vistazo al esquema de la
Figura 1.3., justifica que llamemos periféricos al conjunto de unidades de E/S y de
memoria masiva ó auxiliar.
Fig. 1.3 Esquema de una máquina de von Neumann
Veamos ahora con más detalle las unidades funcionales:
UNIDAD DE ENTRADA (E). Son los dispositivos por donde se introducen los
datos e instrucciones. En estas unidades se transforman las informaciones de
entrada, en señales binarias de naturaleza eléctrica. Son unidades de entrada: el
CONCEPTO DE COMPUTADOR
11
teclado, un terminal de ventas, un digitalizador, una lectora de tarjetas de crédito,
etc.
UNIDAD DE SALIDA (S). Son los dispositivos por donde se obtienen los
resultados de los programas ejecutados en el computador. La mayor parte de estas
unidades transforman las señales eléctricas binarias en caracteres, escritos o
visualizados, inteligibles por un humano o por otra máquina. Son dispositivos de
salida: un monitor, una impresora, un registrador gráfico, el visor de un casco de
realidad virtual, etc.
LA UNIDAD DE PROCESAMIENTO CENTRAL (CPU). La CPU se encarga
de manipular los datos, gracias a su capacidad para ejecutar una serie de tareas
básicas que se corresponde con las operaciones incluidas dentro de sus circuitos,
contenidos, normalmente, en un solo chip llamado microprocesador Estos están
constituidos, al menos, por dos unidades básicas, la UC y la ALU.
LA UNIDAD DE CONTROL. Es la encargada de administrar y coordinar los
recursos y actividades del computador. Se puede pensar en la UC, como si fuera un
guardia de tráfico, dirigiendo el flujo de datos dentro de la máquina, esto es, un
coordinador que controla la ejecución “tirando de la cuerda adecuada, en el
momento adecuado”. Por ello la UC tiene misiones relacionadas con: identificar
instrucciones, supervisar su ejecución (enviando bits a las líneas de señal
adecuadas en los momentos adecuados), y detectar señales eléctricas, procedentes
del resto de unidades. Durante la ejecución de un programa la UC de forma
sucesiva, debe seguir el siguiente ciclo: a) Captar de memoria una a una las
instrucciones. b) Identificar las unidades involucradas en las operaciones asociadas
a la ejecución de la misma. c) Generar, de acuerdo con el código de operación y
con las señales de estado, las correspondiente señales de control.
Más específicamente, las funciones de la UC son:
1.
2.
3.
4
5.
Interpretar el código y generar las señales de control que lo ejecutan.
Controlar la secuencia en que se ejecutan las operaciones.
Controlar el acceso a la memoria principal
Enviar y recibir señales de control relacionadas con las operaciones que
ejecuta la ALU
Regular las temporizaciones de las unidades de E/S
UNIDAD ARITMÉTICO-LÓGICA. Esta unidad contiene los circuitos
electrónicos con los que se llevan a cabo las operaciones básicas de tipo aritmético
(suma, resta, multiplicación, división, etc.), y de tipo lógico (comparar dos
números, hacer operaciones del álgebra de Boole, etc). Este aparentemente limitado
conjunto de circuitos es más que suficiente, ya que todas las operaciones se pueden
llevar a cabo en términos de un gran número de pequeños pasos, involucrando cada
uno de ellos, uno o dos circuitos.
12
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
La ALU aparte de los circuitos operativos, contiene un grupo de registros, es decir,
de pequeñas memorias construidas directamente en la CPU, que se usan para
guardar los datos que van a ser procesados por la instrucción actual. Por ejemplo, la
UC puede cargar dos números de memoria en los registros de la ALU, para luego
ordenarle, que los divida (una operación aritmética) o que verifique si son iguales
(una operación lógica), dejando el resultado correspondiente en otro registro de la
unidad.
MEMORIA
La CPU contiene la lógica y los circuitos para que pueda funcionar la
computadora, sin embargo carece de espacio para guardar programas y datos, esta
es precisamente la misión de la unidad de MEMORIA: almacenar de forma
eficiente tanto datos como programas. Notemos que, aunque la CPU contiene
registros para datos e instrucciones, éstas son áreas de memoria muy pequeñas, que
sólo pueden guardar unos cuantos bits a la vez; cuando hay necesidad de grandes
cantidades de espacio de almacenamiento se hace necesaria la memoria externa a la
CPU. Existen dos tipos básicos de memoria, diferenciadas tanto por sus funciones
como por su velocidad: la principal y la secundaria. En ambas, la información se
codifica en un alfabeto binario formado por bits, generalmente 8, llamado octeto o
byte, que es la unidad utilizada para medir la capacidad de almacenamiento de una
memoria. Como el byte es relativamente pequeño, es usual utilizar múltiplos:
10
3
1 Kbyte (o KB) = 2 bytes = 1024 bytes ### 10 bytes
10
20
1 Megabyte (o MB) = 2 Kbytes = 2 bytes = 1048 576 bytes ### 106
bytes
10
30
1 Gigabyte (o GB) = 2 Mbyte = 2 bytes = 1 073 741 824 bytes ### 109
bytes
10
40
12
1 Terabyte (o TB) = 2 Gbyte = 2 bytes ### 10 bytes
Memoria principal (central o interna). Su función es la de almacenar los
datos y el programa que va ejecutarse en cada momento, por ello es la más rápida y
tiene optimizada sus transferencias, con la CPU Físicamente la memoria consiste
en una serie de chips conectados con el microprocesador de la forma más integrada
posible. La memoria está dividida en celdas o posiciones denominadas también
palabras de memoria (Ver Figura 1.4.), estas celdas tienen como longitud, un
número determinado de bits, normalmente coincidiendo con un múltiplo del byte:
8, 16, 32, 64, etc.
CONCEPTO DE COMPUTADOR
Fig. 1.4.
13
Disposición de las celdas o posiciones de una memoria
Existen distintos tipos de memorias y más de una manera de clasificarlas. Una
manera de hacerlo es por la permanencia de la información en ellas. Algunos chips
de memoria siempre conservan los datos que tienen aun cuando la computadora
esté apagada; esta memoria se llama no volátil. Otros chips, que forman la mayor
parte de la memoria, sí pierden su contenido cuando la computadora se apaga, la
memoria de éstos es volátil.
Una segunda clasificación de la memoria es por la manera en que puede usarse.
Algunos chips de memoria siempre guardan los mismos datos, esto es, además de
ser no volátiles sus datos no pueden ser cambiados. De hecho, cuando los datos se
guardan en este tipo de memoria se llama “grabación permanente de los datos”. ya
que sólo pueden leerse y usarse, nunca cambiarse. Este tipo de memoria se llama
memoria de sólo lectura (Read Only Memory, ROM). Una de las razones por las
que una computadora necesita ROM es para disponer de instrucciones en el
momento del encendido, ya que sin datos grabados de forma permanente, no se
podría producir todas las tareas que constituyen el proceso de arranque. La
memoria cuyo contenido puede cambiarse se llama memoria de acceso aleatorio
(Random-Access Memory, RAM). El propósito de la memoria RAM es guardar los
distintos programas y datos, que vamos a utilizar en cada momento. Utilizamos el
término acceso aleatorio porque la CPU accede a su memoria, utilizando una
dirección de memoria, que es un número que indica un lugar en el chip de
memoria, (de la misma forma que si fuera un número de apartado postal, que indica
en qué buzón deberá ponerse el correo). De esta manera, la computadora no tiene
que reconocer en toda la memoria para encontrar los datos que necesita; puede
buscar la dirección e ir directamente a ella.
En ambos tipos de memoria, la lectura es no destructiva ya que el contenido de una
posición de memoria no se altera por muchas veces que se lea. Sin embargo, la
escritura en una memoria RAM (recordemos que la memoria ROM no permite la
14
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
escritura) es destructiva, es decir, cuando se escribe algo en una posición de
memoria automáticamente se destruye el contenido anterior.
Memoria auxiliar masiva, (secundaria o externa). La memoria principal,
aunque es muy rápida, no tiene gran capacidad de almacenamiento. Para guardar
grandes cantidades de información, se utilizan otros tipos de memoria, tales como
discos y cintas magnéticas, que siendo más lentas en la transferencia de datos,
tienen mucha más capacidad que la memoria principal (del orden de mil veces más
lentas pero más capaces). Frecuentemente los datos y programas se graban
(introduciéndolos por las unidades de entrada) en la memoria masiva, de forma que
si se ejecuta varias veces el programa o se utilizan repetidamente los datos, no es
necesario introducirlos de nuevo por el dispositivo de entrada, sino que basta
leerlos desde el disco o la cinta.
Las memorias masivas han heredado el concepto de fichero de los sistemas
manuales de tratamiento de la información, de forma que mucha de su terminología
deriva de la tradicional. Así hablaremos de ficheros o archivos como una
colección ordenada de datos relacionados entre sí. Existen distintos tipos de
archivos, algunos de ellos tienen como unidad elemental el registro, que se
correspondería con una ficha en un fichero manual. Los registros están formados
por campos, que constituyen unidades de información (la forma más común de
identificar un registro es eligiendo un campo dentro del mismo que llamaremos
clave). En la Figura 1.5. puede verse un ejemplo de este tipo de fichero.
Fig. 1.5.
Elementos de un fichero
Jerarquía de memoria
Una vez revisadas, las unidades funcionales, hay que hacer notar que la
mayor parte del tratamieto de la información se lleva a cabo en la ALU, por lo que
resulta importante aumentar la eficacia de su trabajo. Esta eficiencia depende de
sus registros, que como sabemos ,son pequeñas memorias que se utilizan para el
almacenamiento provisional de datos en el momento de ser objeto de
procesamiento. Un registro de datos debe ser lo suficientemente grande como para
almacenar los datos que puede manejar la ALU, es decir, si el dato estándar tiene
una longitud de m bits, el registro tiene que ser capaz de almacenar los m bits.
CONCEPTO DE COMPUTADOR
15
Notemos que los datos transitan por los registros constantemente: cuando van a
introducirse en la memoria, al acabar de ser extraídos de ella y cuando se obtienen
resultados intermedios durante operaciones de la ALU. En cuanto una palabra,
contenida en la memoria principal, se transfiere al registro adecuado, es cuando
actúa como instrucción o como dato de un programa. Así el programa, que está en
la memoria principal, al ejecutarse va captando, bien las diferentes instrucciones
bien los datos sobre los cuales se va a actuar, para situarlos en los registros
adecuados, consiguiendo con ello facilitar la implementación de las operaciones de
la máquina y aumentar su eficacia.
r e g is tr o s
CPU
V e lo c id a d
T am año
C o s te
m á s r á p id a
m ás pequeñ a
m á s c o s to s a
m á s le n ta
m ás gran de
m á s a s e q u ib le
m e m o r ia
ca ch é
m e m o r ia
p r in c ip a l
m e m o r ia
s e c u n d a r ia
( a u x ilia r o m a s iv a )
Fig. 1.6.
Estructura de una jerarquía de memoria
El conjunto de los tipos de memorias se organizan por niveles como una jerarquía
de memorias (ver Figura 1.6). Los registros se usan para manejar los datos
utilizados en la operación que se esta ejecutando, la memoria principal se utiliza
para soportar los datos que serán utilizados en el futuro próximo y la memoria
secundaria se usa para aquellos datos que normalmente no van a ser manipulados
en el corto plazo. En muchas máquinas existe un nivel adicional, llamado memoria
cache, consistente en una memoria de gran velocidad con tiempos de respuestas
semejantes a los registros, normalmente situada en la propia CPU. La máquina trata
de utilizar esta área de memoria como copia de la porción de memoria que le
interesa en cada momento. En este caso la transferencia de datos en lugar de
hacerse entre memoria y registros se hace entre memoria caché y registros, y
resultando mucho más rápida.
BUSES
Un requisito para el buen funcionamiento de la máquina, es la conexión,
para el intercambio de información, entre unas unidades y otras. Este intercambio
entre unidades se tiene que lleva a cabo en paralelo (varios bits de información al
16
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
mismo tiempo) a través de una canal de información o bus que contiene un
determinado número de hilos conductores.
La palabra es la unidad de transferencia de información, al estar ligada a la
estructura interna de la computadora, su longitud, en bits, indica tanto el tamaño de
los datos con que opera la ALU, como la de los datos transferidos entre la memoria
y la CPU. Por tanto, esta longitud acaba determinando las características físicas de
los buses4. Así, por ejemplo, se se trabaja con palabras de memoria de 16 bits la
información desde una unidad a otra debe transmitirse por un bus de 16 hilos
conductores.
A través del bus, la CPU puede extraer (leer) datos de la memoria principal,
proporcionando tanto la dirección de la posición de memoria como su contenido y
viceversa en el proceso de escritura en memoria. Al bus empleado para
intercambiar información entre los distintos subsistemas se le llama bus de datos,
mientras que si un bus es específicamente utilizado para indicar posiciones de
memoria se conoce como bus de direcciones.
3060" GN"EQPEGRVQ"FG"RTQITCOC"CNOCEGPCFQ
La idea de von Neumann de que tanto los datos como el programa residan
en la memoria principal, supone que una máquina esta diseñada para reconocer
ciertos patrones de bits que representan ciertas instrucciones, que ahora vamos a
definir con mayor precisión: llamaremos instrucción a un conjunto de símbolos
que representan una orden de operación, que suele realizarse con o sobre datos y en
consecuencia programa es un conjunto ordenado de instrucciones, que indican al
ordenador los procedimientos que se desean.
30603" VKRQU"FG"KPUVTWEEKQPGU
Puesto que los circuitos de la UC reconocen y ejecutan un determinado
repertorio de instrucciones, propias de su CPU, cuando se ejecuta un programa, la
computadora interpreta las ordenes contenidas en las instrucciones y las ejecuta
sucesivamente. Un programa se escribe, utilizando una sucesión de instrucciones y
salvo indicación contraria, su ejecución coincide con el orden en que las
instrucciones han sido escritas (Figura 1.7):
4
Nótese que las longitudes de palabra de la CPU y de la memoria pueden no coincidir, pues la longitud de la
palabra de CPU es el número de bits máximo de los datos con los que opera la ALU, mientras que la longitud de la
palabra de memoria es el número de bits que conforman cada posición de memoria (número de bits que se pueden
leer o escribir simultáneamente); este número suele coincidir con el número de bits (integrantes de datos o
instrucciones) que se transmiten simultáneamente entre las distintas unidades en un instante dado. Y longitud de
palabra debe ser tenida en cuenta a la hora de interconectar las distintas unidades.
CONCEPTO DE COMPUTADOR
17
instrucción 1
instrucción 2
.
.
.
instrucción n
Fig. 1.7.
Orden secuencial de las instrucciones de un Programa
Sin embargo, es básico, para que la flexibilidad del programa sea tal, que la UC
pueda interrumpir el orden normal, mediante instrucciones de bifurcación, que
permiten que el control del programa pase a una instrucción que no sea
necesariamente la inmediata. Con ello el desarrollo líneal de un programa se
interrumpe.(Figura 1.8)
instrucción 1
.
instrucción x
instrucción x+1
.
instrucción y
.
instrucción n
Fig. 1.8.
Ruptura del orden secuencial de las instrucciones
de un programa con una bifurcación
Una instrucción de bifurcación debe indicar el punto del programa hacia a donde se
bifurca. Desde el punto de vista del ‘sentido’ del salto, una bifurcación puede ser
hacia delante (en general puede considerarse que el computador deja de ejecutar
determinadas instrucciones), o hacia atrás (con lo cual pasa a ejecutar instrucciones
que pueden haberse ejecutado previamente).
Desde el punto de vista de la causa que la produce, la bifurcación puede ser:
incondicional, (el salto se da siempre que el flujo del programa pase por la
instrucción), ó condicional, caso que la bifurcación dependa del cumplimiento de
una determinada condición; si esta se cumple se produce el salto, si no, el programa
continúa en la instrucción siguiente a la de bifurcación.
Las instrucciones ejecutables por cualquier CPU, se pueden clasificar en los
siguientes grupos:
18
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
-
-
-
Instrucciones de transferencias de datos como por ejemplo: de entrada o
lectura (llevar un dato de una unidad de entrada a la memoria o a la
ALU), de salida o escritura (llevar un dato de la memoria o de la ALU a
una unidad de salida), transferencia de un dato de la memoria a la ALU o
viceversa, etc.
Instrucciones de tratamiento como por ejemplo, sumar dos datos,
comparar dos datos para comprobar si son iguales o uno mayor que otro;
en particular incluye las operaciones aritmético-lógicas que ejecuta la
ALU.
Instrucciones de bifurcación y saltos. Que permiten alterar el orden
secuencial de ejecución.
Otras instrucciones. Tal como detener el funcionamiento de la
computadora a la espera de una acción del operador, cambiar el modo de
funcionamiento de la CPU, etc.
Cada modelo de CPU, tiene su propio conjunto de instrucciones, sin embargo, los
fabricantes tienden a agrupar las CPU en “familias”, con conjuntos de instrucciones
semejantes. Cuando se desarrolla una nueva CPU, su conjunto de instrucciones, por
lo general, contiene las mismas instrucciones que tenia su predecesor, además de
algunas nuevas. Esto permite que un programa, desarrollado para una cierta CPU,
pueda utilizarse con nuevas CPU de la misma familia (esta estrategia de fabricación
es conocida como escalabilidad).
30604" NGPIWCLG"OıSWKPC"["NGPIWCLG"GPUCODNCFQT
La colección de instrucciones ejecutables para cada CPU, junto con su
sistema de codificación, se llama lenguaje máquina. Este lenguaje es el primer
lenguaje de programación que se utilizó y el único que entiende directamente el
computador, aunque, al estar ligado a la circuitería, queda muy alejado de la forma
en que solemos expresar los problemas. Sus principales características son:
• Las instrucciones son cadenas de ceros y unos.
• Los datos se utilizan por medio de las direcciones de memoria donde están
almacenados y no admite identificadores, sino que el programador debe hacer
una asignación de direcciones de memoria para todas las variables y constantes
del programa.
• Las instrucciones realizan operaciones muy simples, dependientes de las
posibilidades de la circuitería del procesador.
Los primeros programadores se comunicaban con los computadores
interconexionando cables, más adelante lo hicieron a través de números binarios,
pero éstas tareas eran tan plúmbeas, que pronto inventaron notaciones simbólicas
CONCEPTO DE COMPUTADOR
19
que facilitasen este trabajo. Sin embargo, estas notaciones tenían que ser traducidas
manualmente a binario, por lo que el siguiente paso fue conseguir programas que
tradujeran la versión simbólica de las instrucciones a la versión binaria. Así el
programador escribe:
CAR A , M(16)
y el programa traductor convierte esta notación en:
000000010000
indicándole al computador que cargue en el registro A de la ALU, el contenido de
la posición de memoria 16.
Este programa traductor se llama ensamblador y el lenguaje simbólico utilizado se
conoce como lenguaje ensamblador. Este lenguaje requiere que el programador
escriba una línea por cada instrucción que seguirá la máquina. Observemos que
ambos lenguajes (ensamblador y máquina) fuerzan al programador a pensar
directamente en las funcionalidades primarias de la propia máquina.
Siendo importante la aparición de los lenguajes ensambladores, la tarea de
programación, con ellos, seguía siendo ardua (aunque para ciertas aplicaciones aun
hoy, hay que recurrir a estos lenguajes). De hecho, los llamados ordenadores de
primera generación se desarrollaron, a pesar de su buen funcionamiento
electrónico, en medio de un cierto escepticismo, pues, al no estar conceptualizadas
abstracciones más próximas al modo de razonar de las personas, se pensaba, no sin
razón, que ni siquiera el propio creador de un programa alcanzaría su total
comprensión, una vez escrito en términos binarios o en lenguaje ensamblador.
Afortunadamente; los primeros programadores superaron tan negras perspectivas e
idearon los lenguajes de programación de alto nivel (Fortran, Basic, Pascal, Lisp,
Prolog, C, C++, etc.) mucho más amistosos, que se tratarán en un próximo
apartado.
30605" GLGEWEKłP"FG"WP"RTQITCOC
Llegados aquí, vamos a profundizar un poco más en el funcionamiento de
la máquina de von Neumann, analizando la forma como se ejecuta un programa ya
almacenadoen memoria. Supongamos que está almacenado a partir de la posición i
de memoria y que la ejecución indica “pasar el control a la posición i de memoria”.
A partir de ese momento, la UC repite sucesivamente las siguientes fases:
a)
Lleva de la memoria a la UC la instrucción que está en la posición i, y
cambiar el valor de i por i+1.
b)
Interpreta el código de operación de la instrucción y, según sea éste y las
señales de estado, envía señales de control a las unidades y circuitos que deben
20
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
intervenir para ejecutar la instrucción. Y efectua
(microoperaciones) que ésta implica. Volver a la fase a)
las
operaciones
La fase a) es igual en todas las instrucciones, siendo la fase de captación de
instrucción, y la b), es específica de cada instrucción, siendo la fase de ejecución de
la misma. En el caso de que la ejecución de la instrucción implique saltar a otra, a
la posición m por ejemplo, (alterándose por tanto el orden secuencial), la UC hace,
en la fase de ejecución de la instrucción de salto, que se cambie i por m, de forma
que en la siguiente fase de captación se ejecuta la instrucción que está en m, por ser
éste el valor actual de i.
A modo de ejemplo, vamos analizar un caso sencillo. Supóngase que se dispone de
un computador, con un teclado como unidad de entrada, una impresora como
unidad de salida (Ver Figura 1.9), y una CPU cuyo lenguaje máquina contiene,
entre otras, las instrucciones siguientes (validas para cualquier CPU):
- ENTrada de información que se transfiere a la posición m de memoria, que
se indica en el campo de dirección de la propia instrucción. Abreviadamente:
ENT M(m),E.
- SALida de información procedente de la posición m de memoria.:
SAL S,M(m).
- MEMorizar en la posición m de memoria el contenido de la ALU.
Abreviadamente: MEM M(m),A.
- CARgar en el registro A de la ALU, el contenido de la posición m de
memoria.: CAR A,M(m).
- SUMar el contenido del registro A, con el contenido de la posición m de
memoria, almacenándose el resultado en A.: SUM A,M(m).
- FIN indica a la UC que debe acabar el procesamiento de ese programa.
Se desea escribir un programa que sume dos números. Analizando el repertorio de
instrucciones de que se dispone, hay que ejecutar los siguientes pasos: 1) Leer
(“dar entrada”) los dos números llevándolos a la memoria, 2) Llevar uno de los
sumandos a la ALU, y sumarlo con el otro , 3) El resultado almacenado en la ALU,
llevarlo a la memoria y 4) Escribirlo a través de la unidad de salida.
(Ver diagrama de la Figura 1.9.)
CONCEPTO DE COMPUTADOR
21
Fig. 1.9. Diagrama de las operaciones a realizar para el programa de sumar
Además, el programador en lenguaje máquina, ha de determinar las posiciones de
memoria que va a utilizar. En el ejemplo vamos a seleccionar:
Primer sumando,
Segundo sumando,
Suma,
en posición 16
en posición 17
en posición 18
El programa es el siguiente:
(1) Leer el primer dato y llevarlo a la posición 16.
ENT M(16),E
00100 001 0000
(2) Leer el segundo dato y llevarlo a la posición 17.
ENT M(17),E
00100 001 0001
(3) Llevar a la ALU el primer dato (que está en m=16).
CAR A,M(16)
00000 001 0000
(4) Sumar el contenido de la ALU con el segundo sumando (que está en m=17).
SUM A,M(17)
11000 001 0001
(5) Llevar el resultado de la ALU a la posición m=18.
MEM M(18),A
00010 001 0010
(6) Escribir el resultado que está en m=18.
SAL S,M(18)
00110 001 0010
22
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
(7) FIN
Después de describir cada instrucción hemos escrito su abreviación y su
correspondiente instrucción máquina, cuyo procesador suponemos esta en
condiciones de manejar instrucciones de 12 bits: los cinco primeros son el código
de operación y los siete restantes constituyen el campo de dirección ó la dirección
de memoria que interviene en la instrucción.
Fig. 1.10 Contenido de la memoria después de ejecutado el programa en la
computadora del ejemplo (Por simplicidad , se representan las
instrucciones abreviadamente y los datos en decimal, aunque realmente
son ceros y unos).
Supóngase que el programa se carga en memoria a partir de la dirección i=8 , y se
indica a la UC que pase su control a la instrucción que está en i=8, con el objetivo
de sumar 50 + 26. Los pasos de la ejecución pueden seguirse fácilmente con ayuda
de la Figura 1.10:
(1.a) La UC capta la instrucción que está en i = 8 y cambia a i = 8 + 1 = 9.
(1.b) La UC interpreta el código de la instrucción, 00100. y genera las señales de
control para que el dispositivo de entrada lea un dato y sea escrito en la
posición m = 001 0000 o 16 en decimal. Si el dato tecleado es 50, al final de
la ejecución de la instrucción este valor en binario (0000 0011 0010) queda
almacenado en la posición 16.
(2.a) La UC capta la instrucción que está en i = 9 y cambia a i = 9 + 1 = 10
(2.b) La UC interpreta el código de la instrucción captada, 00100. y genera las
mismas señales de control que en la instrucción anterior. En este caso m =
CONCEPTO DE COMPUTADOR
23
001 0001 (17 en decimal) y el segundo dato, 26 queda grabado en binario
(0000 0001 1010) en la posición 17.
(3.a) La UC capta la instrucción que está en i = 10 y cambia a i = 10 + 1 = 11.
(3.b) La UC interpreta el código de operación de la instrucción 00000, generando
las señales de control necesarias para que se lea el contenido de la posición
m = 001 0000 (16 en decimal) y sea llevado a un registro de la ALU. Ningún
contenido de la memoria cambia.
(4.a) La UC capta la instrucción que está en i = 11 y cambia a i = 11 +1 = 12.
(4.b) La UC interpreta el código de operación de la instrucción captada, en este
caso 11000 y genera las señales de control para sumar el contenido de la
ALU (0000 0011 0010, en decimal 50) con el contenido de la posición m =
001 0001 de la memoria (que es 0000 0001 1010, en decimal 26). El
resultado de la suma (0000 0011 0010 + 0000 0001 1010 = 0000 0100 1100;
en decimal 76), queda en el mismo registro de la ALU.
(5.a) La UC capta la instrucción que está en i = 12 y cambia i a i = 12 +1 = 13.
(5.b) El código de operación, en este caso 00010, es interpretado por la UC, dando
ésta las señales de control para que el contenido de la ALU (0000 0100
1100) se grabe en la posición m = 0000 0001 0010 (18, en decimal) de la
memoria. El resultado de la suma queda, en la posición 18
(6.a) La UC capta la instrucción que está en i = 13. y cambia a i = 13 + 1 = 14.
(6.b) El código de operación, ahora 00110, se interpreta por la UC y ésta genera
las señales de control para leer de memoria, el contenido de la posición m =
0000 0001 0010 (18 en decimal) y llevarlo a la unidad de salida. Allí el valor
transferido, es convertido de forma que en la impresora se disparan los
elementos necesarios para escribir 76.
(7)
La UC capta la instrucción de FIN y acaba el procesamiento (La Figura 1.10
muestra el contenido de la memoria, al finalizar la ejecución).
Hay que insistir en que este problema, escrito en un lenguaje de alto nivel, habría
resultado mucho más sencillo, aunque una vez traducido el ordenador trabajaría
con un código muy parecido al que acabamos de usar.
3070" EQPEGRVQ"CEVWCN"FGN"EQORWVCFQT
30703" FGHKPKEKłP"CEVWCN
24
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Aunque no está en la óptica de este texto, el profundizar en las nuevas
arquitecturas que presentan los computadores en la actualidad, si parece necesario
poner en evidencia que el concepto de máquina de von Neumann tal como lo
hemos tratado hasta ahora, (como un dispositivo de procesamiento individual
controlado por un único programa), aunque adecuado, debe ser objeto de una
definición más amplia, para llegar al actual concepto de computador. A modo de
reflexión, hay que hacer notar que muchos computadores, contienen más de un
procesador, requieren para obtener varios programas trabajando de forma
aparentemente simultánea y que una computadora moderna puede tener gran
cantidad (cientos) de unidades de entrada o salida, próximas o remotas.Vamos a
dar una definición operativa de computador que amplie la máquina de von
Neumann:
Un computador es una colección de recursos, que incluyen: dispositivos de
proceso electrónico digital, programas almacenados y conjuntos de datos, que, bajo
el control de programas, produce salidas, almacena, recupera y procesa datos,
pudiendo también transmitirlos y recibirlos hacia y desde otros computadores. En
todo computador hay que distinguir dos soportes:
El soporte físico (hardware en inglés) que es la máquina en sí: el conjunto
de circuitos electrónicos, cable, armario, dispositivos electrónicos, etc.
El soporte lógico (o software, neologismo inglés que contrapone soft
(blando) con hard (duro), - logicielle en francés) que es el conjunto de programas
que dirigen el funcionamiento del computador: sistema operativo, programa de
usuario, etc.
Notemos que en la práctica la distinción física/lógica es más difusa de lo que
aparentemente parece, así en algunos computadores las multiplicaciones se hacen
directamente por hardware, mientras que en otros se hace en forma de sumas
múltiples, controladas por software. Además, parte del software está almacenado
permanentemente en forma de ROM, que se conoce como firmware y que es un
ente intermedio entre el hardware y el software.
30704" RCTıOGVTQU"DıUKEQU"FG"NC"OıSWKPC
Existen varias características, relacionadas con el funcionamiento de las
distintas unidades funcionales.que determinan el tipo y velocidad del ordenador
central. En este sentido, hay que saber que la UC contiene un reloj o generador de
pulsos, que sincroniza todas las operaciones elementales de la computadora. El
período de esta señal se denomina tiempo de ciclo, cuyo orden de magnitud es de
nanosegundos. La frecuencia del reloj (que suele darse en millones de
CONCEPTO DE COMPUTADOR
25
ciclos/segundo o Mhz) es un parámetro que en parte determina la velocidad de
funcionamiento de la computadora.
La longitud de palabra determina, la precisión de los cálculos, la característica de
los buses y la variedad de instrucciones respecto a esta velocidad, sabemos que
cada CPU tiene un conjunto de instrucciones, determinado. Hoy en día, hay dos
grandes familias: Procesadores con un amplio conjunto de instrucciones (CISC =
Complex Instruction Set Computer) y Procesadores con un conjunto de
instrucciones reducido, pero optimizadas para que éstas se ejecuten más rápido
(RISC = Reduced Instruction Set Computer).
Es frecuente, en computadores convencionales, que la gestión de las operaciones
con números reales (que arrastran un gran numero de decimales y por tanto
requieren bastantes ciclos de ejecución en la ALU) se realicen por hardware con
circuitos integrados auxiliares conocidos como coprocesador matemático. El que
un computador disponga o no de coprocesador matemático varía enormemente su
velocidad en aplicaciones que requieran gran número de operaciones con números
reales. La tendencia actual es que el coprocesador matemático se integre dentro de
la propia CPU y no se hable explícitamente del mismo (por ejemplo el 486 y el
Pentium). Igualmente el tipo de bus (o buses) que conecta los distintos subsistemas
del computador condiciona su potencia, especialmente en la adecuación del número
de líneas del bus con el tamaño de palabra.
Otros de los parámetros significativos son las capacidades de memoria principal y
secundaria. La capacidad de la memoria principal, indica el tamaño de los
programas (instrucciones+datos) que el computador puede procesar
simultáneamente. La memoria secundaria sirve tanto como ‘ampliación’ de la
memoria principal (dentro de la concepción de jerarquía de memorias ya indicada),
como almacenamiento permanente de programas y datos. Al considerar todos estos
parámetros, es importante recordar, que para acceder a instrucciones o datos, es
imprescindible el poder direccionar todas y cada una de las palabras de la memoria
principal. En una primera aproximación, esto se hace asignando a cada posición un
número en base 2; así con n bits podemos direccionar 2n palabras. Sin embargo,
hay que analizar lo que supone esta función de direccionamiento, a medida que la
memoria crece; así para direccionar 64 Kpalabras necesitamos 16 bits y para 1
Mpalabra son necesarios 20 bits, con lo que al crecer la memoria se hace
imprescindible acudir a técnicas de direccionamiento, para poder acceder a un
número grande de palabras con un número relativamente pequeño de bits.
Junto con la capacidad de la memoria secundaria. de los distintos periféricos, el
tiempo de acceso (para lectura y para escritura en el periférico) es un parámetro
importante para determinar la potencia de un computador. Además de cuantos y
cuáles sean los periféricos que puede incorporar un determinado computador (p.e.
26
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
los computadores personales disponen de slots o ranuras sobre el bus para ‘clavar’
nuevos componentes; el número y tipo de los slots establece las posibilidades de
ampliación de periféricos).
3080" FGN"EQORWVCFQT"C"NC"RTQITCOCEKłP
Una vez visto el funcionamiento del computador, hay dos consecuencias a
sacar sobre la naturaleza de esta máquina:
1) Desde el punto de vista de los datos, éstos se presentan en forma de estructuras
binarias de tamaño predefinido. El computador sólo trabaja con estructuras
aparentemente muy limitadas, que son las que incorporan los registros y las
palabras de la memoria en las que se almacenan valores binarios.
2) Desde el punto de vista algorítmico, el número de operaciones que puede llevar
a cabo viene prefijado y limitado por un conjunto de instrucciones
dado,materializables a través de circuitos electrónicos.
La pregunta que surge es inmediata, ¿cómo puede una sola máquina representar
datos tan complejos y diferentes como números, textos,vectores y otras estructuras
más elaboradas, con solo la utilización de bits y al tiempo, resolver un espectro tan
amplio de problemas con la única utilización del repertorio del lenguaje máquina?.
En otras palabras, ¿cómo supera el computador éstas limitaciones, tanto en materia
de estructura de datos como de algoritmos?
La respuesta la indicó el propio von Neumann: El computador es una máquina de
propósito general, cuya naturaleza queda transformada por el programa que se le
proporciona, de forma que en un momento dado, un caudal de información
constituye un conjunto de datos procesados por el programa, y a continuación otro
caudal de información se interpreta como instrucciones ejecutables.
30803" NQU"FCVQU
Los datos son los objetos sobre los que opera un ordenador; sabemos que
éste tiene capacidad de procesar datos de tres tipos básicos: numéricos, lógicos y
caracteres alfanuméricos (no deja de ser sorprendente que, estando el cálculo
científico en el origen del ordenador, sus actuales aplicaciones sean mucho más
amplias que las derivadas del manejo de números). Los primeros representan las
diferentes clases de números, enteros y reales, con distintas posibilidades de rango
de magnitud y precisión. Los datos lógicos o booleanos son aquellos que pueden
tomar valores ciertos o falsos y que nos servirán para tomar decisiones en función
de que se cumplan o no determinadas condiciones. Los datos alfanuméricos son, a
CONCEPTO DE COMPUTADOR
27
grandes rasgos, los que puede producir un teclado habitual. Retengamos la idea, de
que el ordenador está en condiciones de representar y diferenciar internamente
estos tipos de datos simples, que a su vez pueden aparecer de forma aislada o
agrupados en forma de una estructura. Como tendremos ocasión de ver, existen una
importante variedad de datos estructurados, como por ejemplo:
cadenas de caracteres.
vectores y matrices (habitualmente de datos numéricos).
registros y ficheros para el almacenamiento secundario.
30804" NGPIWCLGU"FG"RTQITCOCEKłP"FG"CNVQ"PKXGN
Como ya anunciamos, ante los serios inconvenientes de los lenguajes
máquina y ensamblador desde los inicios de los computadores actuales, se han
desarrollado los llamados lenguajes de alto nivel, con algunas características muy
apreciadas: están más cercanos a nuestra forma de resolver problemas, son
relativamente independientes de la máquina, (una sola de sus instrucciones
equivale a varias instrucciones de lenguaje máquina), facilitan enormemente el
proceso de programación, acercándolo, en la medida de lo posible, a los lenguajes
que los humanos utilizamos habitualmente, etc.
Las sentencias o frases que se pueden construir a partir de la sintaxis de un
lenguaje de alto nivel son de dos tipos: imperativas (o instrucciones) que indican
acciones a tomar por el computador, o declarativas, que proporcionan información
sobre determinadas circunstancias del programa. Así la sentencia:
float Base
es declarativa, ya que no implica una acción visible dentro del contexto del
programa, sino que indica al programa traductor, que la variable Base se va a
utilizar como un dato numérico en coma flotante, de simple precisión para que lo
tenga en cuenta, a efectos de representación interna en la memoria. Sin embargo, la
sentencia:
Area = Base * Altura
es una instrucción pues produce la ejecución de una operación, en este caso,
multiplicar el valor de Base por el de Altura, y el valor del resultado asignárselo a
la variable Area.
Notemos que comparados con los lenguajes máquina, los de alto nivel permiten
utilizar variables, símbolos y términos más parecidos a los usados por los humanos,
en la resolución de problemas. Este proceso de abstracción nos permite pensar con
independencia de las particularidades con las que trabaja la máquina, sin ello
resultaría casi imposible crear programas de tamaño no trivial. El programador a la
hora de resolver un problema, establece una jerarquía de abstracciones, hasta que el
28
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
computador puede encargarse de su traducción y posterior ejecución. Con ello
tenemos una doble ventaja, por un lado que el programador piense en una
determinada estructura de datos sin tener que preocuparse en cómo se organizan
éstos realmente en memoria y por otro, que pueda utilizar operaciones, habituales
para nosotros, que serán finalmente ejecutadas por el procesador. Por tanto los
lenguajes de alto nivel deben permitir especificar en forma abstracta tanto
estructuras de datos complejas como los distintos pasos que constituyen un
algoritmo que implementa un programa. Esta idea constituirá el hilo conductor de
este libro, obedeciendo a una de las claves de la Programación.
PROGRAMA = ESTRUCTURA DE DATOS + ALGORITMOS
Esto significa que todo proceso de programación, además de contar con un
algoritmo que resuelva el problema planteado, ha de tener conceptualizada la forma
como organizar los datos antes y después de ser procesados. De hecho, ambas
cuestiones están interrelacionadas: una estructura de datos adecuada puede
simplificar el diseño de un algoritmo, y un algoritmo menos adecuado que otro
puede implicar manejar estructuras de datos más complejas.
La evolución del arte y la tecnología de la programación es muy intensa y sigue en
pleno desarrollo, en la actualidad. Veamos algunos hitos: programación clásica,
representada por las primeras versiones de FORTRAN y BASIC, se caracteriza por
el mero uso de una secuencia de ordenes y bifurcaciones; programación modular,
añade un método de diseño que permite resolver un problema, mediante su
descomposición en problemas más simples o módulos; programación
estructurada (representada por PASCAL y C entre otros) supone. además un
conjunto de técnicas que permiten desarrollar programa fáciles de escribir,
verificar, leer y mantener. La naturaleza de todos ellos es procedural, es decir, está
basada en procedimientos que hacen algo concreto, como escribir un mensaje en
pantalla, obtener datos desde el teclado o ejecutar un proceso algorítmico, de forma
que un programa puede incorporar fácilmente cientos de procedimientos
individuales. En otros capítulos, nos extenderemos sobre esta variedad de técnicas
de programación, limitémonos ahora, a añadir la llamada programación orientada
a objetos, cuyos programas se construyen ensamblando partes denominadas
objetos, que es un tipo especial de dato, en un intento de emular el mundo real, que
se compone de objetos que interaccionan entre sí. La programación orientada a
objetos presenta ventajas importantes, pero sus conceptos no son fáciles y en
ningún caso accesibles, sin un buen dominio de la programación estructurada.
Ante la actual babel de lenguajes de programación, el objetivo de este libro es ser
compatible con la mayor parte de los procedurales, sin tomar partido por ninguno
en particular, (es en otros textos y cursos donde se debe aprender a dominar algún
lenguaje de programación específico). No obstante, como ejemplos significativos,
CONCEPTO DE COMPUTADOR
29
(desde la doble óptica de los años noventa y de unos estudios de ciencias e
ingeniería), vamos a tratar de rastrear, en la medida de lo posible, cuatro de los más
populares lenguajes, (alguno de los cuales debe de ser aprendido en paralelo con
este curso), que por orden cronológico son:
FORTRAN. Pasa por ser el primer lenguaje de alto nivel que contó con un
compilador eficiente. Su propio nombre, acronismo de “FORmula TRANslation”,
señala que fue diseñado con el objetivo de ser utilizado para calculo científico.
Desarrollado en 1957 por un pionero de la informática John Backus y un equipo de
científicos de IBM, su primera estandarización data de 1966 y desde entonces han
aparecido dos mejoras sustantivas en 1977 y 1990.
Aunque su panorámica se reduce casi exclusivamente al calculo científico y
técnico, es tal la cantidad de software escrito en este veterano lenguaje, que su uso
en los ambientes de calculo intensivo esta muy extendido y es difícil hacer un
pronóstico acerca de su sustitución por otros lenguajes de alto nivel más
sofisticados.
BASIC. Fue desarrollado en 1964 por John Kemeny y Thomas Kurtz en el
Darmouth College, comenzó siendo una herramienta para enseñar programación
como indica su acronismo (Beginners All-purpose Symbolic Instruction Code). Su
simplicidad le hizo especialmente popular, siendo el primer lenguaje de alto nivel
que se utilizó con la aparición de los primeros ordenadores personales, incluso
anteriores al primer PC de IBM . Existen versiones del Basic especialmente
potentes y accesibles como Turbo-Basic, Quick-Basic, GW-Basic y Visual-Basic
(que ya incorpora alguna de las características y métodos orientados a objetos).
A pesar de su popularidad, el BASIC no ha cuajado completamente a nivel
científico y profesional, ya que no tiene un gran repertorio de herramientas y sus
compiladores no producen archivos ejecutables que sean tan compactos, veloces y
eficientes como los producidos por otros lenguajes. Sin embargo, su simplicidad,
puede llegar a satisfacer las necesidades de muchos usuarios.
PASCAL. Desarrollado por el suizo Niklaus Wirth en 1971, en honor del sabio
francés del siglo XVII del mismo nombre, es el primer lenguaje específicamente
pensado para la programación estructurada. Sus puntos más interesantes son sus
impecables medios para revisar el tipo de datos y para controlar el flujo de
ejecución del programa. Son muchos los libros y cursos que lo utilizan como
lenguaje de primera elección para aprender programación estructurada. Como no
podía ser menos, existen muchas extensiones de PASCAL y en particular las
últimas, orientadas a objetos. Los puntos negativos para los profesionales de la
programación hay que buscarlos en su filosofía excesivamente académica, lo que
conduce a hacerlo un poco tedioso.
C y C++. El lenguaje C está considerado una especie de pura sangre por muchos
programadores, ya que los programas escritos en C producen un código ejecutable
30
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
especialmente veloz y eficiente, pues con él la máquina puede hacer casi todo lo
que su hardware le permite realizar. Fue desarrollado por Brian Kernighan y
Dennis Ritchie a principios de la década de los 70 en los Laboratorios Bell; el
segundo de sus autores tiene también la importante paternidad del sistema
operativo UNIX. De hecho C y UNIX están íntimamente ligados ya que el código
fuente C se puede trasladar de una máquina UNIX a otra. El costo de un lenguaje
tan útil reside en que no es de los de más fácil aprendizaje, lo que puede llevar a
cierto grado de desmoralización a los principiantes, que deben superar rápidamente
este estado de ánimo.
A principios de los 80, otro científico de los Laboratorios Bell, Bjarne Stroustrup,
introdujo la orientación a objetos en C. El resultado fue un lenguaje poderoso y
eficiente pero no sencillo de aprender, cosa que sólo se puede hacer una vez
dominado el C. Hoy, a mitades de los noventa, el C++ aparece como un lenguaje
candidato a ser utilizado en muchas aplicaciones informáticas.
30805" GNGOGPVQU"DıUKEQU"FG"WP"NGPIWCLG"FG"CNVQ"PKXGN
Un programa consta de una sucesión de sentencias, escritas en lineas
sucesivas.Veámos cuales son los elementos que están presentes en cualquier
programa escrito en un lenguaje de programación de alto nivel.
Palabras reservadas: Conjunto de colecciones de caracteres con significado
especial, que el traductor del lenguaje interpreta según su significado. Estas
palabras, permitirán formar sentencias, tanto declarativas como imperativas. Cada
lenguaje tiene un conjunto de palabras reservadas. Veamos algunos ejemplos de
palabras reservadas tomadas de cada lenguaje:
FORTRAN
BASIC
PROGRAM, DATA
COMPLEX, IF
RCUECN
dim, step
loop, select
C
program, procedure
begin, end
main, switch
void, float
Constantes y Variables: Un programa contiene ciertos objetos o conjuntos de
datos que no deben cambiar durante su ejecución, estos valores se llaman
constantes, por contra una variable es un objeto o conjunto de datos cuyo valor
puede cambiar durante el desarrollo del algoritmo o la ejecución del programa. Las
variables tienen un nombre, conocido como identificador, que suele constar de
varios caracteres alfanuméricos de los cuales el primero normalmente es una letra.
Una variable por tanto se identifica por dos atributos: nombre y tipo Este último
CONCEPTO DE COMPUTADOR
31
define el conjunto de posibles valores que puede tomar la variable,a la vez que
determina el tipo de dato que soporta su correspondiente representación interna.
Expresiones: Combinaciones de constantes, variables, símbolos de operación,
caracteres especiales, etc., análogas a las utilizadas en notación matemática. Cada
expresión toma un valor que se determina tomando los valores de las variables y
constantes implicadas y la ejecución de las operaciones indicadas. Una expresión
consta de operandos y operadores. Según sea el tipo de objetos que manipulan,
pueden ser:
- Aritméticas. Donde las variables y constantes son numéricas y las
operaciones son aritméticas, una vez ejecutadas, su valor numérico es:
Ej.: x + (b+5) + z * z
- Relacionales: Utiliza signos de comparación (<, >, =, etc.) con valores de
tipo numérico o carácter para producir un valor lógico (verdadero o falso),
Ej.: (A-2) < (B-4)
- Lógicas: Combina operadores lógicos (AND, OR, NOT) que operarán
sobre valores lógicos, de acuerdo con sus tablas de verdad.
Ej.: (A<B) OR (A>B)
- De Carácteres: Que involucra cadenas de caracteres alfanuméricos.
Ej.: Unión de dos cadenas.
Etiquetas: Ciertas instrucciones de un programa utilizan etiquetas para referirse a
una línea determinada de un programa, bien para realizar un salto a dicha línea,
bien porque dicha línea contiene información adicional para una instrucción. La
etiqueta puede tener un nombre (situado al principio de la línea que está
etiquetando) o ser simplemente el número de la línea en cuestión.
Comentarios: Con el único objetivo, de hacer más comprensible la lectura del
programa por parte de un humano, esta prevista la inclusión de comentarios a la
largo de su desarrollo, que hay que marcar debidamente, para que el ordenador las
ignore.
FORTRAN
BASIC
C comentario
* comentario
RCUECN
´ comentario
REM comentario
C
{comentario}
(*comentario*)
/* comentario */
// comentario en algunos C
32
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Asignación: Es la acción por la cual le damos (asignamos) valores a una variable,
la representaremos por el signo ←. Al escribir A←5 significamos que A toma el
valor de 5 como real. La acción de asignar es destructiva, ya que el posible valor
que tuviera la variable antes de la asignación se pierde y se reemplaza por el nuevo
valor. Se debe pensar en la variable como en una posición de memoria, cuyo
contenido puede variar mediante instrucciones de asignación (un símil es un
marcador -de un campo de fútbol-, donde su contenido variará según el
movimiento del partido; al poner un número en uno de los casilleros, desaparece el
que hubiera anteriormente). Puesto que cada variable tiene un tipo determinado ,se
entenderá que no se pueda (o no se deba) asignar valores a una variable de un tipo
diferente del suyo y así se presentará un error si se trata de asignar valores de tipo
carácter a una variable numérica o un valor numérico a una variable tipo carácter (¡
imaginemos que en nuestro marcador del campo de fútbol pusiéramos una letra A
en el casillero del tanteo del equipo local !).
El computador ejecuta la acción de asignar en dos pasos, en el primero de ellos, el
valor de la expresión al lado derecho del operador se calcula, obteniendo un valor
de un tipo específico. En el segundo paso este valor se almacena en la variable,
cuyo nombre aparece a la izquierda.
Veamos un ejemplo:
¿Cuál es el valor de las variables A, B y AUX antes y después de cada paso?
1.
2.
3.
4.
5.
6.
A ← 10
B ← 13 + 7
AUX ← A + 15
A←B
B←A+4
AUX ← AUX + 1
Antes de la ejecución de las instrucciones, el valor de A, B, y AUX es
indeterminado, es decir, el contenido de las posiciones de memoria
correspondientes a ellas es desconocido.
1. A toma el valor 10
2. se evalúa la expresión 13+7 y B toma el valor resultante, 20
3. se evalúa la expresión con el valor de A en ese momento (10) más 15, AUX
toma el valor 25 (A no se ve afectada)
4. A toma el valor de B en ese momento, o sea 20 (B no cambia)
5. se evalúa la expresión con el valor de A en ese momento (20), más 4, 24; B
toma el valor resultante 24 (A no se ve afectada)
CONCEPTO DE COMPUTADOR
33
6. se evalúa la expresión con el valor de AUX en ese momento (25) más 1;
AUX toma el valor resultante 26.
Nótese que la operación de asignación, pese a que en algunos lenguajes se exprese
con el signo = no es una igualdad matemática. Por ejemplo, la instrucción 4 del
ejemplo anterior escrita en lenguaje C sería:
A=B;
lo cual no quiere decir que a partir de ese momento A y B vayan a ser siempre
iguales. Igualmente, la instrucción 6 del ejemplo en lenguaje C
AUX=AUX+1;
tiene sentido como asignación, pero sería un completo contrasentido como
igualdad matemática.Veámos la asignación en los distintos lenguajes:
FORTRAN
BASIC
V=E
RCUECN
V=E
C
v := e
v = e
Entrada: Las acciones de entrada permiten obtener determinados valores a partir
de un periférico y asignarlos a determinadas variables. Esta entrada se conoce
como operación de lectura. Y se representa por el formato:
leer (lista de variables de entrada)
Por ejemplo, la instrucción:
leer NUMERO, HORAS, TASA.
Lee del terminal los valores NUMERO, HORAS y TASAS, almacenándolos en la
memoria; con la correspondiente acción de asignación a las tres variables. Si los
tres números que se teclean en respuesta a la instrucción son: 12325, 32,1200, y
equivale a la ejecución de las instrucciones.
NUMERO ← 12325
HORAS ← 32
TASA ← 1200
Veamos como se realiza la entrada por teclado en algunos lenguajes:
FORTRAN
BASIC
READ f, numero, horas, tasa
INPUT numero, horas, tasa
34
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
f: etiqueta de formato
(* = formato libre)
RCUECN
C
readln(numero, horas, tasa)
scanf(“%d %d %d”, &numero,
&horas, &tasa)
Salida: Las acciones de salida, permiten transferir a un periférico los resultados
obtenidos por el computador. Esta operación se conoce como escritura y se
representa por el siguiente formato:
escribir (lista de variables de salida)
Como ejemplo, veamos el resultado de la ejecución de las siguientes instrucciones:
A ← 100
B ← 200
C ← 300
escribir A, B, C
Se visualizarán en pantalla o imprimirán en impresora los valores 100, 200 y 300
Veámos como se realiza la salida por pantalla en algunos lenguajes:
FORTRAN
BASIC
WRITE f, numero, horas, tasa
PRINT f, numero, horas, tasa
f: etiqueta de formato
(* = formato libre)
PRINT numero, horas, tasa
RCUECN
C
writeln(numero, horas, tasa)
printf(“%d %d
horas,tasa)
%d”,numero,
30806" QTICPK\CEKłP"FG"WP"RTQITCOC
Un programa escrito en un lenguaje procedural de alto nivel consta de un
encabezamiento (opcional en algunos lenguajes) donde se indica información
general del programa, tal como su nombre y algunas circunstancias que el traductor
debe saber, y un cuerpo, donde se desarrolla el programa. En el cuerpo,
primeramente debe hacerse la declaración de variables por la cual se indica que
CONCEPTO DE COMPUTADOR
35
variables van a emplearse en el subprograma y cual es el nombre y el tipo de cada
una de ellas. A continuación aparecen las sentencias imperativas que, por medio de
las variables que hayamos declarado representan el algoritmo.
La estructura general que se espera que adopte un programa, es la siguiente:
Identificador del programa o módulo
{sección de declaraciones}
inicio
{datos de entrada}
{sentencias imperativas, que ejecutan el algoritmo correspondiente}
{datos de salida}
fin
Aunque es ligeramente prematuro, el lector deberá ser capaz de seguir sin
dificultad la organización de los programas resultantes de codificar el problema de
hallar el volumen de un cilindro a partir de su radio y altura en los cuatro lenguajes
utilizados.
FORTRAN
BASIC
PROGRAM volcilin
C Hallar volumen de un cilindro
REAL radio, altura, volumen
DATA PI /3.14.16/
READ radio,altura
volumen=PI*radio*radio*altura
WRITE volumen
END
REM radio, altura, volumen
REM si no se declaran son SINGLE
PRINT “Radio y altura : ”
INPUT radio, altura
volumen=3.1416* radio^2 *altura
PRINT “el volumen es”;volumen
END
RCUECN
C
program volcilin(input,output);
const PI = 3.1416;
(*Hallar volumen de un cilindro *)
var radio, altura, volumen: real;
begin
write(“Radio y altura : “);
readln(radio, altura);
volumen=PI*radio*radio*altura;
writeln(“el volumen es”,volumen);
end.
#include <stdio.h>
#define PI 3.1416
/*Hallar volumen del cilindro */
main(){
float,radio, altura, volumen;
printf(“Radio y altura : “);
scanf(“%f%f”,&radio, &altura);
volumen=PI*radio*radio*altura;
printf(“volumen=%d\n”,volumen);
}
30807" VTCFWEEKłP"FG"RTQITCOCU
36
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Una vez escrito un programa en lenguaje de alto nivel, para lo que se habrá
empleado un editor de texto, tenemos lo que se llama un programa fuente. Para
poderlo ejecutar, debemos recurrir a un programa traductor, que lo convierta en
lenguaje máquina. Aunque el proceso de traducción puede hacerse de varias
formas, lo más frecuente es hacerlo por medio de un compilador. Un compilador
es un programa que traduce en su totalidad un programa fuente, escrito en un
lenguaje de alto nivel, a un programa objeto, escrito en lenguaje máquina.
Una vez obtenido el programa objeto, raramente puede ejecutarse por sí mismo,
pues habitualmente presenta algunos cabos sin atar, que deben conectarse a otros
programas del sistema para poder ejecutarse. Esta tarea corre a cargo a su vez de un
programa llamado montador (linker) que genera el llamado programa ejecutable.
Finalmente hay que introducir la totalidad del programa en la memoria. De esta
tarea, se encarga un programa denominado cargador (loader) que sitúa las
instrucciones en posiciones consecutivas de la memoria principal a partir de una
determinada posición (con lo que tenemos el concepto ya conocido de programa
almacenado) El proceso completo desde el código fuente hasta el programa
almacenado se muestra en la Figura 1.11.
Programa
Fuente
Compilacion
Fig. 1.11.
Programa
Objeto
Montaje
Programa
Ejecutable
Carga
Programa
Almacenado en
memoria
Preparación de un programa para su ejecución
Las distintas versiones del programa (fuente, objeto y ejecutable), se suelen
guardar en archivos, en un dispositivo de almacenamiento masivo, para ser usado
posteriormente sin necesidad de volver a realizar la traducción. Por ello se habla de
archivos fuente, archivos objeto y archivos ejecutables. Si queremos ejecutar un
programa y disponemos de su archivo ejecutable, en la mayoría de casos será
suficiente con escribir su nombre: el programa se cargará en la memoria como
programa almacenado y podrá empezar a ejecutarse, sin necesidad de pasar por la
compilación y el montaje.
3090" UKUVGOC"QRGTCVKXQ"["RTQITCOCU"FGN"UKUVGOC
A medida que maduraba la programación, se vió lo ventajoso de reutilizar
programas, se comenzó a almacenar programas o subprogramas cuya utilización es
frecuente y básica para el trabajo del ordenador, (ej: los programas relacionados
con la gestión de los distintos tipos de periféricos). Este fue el germen de los
CONCEPTO DE COMPUTADOR
37
primeros sistemas operativos: programas que gestionan las funciones básicas del
computador, simplificando la tarea del programador que puede soslayar ciertos
detalles de la máquina que quedan a cargo del sistema operativo. Hoy en día sería
imposible o extremadamente difícil utilizar un computador sin disponer de un
sistema operativo (S.O.).
Los sistemas operativos son programas que gestionan los recursos de un
computador en beneficio de los programas que se ejecutan en esa máquina. Un
sistema operativo es en sí mismo un programa, pero forma parte integral de la
máquina y es tan importante conocerlo como conocer sus componentes físicos.
Sus tareas principales son:
- Proporcionar al usuario una interfaz que le permita comunicarse con el
computador.
- Administrar los dispositivos de hardware del computador
- Administrar y mantener los sistemas de archivo de disco.
- Dar soporte a otros programas y a los programadores aislando los detalles
físicos
Cuando se enciende un computador, éste ejecuta primero una autoprueba para
identificar los dispositivos que tiene conectados, contar la cantidad de memoria
disponible y hacer una rápida comprobación de la misma. A continuación, busca un
sistema operativo que le indique como interactuar con el usuario y como usar los
dispositivos. Cuando lo encuentra lo carga en memoria y mantendrá parte del
mismo en su memoria hasta que se apague el computador.
Junto al sistema operativo hay un conjunto de programas conocidos como
programas del sistema necesarios para el funcionamiento habitual de la máquina
(algunos de estos programas se suministran con el sistema operativo y en ocasiones
se consideran parte integrante del mismo). El software del sistema está constituido,
además del sistema operativo, por:
- Utilidades generales de programación, que contiene programas o utilidades que
facilitan la construcción de las aplicaciones de los usuarios, sea cual sea la
naturaleza de éstas. Incluye herramientas tales como:
- Traductores (ensambladores, compiladores, etc.).
- Editores de textos
- Rastreadores/depuradores de errores de programación.
- Sistemas de Gestión de archivos
- Administrador de bibliotecas de programas.
- etc.
- Programas de diagnóstico, generación y mantenimiento. Que utilizan los
responsables del mantenimiento y puesta al día del hardware y del software
(incluida la generación y mantenimiento del propio SO). Con estos programas se
38
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
pretende por ejemplo localizar automáticamente las averías de un determinado
dispositivo ó circuito, ó las causas de un mal funcionamiento de algún modulo del
SO.
30:0" VKRQU"FG"EQORWVCFQTGU
Hoy en día existe una gran variedad de computadores de uso general, que
varían en tamaño capacidad y rendimiento. La propia evolución tecnológica
dificulta la clasificación de los diferentes tipos de computadores, aunque se siguen
distinguiendo una serie de grandes familias:
SUPERCOMPUTADORES. Un supercomputador es el computador más potente
disponible en un momento dado. Formado por procesadores múltiples, trabajan en
paralelo accediendo a memorias de grandes dimensiones. Para el control de la
entrada/salida de datos y de los canales de comunicaciones externos utilizan
procesadores especiales, puesto que los requisitos de velocidad son muy elevados
(los llamados front-end). Se suelen utilizar para efectuar cálculos complejos que
requieren grandes cantidades de datos, tal como ocurre en astronomía, predicción
meteorológica y en la simulación y modelado de procesos hidrodinámicos,
aerodinámicos, químicos y biológicos.
MACROCOMPUTADORES (mainframes). Son los ordenadores más potentes de
uso común en aplicaciones comerciales. Están formados por grandes unidades
independientes, con distintos procesadores centrales y otros procesadores que
controlan la entrada/salida, los medios de almacenamiento masivo y los canales de
comunicación de datos, provenientes de un gran número de terminales. Los
mainframe permiten el trabajo concurrente de un gran numero de aplicaciones y
usuarios, siendo su papel, ser el centro de sistemas transaccionales, tales como los
que necesitan bancos, compañías aéreas, organismos de la administración, etc.
SISTEMAS DE TAMAÑO MEDIO (minicomputadores). Se enmarcan, en un nivel
intermedio entre los macrocomputadores y los computadores personales: Suelen
disponer de varios módulos de proceso y de unidades de entrada/salida, que
trabajan en paralelo, todos ellos montados en un bastidor central. Pueden soportar
varias aplicaciones simultáneas, proporcionando servicio a varios usuarios,
pudiendo hacer de enlace de información con otros sistemas de información
remotos. Son computadores adecuados para laboratorios, control de la producción
y organizaciones administrativas de tamaño medio; aunque cada vez están más en
competencia con sistemas de menor coste.
ESTACIONES DE TRABAJO. Son sistemas pensados para ser utilizado por un
solo usuario, basados en microprocesadores muy potentes y dotados de gran
CONCEPTO DE COMPUTADOR
39
capacidad de memoria, diseñados desde el principio para soportar sistemas
operativos capaces de ejecutar más de un programa de forma simultánea. Suelen
estar conectados entre si, compartiendo recursos potentes como discos duros de alta
velocidad, impresoras, y vías de comunicación con el exterior. Son especialmente
adecuadas para diseño asistido por computador, cálculo científico y aplicaciones
gráficas de alta resolución. Sin embargo, con la actual evolución, parece que en el
futuro, tendremos dificultades para distinguir entre una estación de trabajo y un
computador personal.
COMPUTADORES PERSONALES. Diseñados inicialmente para trebajar de
forma aislada e individual, han evolucionado de forma extraordinaria en
prestaciones y reducción de costes. También llamados microcomputadores, son los
ordenadores más difundidos, pudiéndose encontrar comúnmente tanto en oficinas y
laboratorios como en aulas y hogares. La gama de aplicaciones que puede ejecutar
es enorme y cada día penetra más en actividades básicas de nuestra vida cotidiana.
La posibilidad de trabajar en red, incrementa sus prestaciones sin que pueda
saberse con exactitud cuál es su futuro, sus dos representantes son los PC
compatibles y los Apple.
CALCULADORAS DE BOLSILLO (calculadoras programables). Con el aspecto
tradicional de una calculador digital, incorporan las unidades funcionales que
constituyen todo computador; con un teclado elemental para introducir datos y un
sistema de presentación de una o pocas líneas, cada vez incluyen más cantidad de
memoria, más posibilidades de programación y posibilidades de comunicación, con
ordenadores próximos o lejanos. Su evolución es difícil de prever, al desaparecer
las diferencias con los computadores personales portátiles.
30;0" EQOWPKECEKłP"FG"FCVQU"["TGFGU
La posibilidad de interconectar computadoras brinda tantos beneficios que
se ha convertido en una de las áreas con mayor crecimiento en la actualidad. A
medida que las máquinas se dispersan, su interconexión es más deseable (a mayor
numero de usuarios con máquina propia, se incrementa la necesidad de
interconectarlas). Cuando tenemos un conjunto de ordenadores conectados entre si,
decimos que forman una red informática. Con ello, la comunicación de datos y la
transferencia electrónica de información, se ha convertido en un tema básico.
30;03" VTCPUOKUKłP"FG"FCVQU"FGPVTQ"FGN"EQORWVCFQT
Antes de seguir con temas de comunicación, hay que resaltar, que
cualquier tipo de transmisión de datos a larga distancia, funcionalmente, no debe
40
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
diferir de otras comunicaciones de datos, que se dan en el funcionamiento habitual
del ordenador; tales como las que se producen dentro de los propios circuitos
integrados (cuyo orden de magnitud es el mm) o las que se tienen lugar en una
misma tarjeta, a través de los buses, entre procesador y memoria (del orden de
cms).
Incluso, tenemos conexiones de mayor longitud, en la comunicación entre el
procesador y sus periféricos, que habitualmente requieren un soporte físico distinto,
en forma de cables del orden de las decenas de centímetros. Estos cables constan de
varios hilos, entonces se esta en condiciones de transmitir varios bits
simultáneamente, uno por hilo, que ya definimos como transmisión de datos en
paralelo, cuando hablamos de buses. Sin embargo cuando los datos tienen que
transmitirse a cierta distancia, el uso de este tipo de cable resulta inviable; entonces
se utiliza un conductor único. En estas circunstancias se transmiten los datos bit a
bit, lo que se denomina transmisión de datos en serie.
Las distintas posibilidades de intercomunicación implican que los dos soportes del
computador (el físico y el lógico) tengan que adaptarse, a nuevos equipos y a
procedimientos preestablecidos. Dados dos componentes, conectados entre si,
llamaremos Interfaz, al conjunto de informaciones y equipos utilizadas para
interconectarlos, que nos indican las secuencias de operaciones permitidas entre
ellos y Protocolo, al conjunto de reglas y de procedimientos que permiten que
desde uno de los componentes y a través de las interfaces respectivas, que el otro
componente realice correctamente una función determinada. Por tanto las
interfaces y protocolos especifican la forma de interconectar dos o más
componentes de un sistema informático. Dado que hay dos tipos de transmisión,
serie y paralelo, existen estas mismas dos clases genéricas de interfaces: y en cada
uno de ellos se distinguen distintos tipos. En la Figura 1.12. se puede ver un
ejemplo de un interfaz paralelo (tipo centronics) comúnmente utilizado para
conectar un computador a una impresora.
Fig. 1.12.
Ejemplo de una conexión paralelo (tipo centronics)
CONCEPTO DE COMPUTADOR
41
30;04" EQOWPKECEKłP"FG"FCVQU"C"NCTIC"FKUVCPEKC
Para llevar a cabo la comunicación entre dispositivos informáticos, se
necesita un medio físico por donde transmitir las señales eléctricas, que van desde
el simple es el par de cables trenzados hasta la fibra óptica, además de la
posibilidad de conexión inalámbrica, a través de enlaces vía radio y vía satélite.
Para transmisiones del orden de kilómetros, lo más común, es recurrir a la red
telefónica ya existente, que está pensada para transmitir voz, por lo que su rango de
frecuencias, de 300 a 3400 Hz, no la hace totalmente adecuada para la transmisión
digital.
Para poder transmitir datos mediante la red telefónica, debemos recurrir a una señal
analógica, que codifique de cierta manera, los diferentes valores discretos, que
caracterizan la información digital. Este proceso se lleva a cabo por un dispositivo
llamado modem (que toma su nombre de la expresión modulador/demodulador).
Los modems se conectan a la red telefónica de forma que se pueden utilizar la
infraestructura de la misma, incluidas las conexiones celulares, de los teléfonos
portátiles, para intercambiar información. Las velocidades de transmisión de datos
varían considerablemente, dependiendo de las aplicaciones y el medio de
comunicación. La unidad de medida del ritmo de transmisión de datos es el
baudio. cuya definición precisa es realmente complicada, pero puede considerarse
para propósitos prácticos como la velocidad de transmisión (bit/seg).
La necesidad de interconectar dispositivos separados por grandes distancias, ha
propiciado la aparición de una nueva disciplina técnica la Telemática, como rama
interdisciplinar entre la Informática y las Telecomunicaciones, que versa sobre la
utilización de equipos informáticos interconectados a través de líneas o redes de
telecomunicación, bien sea periférico-computador, o computador-computador.
Cuando introducimos estos nuevos elementos, aparecen una serie de nuevos
factores que no se apreciaban en el tipo de interconexión que define el bus: el
medio de transmisión -que va a requerir un tipo de circuitería especial y la
aparición de nuevos errores de transmisión, debidos a la larga distancia y que no se
dan en el interior del ordenador. Será de nuevo, tarea de la interfaz y del protocolo
correspondiente, el establecer entre las máquinas, el convenio de transmisión de
datos (piénsese que en una máquina una palabra puede ser de 1 byte y en otra de
dos), la sincronización entre ambas, la velocidad de transmisión, la comprobación
de errores de transmisión, etc.
Con independencia del medio de comunicación entre dispositivos, analógico o
digital, aparece la cuestión de gestionar la intercomunicación de múltiples y
diferentes sistemas informáticos (networking en inglés), de forma que los distintos
recursos puedan ser compartidos y utilizados de forma remota. En el caso de que
estos recursos estén situados en un mismo edificio o en edificios próximos,
42
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
hablaremos de una LAN (Local Area Network), mientras que si hablamos de áreas
geográficas de mayores dimensiones nos referiremos a WAN (Wide Area
Network).
30;05" TGFGU"FG"QTFGPCFQTGU
Entenderemos como red una manera de interconectar ordenadores de tal
forma que cada uno de ellos sea consciente de esta circunstancia y de los recursos
que puede compartir. La red viene a superar la utilización por múltiples usuarios de
una misma máquina, habida cuenta que resulta mucho más funcional y económico,
el dotar a cada usuario de su propio computador y conectarlos entre si, que poner
en servicio complicados sistemas operativos que resuelvan este mismo problema.
Las redes, en principio, consiguen aumentar la relación prestación/coste,
proporcionando las siguientes posibilidades:
• Aumentar la seguridad (fiabilidad) del sistema (si una computadora de la
red falla, se puede utilizar otra de la misma red).
• Si el equipo local, al que se tiene acceso directo, no dispone de las
prestaciones adecuadas (poca memoria, está muy cargado de trabajo, no
dispone de impresoras rápidas, etc.), el usuario puede conectarse a otro
equipo de la red que reúna las características pertinentes y utilizar sus
recursos o repartir su tarea entre varias máquinas.
• Un servicio remoto para la utilización de aplicaciones, sin necesidad de
que el usuario disponga realmente de ellas.
• Permitir el acceso a bancos de datos ubicados a grandes distancias.
• Posibilitan la existencia de sistemas de control industrial constituidos, por
ejemplo, por varias computadoras de uso específico de una fábrica,
interconectadas entre sí.
• Utilización de la red de computadoras como medio de comunicación:
correo electrónico.
• etc.
CONCEPTO DE COMPUTADOR
43
1.1. UNA PRIMERA APROXIMACIÓN AL COMPUTADOR ........................1
1.1.1 OPERACIONES BÁSICAS DEL PROCESADO DE DATOS ......................2
1.1.2 ALGORITMOS Y PROGRAMAS ..................................................................3
1.2. ANTECEDENTES HISTÓRICOS .................................................................4
1.3. ORGANIZACIÓN DE UN COMPUTADOR................................................9
1.3.1 LA ARQUITECTURA DE VON NEUMANN ...............................................9
1.3.2 UNIDADES FUNCIONALES.......................................................................10
1.4. EL CONCEPTO DE PROGRAMA ALMACENADO ...............................16
1.4.1 TIPOS DE INSTRUCCIONES......................................................................16
1.4.2 LENGUAJE MÁQUINA Y LENGUAJE ENSAMBLADOR.......................18
1.4.3 EJECUCIÓN DE UN PROGRAMA .............................................................19
1.5. CONCEPTO ACTUAL DEL COMPUTADOR..........................................23
1.5.1 DEFINICIÓN ACTUAL................................................................................23
1.5.2 PARÁMETROS BÁSICOS DE LA MÁQUINA ..........................................24
1.6. DEL COMPUTADOR A LA PROGRAMACIÓN .....................................26
1.6.1 LOS DATOS..................................................................................................26
1.6.2 LENGUAJES DE PROGRAMACIÓN DE ALTO NIVEL...........................27
1.6.3 ELEMENTOS BÁSICOS DE UN LENGUAJE DE ALTO NIVEL .............30
1.6.4 ORGANIZACIÓN DE UN PROGRAMA.....................................................34
1.6.5 TRADUCCIÓN DE PROGRAMAS..............................................................35
1.7. SISTEMA OPERATIVO Y PROGRAMAS DEL SISTEMA....................36
1.8. TIPOS DE COMPUTADORES ....................................................................38
1.9. COMUNICACIÓN DE DATOS Y REDES .................................................39
1.9.1 TRANSMISIÓN DE DATOS DENTRO DEL COMPUTADOR .................39
1.9.2 COMUNICACIÓN DE DATOS A LARGA DISTANCIA...........................41
1.9.3 REDES DE ORDENADORES ......................................................................42
CAPÍTULO 2
SOPORTE LÓGICO DE UN COMPUTADOR
En el capítulo anterior distinguimos soporte lógico, de soporte físico a la hora de
definir los distintos componentes de un computador. En este capítulo vamos a
profundizar y a desarrollar el primero de ellos, cuyo conocimiento será
imprescindible para poder proceder al proceso de programación. Muchos de los
conceptos desarrollados en este capítulo se deberán confrontar frente al
computador donde se valorará su utilidad.
Un mayor desarrollo de los elementos del soporte físico del ordenador están fuera
de la óptica de este libro, que trata de enfocar prioritariamente los fundamentos de
programación. Sin embargo, existe un gran número de conceptos relacionados con
el hardware que no deberían ser ignorados por el estudiante. Por esta razón hemos
incluido al final del texto un apéndice que describe los elementos más
representativos del hardware actual, a cuyo contenido podrá recurrir el lector si lo
considera necesario.
4030" EQPEGRVQ"FG"UQRQTVG"NłIKEQ
El soporte lógico o software de un ordenador es el conjunto de programas
que permiten realizar las tareas asignadas a la máquina. En este concepto
incluimos, tanto los programas suministrados en el momento de adquisición del
ordenador, como los adquiridos a empresas de desarrollo y venta de programas y
los escritos por los propios usuarios. El soporte lógico, según sea el nivel de trabajo
de cada programa, se suele clasificar en software del sistema (necesario para
administrar y mantener los recursos del ordenador de una forma eficiente) y
software de aplicación (que corresponde a las aplicaciones específicas que utilizan
los recursos del ordenador).
El software del sistema está constituido por:
45
46
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
* Programa de Arranque, es el primer programa que se ejecuta cuando
arranca la máquina. Comprueba los dispositivos del ordenador y carga en
memoria al Sistema Operativo.
* Sistema Operativo (SO) conjunto de programas que controlan y supervisan
el uso de los recursos del ordenador.
* Programas de diagnóstico, generación y mantenimiento. Son utilizados por
los responsables del mantenimiento y puesta al día del hardware y del software
(incluida la generación y mantenimiento del propio SO). Con estos programas
se pretende por ejemplo localizar automáticamente las averías de un
determinado dispositivo o circuito, o las causas de un mal funcionamiento de
algún modulo del SO.
* Utilidades generales y Herramientas de programación que contienen
programas o ayudas que facilitan la construcción o el uso de las aplicaciones,
sea cual sea la naturaleza de éstas. Incluye herramientas tales como:
- Traductores (ensambladores, compiladores e interpretes).
- Editores de textos.
- Rastreadores / depuradores de errores de programación.
- Gestores de archivos.
- Administradores de bibliotecas de programas.
Por su parte el software de aplicación es de difícil clasificación, habida cuenta de la
diversidad de campos donde se utiliza la informática. Una relación parcial de este
tipo de software podría ser:
- Procesadores de texto.
- Bibliotecas matemáticas y estadísticas.
- Hojas de cálculo.
- Sistemas de gestión de archivo y de Bases de Datos.
- Agenda Electrónica.
- Correo Electrónico.
- Aplicaciones Gráficas.
- CAD/CAM (Computer Aided Design/ Manufacturing).
- Gestión de comunicaciones.
- Programas escritos por los usuarios.
Diferenciar si ciertos programas de utilidades son software del sistema o software
de aplicación es difícil. Así en principio el SO proporciona todos las características
necesarias para el funcionamiento del sistema, sin embargo a veces no alcanzan a
cumplir las necesidades del usuario o no es de fácil manejo. Estas deficiencias del
SO se cubren mediante las llamadas utilidades, que se desarrollan posteriormente.
Algunas de estas utilidades adquieren gran popularidad y las versiones posteriores
SOPORTE LÓGICO DE UN COMPUTADOR
47
del SO las van incorporando. La rápida evolución del software hace que muchos de
estos programas de utilidades pasen de ser aplicaciones a ser software básico.
4040" C[WFCU"RCTC"NC"RTQITCOCEKłP
40403" VTCFWEVQTGU
Como vimos en el primer capítulo, un programa escrito en un lenguaje de
alto nivel debe ser traducido para que lo pueda ejecutar el computador. Cada
traductor de programas es específico de cada tipo de computador y ‘entiende’ un
lenguaje determinado. La transportabilidad de un programa consiste en que un
mismo programa escrito en un lenguaje pueda ser entendido por traductores de ese
lenguaje para distintos computadores.
No obstante debe tenerse en cuenta que existen muchos “dialectos”, siendo
necesario con frecuencia adaptar partes de los programas escritos en un dialecto de
un lenguaje para pasarlos de una computadora a otra. Existen lenguajes
prácticamente “independientes de la computadora” que están normalizados por
organismos como el “American National Standars Institute” (ANSI), con el
objetivo de garantizar la transportabilidad de los programas (ANSI FORTRAN,
ANSI C, etc.).
Para la traducción de los lenguajes de alto nivel, se utilizan los mismos métodos
que nosotros usamos cuando tratamos de entender una conferencia expresada en un
idioma que desconocemos: una opción es que alguien nos traduzca el contenido
completo de la misma una vez concluida, otra es que alguien efectúe una
traducción simultánea (frase a frase). Similarmente, según sea su forma de trabajar,
existen dos tipos de traductores de programas: los compiladores y los intérpretes.
2.2.1.1" COMPILADORES
Un compilador traduce en su totalidad un programa fuente, escrito en un
lenguaje de alto nivel, a un programa objeto, escrito en lenguaje máquina. El
programa fuente suele estar contenido en un archivo, y el programa objeto puede
almacenarse como otro archivo en un dispositivo de almacenamiento masivo para
ser procesado posteriormente, sin necesidad de volver a realizar la traducción.
La traducción por un compilador (la compilación) consta de dos etapas
fundamentales: Análisis del programa fuente (tanto lexicográfico como gramatical,
llamado también parsing) y Síntesis del programa objeto.
48
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Análisis
lexico
Parsing
Generación
del
código
Programa
fuente
Programa
objeto
Fig. 2.1.
Etapas de la compilación
Como todo programa complejo, los compiladores estas diseñados modularmente,
de forma que las distintas etapas del proceso de compilación, a su vez, se
descomponen en varias fases o módulos, cada una de las cuales puede implicar el
recorrer completamente el programa fuente. Vamos a describir brevemente la
funcionalidad de cada uno de estos módulos o fases:
a) Análisis lexicográfico.Consiste en descomponer el programa fuente en sus elementos
constituyentes o símbolos: palabras reservadas, símbolos de operadores,
identificadores constantes, comentarios, blancos, etc. Así por ejemplo los símbolos
constitutivos de la sentencia:
A=(C+D) * 17
son:
operadores: = ( ) + *
variables: A C D
constantes: 17
b) Análisis sintáctico.
Es la primera parte del análisis gramatical y tiene como misión identificar
las estructuras (expresiones, sentencias declarativas, asignaciones, etc.) del
programa. La sintaxis de un lenguaje de programación especifica cómo debe
escribirse un programa, mediante las reglas correspondientes. Por ejemplo, es
sintácticamente incorrecta la sentencia:
A+B= (C-D)* 17
ya que el signo “=“ no tiene el sentido que se le da en matemáticas (para formar
ecuaciones). En los lenguajes citados dicho signo se utiliza para asignar a una
variable (no a una expresión aritmética) el resultado de evaluar una expresión (la
que está a la derecha del signo igual). Es correcto sintácticamente escribir:
A=(C-D) * 17
(“Calcular (C-D) x17, y el valor que resulte asignárselo a la variable A”).
SOPORTE LÓGICO DE UN COMPUTADOR
49
c) Análisis semántico.
La semántica de un lenguaje de programación es el significado dado a las
distintas construcciones sintácticas. Por ejemplo, asignar a una variable definida
como dato numérico, el valor de una cadena de caracteres, es semánticamente
incorrecto para algunos compiladores y si se detecta una circunstancia de este tipo,
debe señalarse el error correspondiente.
d) Optimización.
En las fases de optimización se mejora el código intermedio analizándose
el programa globalmente. Un programa, por ejemplo (ver Figura 2.2.a) puede
incluir dentro de un bucle, que debe ejecutarse diez mil veces, una sentencia que
asigna a una variable un valor constante (B= 7,5), no alterándose dicho valor (B)
dentro del bucle. Con ello, innecesariamente se asignaría el valor 7,5 a la variable
B diez mil veces. El optimizador sacaría la sentencia B= 7,5, fuera (antes) del
bucle, ejecutándose así dicha instrucción una sola vez (ver Figura 2.2.b) . Hay que
hacer notar que el programa inicial es correcto (con B=7,5 dentro del bucle los
resultados del programa son los mismos), pero la optimización realizada por el
compilador reduce el tiempo de ejecución.
Desde I = 1 hasta I = 10 000
R= 37.-I*35
B=7,5
Z= B-SIN (-R/35000)
fin hacer
(a)
Fig. 2.2.
B=7.5
Desde I = 1 hasta I=10.000
R=37.-I*35
Z=B-SIN(-R/35000)
fin hacer
(b)
Ejemplo de optimización de un bucle
e) Generación de código.En esta etapa se genera el código objeto definitivo. El archivo objeto
generado puede ser (dependiendo del compilador) directamente ejecutable, o
necesitar otros pasos previos a la ejecución, tales como ensamblado, encadenado y
carga. Un programa objeto no es todavía ejecutable en la mayoría de los casos ya
que es necesario incorporarle las llamadas a funciones estándar, que residen en
bibliotecas de programas. Este proceso se llama encadenado (link) y tras él sí se
consigue el código ejecutable.
La compilación es un proceso complejo que consume a veces un tiempo muy
superior a la propia ejecución del programa. En cualquiera de las fases de análisis,
el compilador puede dar mensajes sobre los errores que detecta en el programa
50
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
fuente, cancelando en ocasiones, la compilación para que el usuario realice en el
archivo fuente las correcciones oportunas.
2.2.1.2" INTÉRPRETES
Una alternativa a la compilación, la cual sólo produce una traducción a
lenguaje máquina del programa fuente, es la interpretación que ejecuta el programa
directamente desde el programa fuente (Ver Figura 2.3)
Un intérprete hace que un programa fuente escrito en un lenguaje vaya, sentencia
a sentencia, traduciéndose y ejecutándose directamente por la computadora. El
intérprete capta una sentencia fuente, la analiza e interpreta dando lugar a su
ejecución inmediata, no creándose, por tanto, un archivo o programa objeto
almacenable en memoria masiva para ulteriores ejecuciones.
Programa compilado
Programa
fuente
Compilación
Programa
objeto
Programa interpretado
Programa
fuente
Fig. 2.3.
Programa ejecutado
por la máquina mediante
el uso de un intérprete
Compilación e Interpretación
En la práctica el usuario crea un archivo con el programa fuente (esto suele
realizarse con un editor específico del propio intérprete del lenguaje). Según se van
almacenando las instrucciones simbólicas, éstas se analizan y se generan los
mensajes de error a que dieran lugar; así el usuario puede proceder inmediatamente
a su corrección. Una vez creado el archivo fuente, el usuario puede dar la orden de
ejecución y el intérprete lo ejecuta línea a línea. El análisis siempre antecede
inmediatamente a la ejecución, de forma que:
a) Si una sentencia forma parte de un bucle, se analiza tantas veces como tenga
que ejecutarse el bucle. Si el programa de la figura 2.2 a) fuese traducido por un
SOPORTE LÓGICO DE UN COMPUTADOR
51
intérprete, la sentencia R=37.-I*35, se analizaría 10 000 veces, y no sólo una
vez, como ocurría en un compilador.
b) Las optimizaciones sólo se hacen dentro del contexto de cada sentencia, y no
contemplándose el programa o sus estructuras en conjunto. La optimización
mostrada en la figura 2.2 b), no podría ser llevada a cabo por un intérprete,
porque cuando llegue a B=7.5 ya se han ejecutado las sentencias anteriores, no
pudiendo, por tanto, ubicar la sentencia B=7.5 antes del bucle.
c) Cada vez que utilicemos un programa tenemos que volver a traducirlo, ya que
en la traducción no se genera un archivo objeto que poder guardar en memoria
masiva (y utilizarlo en cada nueva ejecución). Con un compilador, aunque en
muchos casos la traducción sea más lenta, ésta sólo debe hacerse una vez (ya
depurado el programa) y cuando deseamos ejecutar un programa ejecutamos el
archivo ejecutable creado a partir del objeto.
Los intérpretes, a pesar de los inconvenientes anteriores, a veces son preferibles a
los compiladores, como por ejemplo, cuando el número de veces que se va a
ejecutar el programa es muy bajo y no hay problemas de velocidad; además, con
ellos puede ser más fácil desarrollar programas. Esto es así porque normalmente la
ejecución de un programa bajo intérprete puede interrumpirse en cualquier
momento para conocer los valores de las distintas variables y la instrucción fuente
que acaba de ejecutarse. Cuando esto se hace se tiene una gran ayuda para la
localización de errores en el programa. Con un programa objeto esto no se puede
realizar, salvo que el programa se ejecute bajo el control de un programa especial
de ayuda denominado depurador (“debugger”). Además, con un intérprete,
cuando se localiza un error sólo debe modificarse este error y volver a ejecutarse a
partir de la instrucción en cuestión. Con un compilador, si se localiza un error
durante la ejecución, el programador debe corregir las instrucciones erróneas sobre
el archivo fuente (no sobre el objeto) y volver a compilarlo en su totalidad después
ensamblarlo, y en su caso, montarlo y cargarlo.
Existen en la actualidad traductores que en cierta medida responden de las ventajas
tanto de los intérpretes como de los compiladores. Estos traductores se denominan
compiladores interactivos o incrementales. Un compilador interactivo es un
sistema que permite la edición , compilación y ejecución de programas escritos en
un determinado lenguaje de alto nivel, simplificando la creación y depuración del
programa, permitiendo que el compilador durante la edición realice parte de las
comprobaciones y la traducción a código intermedio. Ello permite detectar con
antelación muchos errores y evitar la retraducción de todo el programa , si se han
realizado sólo pequeños cambios.
52
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
40404" VKRQU"FG"NGPIWCLGU"FG"CNVQ"PKXGN
En los primeros tiempos de la informática y considerando el pequeño
tamaño de las memorias disponibles y la lentitud de los procesadores, se pensaba
que los traductores iban a ser muy ineficientes; sin embargo con la aparición del
primer compilador FORTRAN a mitad de los 50, su uso se extendió rápidamente,
hasta que en 1965, se estima que la Babel informática llegaba ya, hasta los 1700
lenguajes de programación diferentes. Esta explosión continua en la actualidad,
puesto que la experiencia acumulada y el advenimiento de nuevas tecnologías,
tanto en software como en hardware, favorecen la aparición de nuevos lenguajes y
el refinamiento y mejora de los existentes. Este frenesí, que conduce a que un
lenguaje aprendido hoy, esté destinado a ser declarado mas o menos obsoleto
dentro de pocos años, explica que esté fuera del objetivo de este libro, el estudio de
un lenguaje particular.
Nuestro objetivo es separar los principios de la informática y la programación, del
conocimiento de una sintaxis y una semántica particular. Sin embargo es obvio,
que la formación en Informática, no se entiende sin un cierto dominio de al menos
un lenguaje de alto nivel( que debe conseguirse delante de un ordenador) aunque la
selección del mismo dependerá de las necesidades y posibilidades de cada lector, ó
curso.
Con el objetivo de poner orden en esta Babel, en una primera clasificación
podemos distinguir entre lenguajes de propósito general (empleados en todo tipo de
aplicaciones: de gestión, científico-técnicas, de desarrollo de software de sistemas,
etc.) cuyos ejemplos podrían ser el C, Pascal y otros de propósito más específico
como sería el caso del FORTRAN para el calculo científico, el Cobol para la
gestión o el LISP y el Prolog para la Inteligencia Artificial, por no referirnos a
lenguajes específicos para la gestión de bases de datos, como el SQL.
Una segunda clasificación, es posible atendiendo al estilo de programación:
a) Lenguajes basados en la asignación de valores (Lenguajes Procedurales o
Imperativos). Se fundamentan en la utilización de variables para almacenar
valores y en la realización de operaciones con los datos almacenados,
especificando la secuencia de acciones que conduce a la resolución del
problema propuesto. La mayoría de los lenguajes son de este tipo :
FORTRAN, BASIC, COBOL, Pascal, Modula, Ada, C, etc.
b) Lenguajes declarativos, que se limitan a describir sus estructuras de datos y las
relaciones entre ellas que puedan resultar significativas para la realización de
una determinada tarea. Por tanto están basados en la definición de funciones o
relaciones y no utilizan instrucciones de asignación , por lo que sus variables
SOPORTE LÓGICO DE UN COMPUTADOR
53
no almacenan necesariamente valores. Los programas están formados bien por
una serie de definiciones de funciones (Lenguajes Funcionales, como LISP)
o de predicados (Lenguajes de Programación Lógica, como PROLOG, CLP,
etc.).
c) Lenguajes orientados a objetos. Estos lenguajes utilizan estructuras de datos
complejas, llamados objetos, que encapsulan simultáneamente información y
operaciones. Estos objetos se comunican entre si a través de mensajes que son
reconocibles de forma específica por cada objeto. Un programa es
básicamente un universo de objetos que al ejecutarse intercambian mensajes
entre sí, simulando sus respectivos comportamientos, en busca del resultado
final. Ejemplo de estos lenguajes son el C++, Smalltalk, etc.
40405" WVKNKFCFGU"["HCUGU"GP"NC"GLGEWEKłP"FG"WP"RTQITCOC
Ya hemos adelantado que una vez codificado un programa, para su
ejecución era necesario realizar una serie de operaciones previas. Durante las
primeras generaciones de computadoras estas operaciones (o su control) se hacían
más o menos manualmente, pero hoy día existen programas de ayuda al usuario, de
forma que la propia computadora se usa para auxiliar en la confección, prueba y
control de la ejecución de los programas. Los programas que proporcionan estas
herramientas y ayudas, genéricamente se denominan utilidades de programación.
Por ejemplo, la ejecución de un programa llamado MEDIAS en un lenguaje de alto
nivel, supone seguir el esquema de la Figura 2.4.
Una vez redactado el programa, debe introducirse en la computadora. Para ello crea
un archivo en memoria masiva (disco), con ayuda del editor de textos. Este es un
programa de utilidad que nos permite introducir y modificar (borrar, intercalar,
cambiar, ampliar, duplicar, etc.) cómodamente información (de programas o datos)
en un archivo. Podríamos decir que esta fase es la introducción y corrección
“mecanográfica” del programa.
Cuando el archivo está creado (supongamos que con el nombre de MEDIAS.C en
un PC con DOS), pasamos a compilar el programa. Con ello obtenemos el mismo
programa en lenguaje ensamblador (suponiendo que este compilador no genera
directamente código máquina).
FASE
1) Introducción
y
corrección
‘mecanográfica’ del programa.
UTILIDAD O AYUDA
Editor de textos (“text editor”).
2) Traducción de lenguaje de alto
nivel a lenguaje ensamblador.(*).
Compilador (“compiler”)
3) Traducción
Ensamblador (“assembler”).
de
lenguaje
54
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
ensamblador a lenguaje máquina.
(*).
4) Montaje de un archivo ejecutable,
enlazando los módulos que
componen el programa completo.
Montador, Enlazador (“linker”).
5) Carga del programa en memoria
principal.
Cargador (“loader”).
6) Ejecución del programa.
Sistema Operativo.
7) Rastreo y depuración.
Rastreador y depurador
(“tracer” y “debugger”).
(*) En el caso de que el compilador genera el código objeto directamente en lenguaje máquina y no en
lenguaje ensamblador estos dos pasos se funden.
Fig. 2.4.
Fases y utilidades en la ejecución de un programa
A continuación se ensambla, generándose un nuevo archivo (en nuestro ejemplo de
nombre MEDIAS.OBJ) que contiene el programa en lenguaje máquina. Este
programa se suele denominar reubicable, y no es directamente ejecutable. En
efecto, la mayoría de programas hacen llamadas a diversas rutinas o segmentos del
propio usuario o del sistema (funciones de biblioteca, etc.) que deben “unirse” al
programa principal. Todos estos segmentos, antes de unirse o montarse deben
estar compilados y ensamblados.
Todos los segmentos a unir han de ser reubicables, en el sentido de que su
direccionamiento es relativo, comenzando la primera instrucción en la dirección 0
de memoria. Además tienen asociados unas tablas donde se encuentran anotadas
las direcciones relativas de aquellas instrucciones que hacen referencia a otras
direcciones de memoria bien del propio segmento (instrucciones de saltos, por
ejemplo) o de otros segmentos (por ejemplo llamadas a subrutina). A veces, el
programa principal y sus subrutinas no se cargan consecutivamente, sino que
pueden ocupar zonas diversas de la memoria, y en este caso hay que transformar
las direcciones relativas de los segmentos en las direcciones físicas en que
realmente se ubicarán.
Para efectuar la unión de los distintos segmentos o módulos, “encadenando” o
“enlazando” las llamadas entre ellos, se utiliza una denominada montador,
colector, enlazador o encadenador que genera un nuevo archivo (por ejemplo de
nombre MEDIAS.EXE en un PC con DOS) denominado ejecutable ya que puede
ser ejecutado directamente. El encadenador, para realizar su trabajo, utiliza las
tablas de instrucciones con referencia a memoria de los módulos reubicables y
genera una tabla de símbolos externos, que incluye los nombres y direcciones de
las instrucciones a las que hay que saltar desde otros segmentos.
SOPORTE LÓGICO DE UN COMPUTADOR
55
La fase siguiente es introducir o cargar el programa ejecutable en memoria y
prepararlo para su ejecución. Estas operaciones las realiza una utilidad denominada
cargador. La siguiente fase es la ejecución del programa. Para ello un módulo del
sistema operativo pasa el control de la CPU a la dirección de la palabra de memoria
donde se encuentra la primera instrucción del programa (es decir, carga en el
registro contador de programa la dirección física de dicha instrucción) a partir de
la cual se sucederá la ejecución de las distintas instrucciones que constituyen el
programa.
Las utilidades de rastreo y depuración de errores son de uso opcional y permiten
efectuar funciones tales como ejecutar el programa instrucción a instrucción,
mostrándose después de cada ejecución el contenido de las variables que van
cambiando; su objeto es el de detectar posibles errores u optimizar el programa.
4050" RTQITCOC"FG"CTTCPSWG
Cuando se enciende un computador, lo primero que éste hace es llevar a
cabo un autodiagnóstico llamado autoprueba de encendido (Power On Self Test,
POST). Durante el mismo, la computadora identifica su memoria, sus discos, su
teclado y cualquier otro dispositivo que tenga conectado. Lo siguiente es buscar un
SO para arrancar (boot) como primer programa para “empezar a funcionar por sí
misma”. Ello lleva a preguntarnos en qué momento empieza a trabajar el Sistema
Operativo. Para entender este procedimiento hemos de recordar algunos elementos
de la tecnología de la memoria principal. Sabemos que la RAM es volátil, mientras
que la ROM retiene la información almacenada, aunque se apague el ordenador. En
esta última hemos de cargar un software cuyo concurso es imprescindible para la
citada identificación del hardware del ordenador y para que se produzca el proceso
de arranque de la máquina.
Una CPU está construida de forma que cada vez que se arranca, se inicializa el
contador de programa en una dirección predeterminada, antes de su primer ciclo de
máquina. Por tanto, de forma automática, interpreta que el contenido de esta
posición de memoria, es el inicio del primer programa que va a ser ejecutado. En
esta área de memoria ROM se arranca el programa, que entre otras cosas se
encargará de cargar el sistema operativo (ver Figura 2.5). Evidentemente este
programa en ROM no forma parte del propio sistema operativo, ya que su función
consiste, normalmente, en acceder a un disco predeterminado, donde asume que se
encuentra el inicio del sistema operativo (Un PC busca primero el SO en la
unidad de disco flexible; si encuentra ahí un SO válido, lo utiliza; si no lo
busca en el disco duro primario) y ejecuta una transferencia del disco al área de
memoria donde se instala el sistema operativo (o parte de éste). De esta forma, al
arrancarse la máquina, el Sistema Operativo se carga automáticamente en ella, en
posiciones que salvo cambios son siempre las mismas (Ver Figura 2.5).
56
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Memoria Principal
ROM
Programa de
arranque
Sistema
Operativo
Memoria
volátil
Fase 1:
Disco
La máquina al empezar ejecuta el programa de arranque que está en memoria.
El Sistema Operativo está almacenado en memoria secundaria.
Memoria Principal
ROM
Memoria
volátil
Fase 2:
Fig. 2.5.
Programa de
arranque
Sistema
Operativo
Disco
Sistema
Operativo
El programa de arranque transfiere el Sistema Operativo a memoria
principal, que a partir de ahora controlará a la máquina.
Proceso de arranque y carga del sistema operativo.
4060" UKUVGOCU"QRGTCVKXQU"*UQ+
Un sistema operativo (SO) es en sí mismo un programa de computadora,
aunque un tanto especial, quizás el más complejo e importante. El SO es en cierto
sentido, una parte integral de la máquina y es tan importante conocerlo como
conocer su hardware. Tras el arranque, ya sabemos, que el SO despierta a la
computadora y hace que reconozca a la CPU, la memoria, el teclado, y los distintos
periféricos. Una vez puesto en marcha el SO, mantiene al menos parte de éste en su
memoria en todo momento. Todos los SO tienen dos objetivos fundamentales: a)
Hacer posible el uso eficiente de los recursos del sistema y b) Ocultar las
dificultades que supone el control directo del hardware del ordenador. El primer
objetivo se ve entorpecido por el hecho de que algunos dispositivos funcionan
mucho más rápidamente que otros; por ello, una de las misiones de los SO es la de
garantizar que los dispositivos más rápidos, como los procesadores, no sean
retenidos por otros dispositivos más lentos, como los dispositivos periféricos. Para
conseguir el segundo, simplificar las operaciones del hardware, los SO generan una
máquina virtual. Una máquina virtual es un ordenador simplificado, en el que los
SOPORTE LÓGICO DE UN COMPUTADOR
57
detalles corren a cargo del SO. Las personas que escriben programas sólo necesitan
conocer la máquina virtual, sin necesidad de entrar en los detalles reales del
hardware. Una consecuencia importante de ello es que una aplicación desarrollada
para un SO, puede que sólo necesite recompilarse, para pasar de un entorno
hardware a otro.
40603" HWPEKQPGU"FG"NQU"UKUVGOCU"QRGTCVKXQU0
Las tareas que desempeña un SO dependen en cierta medida del tipo de las
características de cada ordenador. Así las funciones de un SO multitarea, en un
gran ordenador, son diferentes de las de un ordenador personal. Sin embargo,
existen ciertos puntos en común que permiten clarificar de forma general las tareas
principales de un SO en:
• Proporcionar una interfaz de usuario, para que este último se pueda
comunicar con la computadora.
• Administrar y controlar los dispositivos de hardware del computador.
• Administrar y mantener los sistemas de archivo de disco.
• Apoyar la ejecución de otros programas.
En los grandes sistemas, existe un operador (o un equipo de ellos) cuya misión
está relacionada con el SO, ellos arrancan y paran el ordenador, cargan programas
y discos de datos, asignan recursos a los usuarios y responden a cualquier problema
que pueda presentarse. Las redes de ordenadores suelen tener, además, un
administrador de red cuyo trabajo consiste en mantener la red funcionando de
forma eficiente, principalmente controlando los recursos compartidos como
servidores de ficheros e impresoras. Estos operadores de ordenadores y
administradores de redes trabajan directamente con el SO de los ordenadores. En
los PC y estaciones de trabajo el usuario es también el operador, activando y
parando programas, cargando disquetes, etc.
Los SO como programas deben tener una serie de características relacionadas con
su calidad, en particular: eficiencia, (supone que el SO debe ejecutar sus funciones
de forma rápida ya que el tiempo que el SO emplea en su funcionamiento es tiempo
no disponible para la aplicación que se ejecuta), fiabilidad, (un fallo en el SO
puede inutilizar el ordenador que éste controla), facilidad de mantenimiento y un
tamaño reducido (un SO pequeño ocupa menos espacio es menos propenso a los
errores y funciona más rápidamente). En la práctica es necesario llegar a un
equilibrio entre las facilidades que proporciona el SO y su tamaño.
58
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
40604" NC"GUVTWEVWTC"FG"WP"UKUVGOC"QRGTCVKXQ"V¯RKEQ
La estructura de un SO varía de acuerdo con su tamaño y complejidad. Sin
embargo, las partes o módulos que vamos a citar se encuentran en todos los SO de
una u otra forma. Los encargados de desarrollar sistemas operativos utilizan la
metáfora de una semilla para describir la estructura de los programas que escriben.
Así las funciones centrales de un SO son controladas por el núcleo (kernel)
mientras que la interfaz del usuario es controlada por el entorno (shell). Por
ejemplo, la parte más importante del DOS, es un programa con el nombre
COMMAND.COM. Este programa tiene las citadas dos partes: a) El núcleo, que se
mantiene en memoria en todo momento contiene el código máquina de bajo nivel
para manejar la administración del hardware que pueda necesitar el programa que
se está ejecutando. b) La shell, que también se le llama intérprete de órdenes (es
quien toma el control de la pantalla), permite que el usuario teclee, interpreta lo
tecleado y lo lleva a cabo. El intérprete de órdenes es la parte del programa que
establece la interfaz de línea de órdenes.
En los sistemas DOS, al menos una parte del programa COMMAND.COM está
siempre en la memoria, proporcionando a los programas los servicios de bajo nivel
administración del hardware y del disco. Sin embargo, las funciones de bajo nivel
del SO y las funciones de interpretación de órdenes están separadas, de tal forma
que es posible reemplazar el intérprete de órdenes MS-DOS estándar con uno
diferente. En otras palabras, puedes mantener el núcleo del DOS ejecutándose, pero
utilizar una interfaz de usuario diferente. Esto es exactamente lo que sucede cuando
cargas Windows. Al teclear “WIN” en el prompt de DOS, el programa Windows
toma el lugar de la shell, reemplazando la interfaz de línea de órdenes con una
interfaz gráfica del usuario.
2.4.2.1" NÚCLEO
El propio núcleo es el módulo de más bajo nivel del SO y trabaja al
servicio del resto de módulos. El núcleo trabaja directamente sobre el hardware del
ordenador y proporciona una serie de servicios a las capas superiores del sistema.
Entre estas tareas se incluyen:
- Manejo de interrupciones: Entendemos como interrupción toda señal externa
que detiene la ejecución de un programa. Cuando el hardware del ordenador
detecta una interrupción, el control se transfiere al módulo de control de
interrupciones del núcleo, que analiza el carácter de la interrupción y toma las
acciones apropiadas (transferir el control a otro módulo del SO, iniciar otro
programa o continuar la ejecución del programa interrumpido, etc.).
SOPORTE LÓGICO DE UN COMPUTADOR
59
- Asignación de trabajo al procesador: Para ello el núcleo transfiere el control al
programa que el planificador ha determinado, para que sea el próximo en
ejecutarse. El control se logra manteniendo una cola de mensajes en espera para
cada uno de los programas activos. El núcleo recibe los mensajes y los va
almacenando en la cola apropiada al destino en cuestión, para distribuirlos cuando
el programa de destino se active.
- Comunicación entre programas: La mayoría de los ordenadores disponen de
instrucciones cuyo uso está restringido al núcleo, que transfieren el control de un
programa a otro y que acceden a determinados registros.
2.4.2.2" MÓDULOS DE INTERFAZ CON EL OPERADOR Y LOS
USUARIOS
Las comunicaciones entre el SO y el mundo exterior tienen lugar a través
de dos interfaces: el interfaz usuario/SO y el interfaz SO/operador. Esta idea puede
resultar extraña para el usuario habitual de un ordenador personal, pues en estos
sistemas, se confunden en uno solo. El interfaz con el usuario proporciona un
lenguaje, cuyas instrucciones controlan la ejecución de cada programa,
especificándose entre otras cosas el máximo tiempo de CPU que se puede utilizar,
cuánta memoria se necesita y qué periféricos se van a utilizar. El interfaz
SO/operador del sistema está constituido también por órdenes y mensajes de forma
que el operador puede dirigir gran parte de las funciones del SO. Esto se aplica
particularmente a la planificación y asignación de recursos. En todo momento el
operador debe tener el control global del ordenador.
Existen dos amplias categorías de interfaz de usuario: interfaces de línea de
órdenes o interfaces gráficas de usuario. Para usar un SO con interfaz de línea de
orden, se introduce palabras y símbolos desde el teclado de la computadora. Con
un interfaz gráfico del usuario (Graphical User Interface, GUI), se seleccionan
las acciones mediante el uso de un ratón o dispositivo indicador similar para pulsar
sobre figuras llamadas iconos o seleccionar opciones de los menús. Cada SO
proporciona una interfaz de usuario, de cualquiera de los tipos ya descritos. (Ya
hemos visto que esto lo hace Windows respecto a DOS).
La interfaz de línea de ordenes.Como ejemplo, la interfaz de línea de órdenes permite controlar las
funciones mediante el tecleo de órdenes, después del indicador de petición de
entrada o prompt. En DOS, el prompt por omisión es la letra que identifica la
unidad activa de disco seguida de un signo mayor que (C>). El prompt indica que
el SO está listo para aceptar una orden. Para introducirla, se utiliza el teclado para
teclear las palabras y los símbolos. Si se teclea una orden en forma incorrecta, el
60
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
SO responde con un mensaje indicando que no entendió la orden. Cuando esto
pasa, simplemente se vuelve a teclear la orden correctamente.
La interfaz gráfica del usuario.Mucha gente piensa que el desarrollo más significativo en el mundo de las
computadoras desde que los fabricantes comenzaron a construirlas en torno a
microprocesadores, fue el desarrollo de la interfaz gráfica del usuario. Al fin, las
computadoras permitían trabajar de la misma forma en que la gente trabaja:
visualmente. Las interfaces más intuitivas utilizan objetos y símbolos llamadas
iconos con los cuales cualquier persona está familiarizada, incluyendo aquellas
personas que nunca antes han utilizado una computadora. Por ejemplo, todo el
mundo sabe lo que es un bote de basura. Es bastante obvio para lo que sirve un
icono representando un bote de basura: para tirar objetos. Tú te deshaces de algo
llevando su icono al bote de basura. Cuando sueltas el botón del ratón, el objeto
desaparece en el bote de basura, que se abulta.
40605" CFOKPKUVTCEKłP"FGN"JCTFYCTG
Sin importar qué tipo de interfaz del usuario tenga la computadora (de
línea de ordenes o gráfica), el SO intercepta las órdenes para usar la memoria y
otros dispositivos, mantiene un registro de qué programas tienen acceso a qué
dispositivos, y así sucesivamente. Así por ejemplo, cuando se introduce la orden
directorio (dir) en el prompt del SO o se hace clic en una carpeta de una GUI, el
SO interpreta la acción como una orden para mostrar los archivos en ese directorio
o carpeta. La lógica del programa en el núcleo responde a la orden mediante la
interrupción de la CPU y la instruye para que vaya a la unidad de disco y muestre
los nombres de los archivos que encuentre en el directorio o en la carpeta. El SO
intercepta la cadena de datos (los nombres de los archivos) regresándolos del disco
y desplegándolos en la pantalla. Veamos con un poco mas de detalle, la interacción
del SO con los distintos elementos del hardware del ordenador:
2.4.3.1" GESTIÓN DE LA MEMORIA
La memoria principal de la mayoría de los ordenadores es mucho más
pequeña de lo que sería necesario para contener todos los programas y datos que
maneja un ordenador en un momento dado. El módulo de gestión de la memoria de
un SO es el encargado de asignar ciertas porciones de la memoria principal a los
diferentes programas o partes de los programas que la puedan necesitar, mientras el
resto de los datos y los programas se mantienen en los dispositivos de
almacenamiento masivo. De este modo, cuando se asigna una parte de la memoria
principal se hace de una forma estructurada, siguiendo una determinada orden.
SOPORTE LÓGICO DE UN COMPUTADOR
61
La forma más común de gestión de la memoria supone crear una memoria virtual
utilizando los dispositivos de almacenamiento masivo como si fueran parte de la
memoria principal. El SO se encarga de controlar las transferencias entre los
medios de almacenamiento masivo y la memoria, creando la sensación de una
memoria mayor de la que en realidad existe. De este modo, para un usuario la
memoria principal y la memoria de almacenamiento masivo forman parte de la
misma cosa, la memoria virtual del sistema.
2.4.3.2" CONTROL DE ENTRADA/SALIDA
Los problemas asociados con la E/S de datos tienen su origen en las
diferentes características y velocidades de los dispositivos. Por ejemplo, una
impresora de líneas produce una línea de caracteres cada vez, mientras que un
teclado acepta un único carácter cada vez. Una impresora de líneas tiene una
velocidad de transferencia de caracteres (más de cien veces mayor) que un teclado.
El módulo de control de E/S de un SO trata estos problemas presentando al
programador la entrada/salida como una cuestión independiente del dispositivo.
Para los programadores, todos los dispositivos tienen las mismas características,
siendo el SO el encargado de atender las particularidades de cada uno de ellos.
Puesto que el sistema operativo es único, se entenderá que los detalles de cada
periférico del sistema deban residir en ROM, para que esta información que maneja
el SO no se pierda cada vez que se apague el ordenador. Además, también existen
“drivers” (conductores) que son programas que se ejecutan en cada arranque para
hacer de interfaz entre el SO y el periférico.
2.4.3.3" GESTIÓN DE LOS DISPOSITIVOS DE ALMACENAMIENTO
MASIVO
Los dispositivos de almacenamiento masivo de un ordenador constituyen
la zona donde se guardan datos y programas tanto del sistema como de los
diferentes usuarios. El módulo encargado de la gestión de estos dispositivos tiene
la misión de mantener la estructura de esta información y de asegurar el uso
eficiente de los medios de almacenamiento masivo. El SO se encarga de los
aspectos físicos de la transferencia (determinar qué bloques y sectores de un disco
se van a utilizar, etc.), dejando al programador libre para que sólo se preocupe de
los aspectos lógicos de la transferencia (los registros y ficheros involucrados).
Los datos y los programas de un dispositivo de almacenamiento masivo se
mantienen en ficheros. Como veremos a continuación, el módulo de gestión de
estos dispositivos de almacenamiento masivo supervisa la creación, actualización y
62
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
eliminación de los ficheros que existen en el sistema en cada momento y coopera
con el módulo de gestión de la memoria durante las transferencias de datos desde y
hacia la memoria principal. Si se dispone de un sistema de memoria virtual, existen
transferencias entre la memoria principal y los medios de almacenamiento masivo
para mantener la estructura de la memoria virtual.
40606" CFOKPKUVTCEKłP"FGN"UKUVGOC"FG"CTEJKXQU
Sabemos cómo un controlador de disco y una unidad de disco trabajaban
juntos para almacenar bits y bytes de información en un disco, pero no
consideramos la información que el SO pasa a la computadora para leer y
almacenar archivos. Los archivos pueden contener instrucciones de programas o
información creada o usada por un programa. Cuando hay cientos de archivos en
un disco, encontrar lo que se necesita puede tomar su tiempo, para reducirlo, se
necesita usar los medios proporcionados por el SO para organizar estos archivos
dentro de grupos más pequeños y más lógicos, habitualmente en forma de
directorios.
Los ficheros almacenados en los dispositivos de almacenamiento masivo contienen
información que puede ser compartida, de carácter privado, o incluso secreta. Por
tanto, cada fichero está dotado de un conjunto de privilegios de acceso, siendo una
misión del SO asegurar que estos privilegios no sean violados.
40607" CRQ[Q"C"NC"GLGEWEKłP"FG"RTQITCOCU"FG"CRNKECEKłP
Otra de las funciones importantes del SO es proporcionar servicios a otros
programas. A menudo, estos servicios son similares a aquellos que el SO
proporciona directamente a los usuarios. Por ejemplo, cuando se quiere que un
procesador de texto recupere un documento, con el cual se ha estado trabajando, el
procesador desplegará los archivos del directorio que se especifique. Para hacer
esto, el programa llama al SO para que muestre los archivos. El SO lleva a cabo el
mismo proceso para construir una lista de archivos sin importar si la solicitud viene
directamente del usuario o de un programa de aplicación, (cuando la solicitud viene
de una aplicación, el SO envía los resultados de su trabajo al programa de
aplicación en lugar de mandarlos directamente a la pantalla de la computadora).
Algunos otros servicios que el SO proporciona a los programas es guardar archivos
en el disco, leerlos de disco a memoria, revisar espacio disponible en disco y en
memoria, ubicar memoria para guardar información de un programa, leer la captura
en el teclado y desplegar caracteres o gráficos en la pantalla. Cuando los
programadores escriben programas de computadora, incluyen en sus programas
instrucciones que solicitan los servicios del SO. Estas instrucciones son conocidas
SOPORTE LÓGICO DE UN COMPUTADOR
63
como llamadas del sistema debido a que el programa tiene que llamar al SO, para
conseguir alguna información o servicios.
La mayor parte del tiempo en que un ordenador está funcionando, la demanda de
recursos es mayor que los que realmente existen. Para resolver este problema los
SO disponen de una política de administración, a lo largo del tiempo y según las
demandas, de estos recursos. El planificador es el responsable de llevar a la
práctica esta política. El mecanismo sería muy sencillo si fuera posible utilizar una
política directa, del tipo “se atenderá primero al que antes lo solicite”. Esta política
puede llevar a situaciones de bloqueo. Esto sucede cuando dos programas quedan
bloqueados al solicitar insistentemente recursos que están asignados al otro, como
ocurre cuando dos vehículos pesados intentan atravesar simultáneamente un puente
estrecho. El planificador se ocupa fundamentalmente de asignar tiempo del
procesador a los programas de acuerdo a una cierta política, que varía notablemente
de un SO a otro.
Cuando distintos programas se ejecutan simultáneamente, es necesario protegerlos
entre sí, incluido del propio SO. Esta protección debe ocurrir especialmente, frente
a errores y al abuso deliberado de los recursos del sistema. Aunque es imposible
para el SO prever los errores de los programas de aplicación, es esencial detectarlos
y diagnosticarlos lo antes posible para limitar sus efectos. Un abuso deliberado del
sistema es más difícil de resolver.
La protección de la memoria principal es el aspecto más importante de la seguridad
de un ordenador, ya que interviene en todos los procesos. El módulo de gestión de
la memoria asigna a cada tarea una parte de la memoria principal del ordenador y a
continuación asigna a cada una de estas porciones un grado de protección según la
naturaleza de las tareas que tiene encomendadas. Se realizan comprobaciones
reiteradas para asegurar que no se producen violaciones de la memoria. La forma
más común de protección contra la violación de memoria se da cuando un
programa trata de leer o escribir datos fuera del área de memoria que tiene
asignada.
40608" OłFWNQU"RCTC"NC"IGUVKłP"FG"TGFGU
Después de haber indicado la importancia de las redes de computadores, no
podemos terminar esta descripción de las funciones de un SO, sin indicar las
nuevas demandas a las que tienen que hacer frente éstos, para gestionar redes de
ordenadores. La primera consideración a tener en cuenta, es la diversidad de
topologías que se pueden dar en una red (en anillo, en bus, irregular, etc.), a las
cuales tienen que adaptarse cada uno de los SO que gestiona cada una de las
máquinas (Ver sección 2.5). Para que una red pueda operar, los protocolos deben
ser gestionados debidamente y cada uno de estos SO debe estar en condiciones de
64
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
trabajar con el soporte lógico de las redes de computadores (que trataremos con
más detalle en un apartado posterior de éste mismo capítulo). Otras funciones que
en este escenario de red debe desarrollar el SO son: controlar la seguridad de las
transacciones y evitar accesos no autorizados o vandálicos (introducción de virus
en la red, bloqueo intencionado de la misma, etc.)
40609" GLGORNQU"FG"UKUVGOCU"QRGTCVKXQU
2.4.7.1" MS DOS
El MSDOS (MicroSoft Disk Operating System) es un SO, diseñado
inicialmente para un único usuario para los ordenadores que utilizan la familia de
microprocesadores Intel 8086 -286-386-486 y Pentium. Fue desarrollado
inicialmente en 1979 por Tim Paterson, que trabajaba en Seattle Computer
Products. Siendo adquirido y terminado por Microsoft Corporation (con motivo de
la aparición del IBM-PC) que es quien lo distribuye y ha realizado sucesivas
extensiones, con el objetivo de adaptarlo a las capacidades de los nuevos
ordenadores.
CARACTERÍSTICAS GENERALES
El espíritu del MSDOS es el de proporcionar una base para el software de
un sistema, capaz de controlar todos los aspectos de la operación de un PC,
particularmente el sistema de gestión de ficheros en disco, la transferencia de datos
entre periféricos y la carga y ejecución de programas. El MSDOS dispone de un
procesador de órdenes que llama al sistema de entrada/salida (E/S) y a las
utilidades del sistema. El sistema de (E/S) tiene tres niveles: el sistema de gestión
de ficheros, el sistema básico de (E/S) (BIOS) y las rutinas firmware de E/S,
mientras que las operaciones a nivel de detalle, especialmente las transformaciones
entre estructuras físicas y lógicas, corren a cargo del BIOS. El sistema de E/S
dispone de dos formas de comunicación, una para las unidades de disco, que
constituye el sistema de gestión de ficheros, hacia las que se transfieren los datos
en bloques y otra para los periféricos hacia los que se transfieren los datos carácter
a carácter.
PROCESADOR DE ÓRDENES
El procesador de órdenes tiene cuatro funciones: actuar de interfaz con el
usuario, gestionar el sistema de interrupciones, tratar los errores y ejecutar las
órdenes internas del MSDOS. Este procesador transfiere el control al sistema de
E/S, a una de las utilidades del MSDOS o, a través del sistema de gestión de
ficheros, a un programa, según los casos.
SOPORTE LÓGICO DE UN COMPUTADOR
65
El interfaz con el usuario es un conjunto de mensajes emitidos por el ordenador
bien en respuesta a órdenes del usuario, bien de forma autónoma (prompt). El
MSDOS dispone de facilidades de edición que permiten a los usuarios corregir las
órdenes a medida que los van tecleando. También dispone de un editor de líneas
para crear ficheros batch, los cuales contienen varias órdenes del propio SO que se
van ejecutando secuencialmente una a una al llamar al fichero batch. Como ya
hemos dicho todas estas características se han visto superadas con el advenimiento
de las distintas versiones de Windows.
El sistema de interrupciones dispone de una jerarquía sencilla de prioridades para
tratar las interrupciones ocasionadas por los periféricos. Cuando el tratamiento de
una interrupción termina, se devuelve el control al programa que se estaba
ejecutando cuando sucedió la interrupción. El sistema de tratamiento de errores
funciona de una forma muy similar, devolviendo el control al programa en que se
produjo el error si ello es posible, y si no al MSDOS.
Varias órdenes del MSDOS dependen directamente del procesador de órdenes.
Estas son las órdenes que permiten conocer el directorio de un disco, borrar,
cambiar el nombre y copiar ficheros. El MSDOS mantiene un control de la hora y
el día, pudiéndose ajustar ambos mediante órdenes.
GESTIÓN DEL SISTEMA DE ALMACENAMIENTO MASIVO
La tarea más importante que desarrolla el MSDOS es la de controlar el
sistema de gestión de ficheros del ordenador. Cada disco dispone de un directorio,
que contiene los detalles de todos los ficheros del disco, así como los nombres de
los subdirectorios. De esta forma los directorios constituyen una estructura
jerárquica, en forma de árbol.
En cualquier momento el usuario está “conectado” a un determinado directorio (el
directorio por defecto), y , a menos que se especifique otra cosa, todos los ficheros
se buscan o crean en ese directorio. Los nombres de los ficheros están compuestos
por un identificativo seguido de una extensión de fichero de tres letras, que sirve
para agrupar a los ficheros de un mismo tipo. Para localizar un fichero fuera del
directorio por defecto hay que utilizar un pathname, que contiene los nombres de
todos los directorios por los que hay que pasar para llegar al fichero en cuestión.
Por ejemplo, el pathname que conduce a un fichero de nombre PBA850.TXT (en
este caso la extensión sería TXT), situado en el subdirectorio CARTAS del
directorio ADMIN del disco B, sería:
B:\ADMIN\CARTAS\PBA850.TXT
El sistema de gestión de ficheros controla esta estructura jerárquica. Dispone de
facilidades para crear un fichero, abrir uno para lectura o escritura, transferir
66
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
información entre dos ficheros en el sentido que se indique y para informar del
espacio disponible. Las transferencias tienen lugar sector a sector (un sector está
compuesto por un bloque de 512 bytes), pudiéndose acceder a los registros de los
ficheros de forma secuencial o aleatoria. El sistema de gestión de ficheros se
encarga de los detalles relativos a la carga y ejecución de los programas de usuario
y trata la mayoría de las llamadas que éstos hacen al SO.
El espacio en disco se asigna tomando el siguiente sector disponible. Cuando un
fichero se borra o se reduce su longitud, se liberan los sectores que no se necesitan.
No existe un mecanismo de agrupación, y algunos ficheros, en particular, los que
se usan para tratamiento de textos y que cambian cada vez que se editan, pueden
fragmentarse notablemente. Si un fichero está muy disperso entre los sectores del
disco, el acceso al fichero para lectura o escritura puede ser muy lento.
ENTRADA/SALIDA ORIENTADA AL CARÁCTER
Con la excepción de las unidades de disco, todos los datos se envían a
todos los dispositivos periféricos carácter a carácter. Estos incluyen el teclado, la
pantalla, la impresora y las líneas de comunicaciones. El MSDOS dispone de un
conjunto de controladores de dispositivos, uno para cada uno de los dispositivos
anteriores, que presentan un interfaz estándar para el programador. De esta forma
todos los dispositivos parecen tener las mismas características a los ojos del
programador.
UTILIDADES
Las utilidades del MSDOS, van creciendo a medida que aparecen nuevas
versiones. Entre las utilidades existentes, se incluyen: formatear, copiar y verificar
el estado de los discos, recuperar ficheros perdidos, conexión a red, trabajo en
grupo, etc. Además se cuenta con: un editor de líneas, un depurador para detectar
errores en los programas en ensamblador y un montador/enlazador para generar
módulos ejecutables a partir de código relocalizable. Existe también un programa
de ordenación para disponer las líneas de un fichero de texto en orden alfabético.
NUEVAS CARACTERÍSTICAS
La limitaciones del MSDOS, frente a la creciente potencia de los nuevos
PC, han propiciado la aparición de aplicaciones tales como Windows que corren
bajo MSDOS que permite a los usuarios interactuar con varios programas a la vez.
Este software, crea una ventana en la pantalla para cada programa que está activo.
Utilizando un ratón el usuario mueve el puntero a una ventana particular para
interactuar con el programa que se está ejecutando en ella. A su vez las ventanas
pueden disponerse en la pantalla y dimensionarse en la forma en que se desee. Los
programas que se ejecutan bajo MS Windows disponen de interfaces de usuario
SOPORTE LÓGICO DE UN COMPUTADOR
67
estándar y utilizan menús desplegables. Los datos pueden transferirse de un
programa a otro, por ejemplo, una porción de una hoja de cálculo puede incluirse
en un documento de un procesador de texto.
La evolución de estas aplicaciones está dando lugar a nuevo sistemas operativos,
de tipo gráfico (Windows NT, Windows 95) totalmente diferentes de MSDOS.
Estos nuevos sistemas operativos tratan de superar las carencias derivadas de los
orígenes del MSDOS que impiden aprovechar todo el potencial de los nuevos
procesadores.
2.4.7.2" UNIX
El SO UNIX fue diseñado en los Bell Laboratories de la American
Telephone and Telegraph Corporation (AT&T) que todavía siguen dándole
soporte. La primera versión entró en funcionamiento en 1971. El UNIX se ha
actualizado en varias ocasiones desde entonces y en este proceso de modificación
se ha adaptado para usarse en una gran variedad de máquinas. Su implementación
en el Cray-2 fue un espaldarazo notable, pues se demostró que podía ser un SO
apropiado para un gran rango de sistemas, desde el PC hasta el superordenador. El
UNIX combina las características de simplicidad, facilidad de uso y potencia con
un pequeño tamaño y una considerable flexibilidad. En un SO con un núcleo
pequeño que cuenta con un amplio grado de aceptación, especialmente entre los
usuarios experimentados. Aunque tiene ya varios años, su popularidad sigue en
aumento. La característica más importante del UNIX es que se ha convertido en un
estándar, proporcionando una plataforma estándar, para desarrollar un gran número
de aplicaciones y asegura, en la medida de lo posible, la transportabilidad del
software entre sistemas UNIX sobre distinto hardware.
CARACTERÍSTICAS GENERALES
El UNIX es un SO de propósito general, multiusuario y multiproceso.
Soporta multiprogramación y multiacceso. Dispone de un ensamblador, varios
compiladores para lenguajes de alto nivel y de un editor de texto, entre otros
elementos. El UNIX está pensado para que varios usuarios puedan acceder a un
único procesador a través de terminales. Ningún usuario recibe la consideración de
operador del ordenador. Todos los usuarios pueden enviar órdenes al SO durante su
trabajo y el SO va respondiendo a estas órdenes.
El UNIX implementa el concepto de memoria virtual, cada usuario parece tener
acceso a la totalidad de la memoria del ordenador.
CONTROL DE LA ENTRADA/SALIDA
68
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Cada dispositivo periférico del sistema está controlado mediante uno o más
ficheros. Estos ficheros se tratan de la misma forma que los ficheros de datos
ordinarios. En otras palabras, para mostrar un carácter en la pantalla, el carácter se
escribe en el fichero asociado a ésta. Esto simplifica la entrada/salida y oculta el
usuario las peculiaridades de los distintos dispositivos.
GESTIÓN DE LOS DISPOSITIVOS DE ALMACENAMIENTO MASIVO
Todo el volumen de almacenamiento masivo disponible se divide en
ficheros. El contenido de un fichero puede estructurarse de acuerdo a los deseos del
usuario, pero las relaciones entre ficheros están controladas a nivel de sistema
mediante directorios. Los directorios permiten agrupar los ficheros y estructurar los
métodos para dar acceso a ciertos ficheros a los distintos usuarios. El SO mantiene
un directorio raíz, a través del cual se llega a todos los demás ficheros del sistema.
El sistema de ficheros se considera una de las características más importantes de
UNIX.
PROTECCIÓN
La protección dentro del sistema se logra mediante bits asociados a cada
uno de los ficheros. Estos permiten otorgar permisos de lectura, escritura y
ejecución, tanto para el propietario del fichero como para los demás usuarios.
Diferentes usuarios pueden tener diferentes niveles de privilegios, que determinan
la extensión con la que pueden acceder a los ficheros y por tanto utilizar los
recursos del ordenador.
El sistema dispone de mecanismos de tratamiento de errores, de modo que si se
detecta un error durante la ejecución de un programa el SO salta a una subrutina de
tratamiento de errores. Además el usuario dispone de la facilidad de interrumpir un
programa cuya ejecución no parezca correcta.
INTERFAZ CON EL USUARIO
Todos las órdenes del SO son interpretados por un programa denominado
shell (concha, para dar la idea que es el caparazón o la parte visible del sistema).
Una característica notable del shell es que permite al usuario controlar la extensión
del funcionamiento en multitarea del ordenador. En circunstancias normales el SO
completa la ejecución de una orden antes de indicar al usuario que puede introducir
otro. Sin embargo, un usuario puede pedir al SO que comience a trabajar con una
orden a la vez que queda dispuesto para aceptar otro. Las acciones derivadas de
ambas órdenes se ejecutan juntas en multiprogramación.
En UNIX también se han producido importantes avances en materia de GUI (XWindows) y además, con la integración de la red en el SO se han desarrollado
SOPORTE LÓGICO DE UN COMPUTADOR
69
múltiples aplicaciones relacionadas con la distribución de información (WWW =
World Wide Web) que sean accesibles desde aplicaciones que se ejecutan en otros
ordenadores con otros SO (p.e. desde PC bajo MSDOS)
En la actualidad hay UNIX para PC cuyo código y manuales pueden obtenerse por
red gratuitamente al ser software de dominio público. Quizá el más popular es el
LINUX.
2.4.7.3" SISTEMAS OPERATIVOS PARA MAINFRAMES
Las grandes máquinas, han venido históricamente usando sistemas
operativos especiales para cada una de ellas, sin embargo ésto está cambiando
afortunadamente. Así, en la actualidad la mayoría incorporan el concepto de
máquina virtual y podemos describir algún SO suficientemente representativo de
los que utilizan este tipo de ordenador. Un ejemplo característico es el VME/B, que
se diseñó y desarrolló a la vez que los ordenadores para los que está pensado (La
serie 2900 de ICL).
CARACTERÍSTICAS GENERALES
El VME/B es un SO de propósito general muy sofisticado que incorpora
varias características modernas. Soporta multiacceso, batch y tratamiento de
transacciones. Uno de sus primeros objetivos es el de proporcionar un interfaz de
alto nivel simple y coherente para todos los usuarios. Es flexible, en el sentido de
que puede ser adaptado a los requisitos de una instalación particular. El VME/B
está escrito en un lenguaje de alto nivel especialmente diseñado para ese propósito.
Las comunicaciones con el VME/B se realizan mediante un lenguaje de control del
sistema (SCL) que está estructurado como un lenguaje de alto nivel.
La máquina virtual disponible para cada usuario incluye sus programas y sus datos,
así como todas las facilidades del SO y las utilidades que necesite el usuario. Para
un usuario la máquina virtual aparece como una entidad totalmente autocontenida,
aunque el VME/B permite compartir determinadas áreas de datos y código para
evitar la duplicación del software. Se utiliza un sistema de protección muy
sofisticado para garantizar la seguridad de cada una de las máquinas virtuales y de
los segmentos compartidos.
ESTRUCTURA DEL SISTEMA
Como muchos otros SO, el VME/B está constituido por una serie de capas.
En el nivel más interno se sitúa el núcleo, que es el encargado de transformar el
hardware del ordenador en un conjunto de máquinas virtuales. La siguiente capa
está constituida por el software del sistema, que gestiona los recursos de las
máquinas virtuales. La capa más externa contiene los programas de aplicación a
70
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
diferencia de otros SO más antiguos, el VME/B no presenta una separación rígida
entre el software del sistema y los programas de aplicación.
SISTEMA DE GESTIÓN DE MEMORIA Y COMUNICACIONES
Cada una de las máquinas virtuales que corren bajo VME/B dispone de un
área de almacenamiento virtual mucho mayor que la memoria principal del
ordenador. El VME/B controla todas las transferencias de segmentos de programas
y datos desde y hacia los medios de almacenamiento masivo para que el sistema de
memoria virtual sea una realidad.
Uno de sus objetivos generales es el proporcionar un eficiente servicio de
comunicaciones. El aspecto hardware del problema se resuelve utilizando una serie
de controladores de entrada/salida que enlazan los dispositivos periféricos con la
memoria principal. El aspecto software está controlado por el VME/B , que
controla y planifica todas las entradas/salidas. Así se libera a los usuarios de los
problemas que plantean las comunicaciones y se hace un mejor uso de los recursos
del ordenador.
GESTIÓN DEL ALMACENAMIENTO MASIVO
Todos los aspectos relativos al uso y la seguridad de los ficheros corren a
cargo de un sistema de almacenamiento integrado que forma parte del VME/B. El
usuario puede tomar la decisión de hacerse responsable del control del estado de
sus ficheros en el sistema de almacenamiento masivo o dejar esta tarea bajo el
control del SO.
PROTECCIÓN
Uno de los aspectos principales del VME/B es su sistema de protección
que está basado en el concepto de niveles de privilegio. Cada proceso que se
ejecuta en el sistema tiene asociado un nivel de privilegio, de 0 a 15, siendo el nivel
0 el de mayor privilegio y el nivel 15 el más bajo. Los niveles 0 a 2 están
reservados para el núcleo; los niveles 3 a 9, para el software del sistema, y los
niveles 10 a 15, para los programas de aplicación.
Cuando un proceso se está ejecutando, un registro, denominado registro de control
de acceso, contiene su nivel de privilegio. Cada uno de los segmentos de datos a
los que el proceso pueda acceder tiene una clave de acceso para lectura y una clave
de acceso para escritura. Cada clave tiene un valor entre 0 y 15. Sólo se permite el
acceso si el nivel de privilegio del registro de control de acceso es menor o igual al
valor de la clave. Por ejemplo, un proceso con nivel de privilegio 11 puede leer de
un segmento con clave de acceso 14, pero no puede escribir en un segmento con
clave de acceso 8. Además cada segmento dispone de un bit de autorización de
SOPORTE LÓGICO DE UN COMPUTADOR
71
ejecución. Sólo si éste tiene el valor 1 se puede ejecutar el código contenido en ese
segmento.
4070" UQRQTVG"NłIKEQ"FG"NCU"TGFGU"FG"EQORWVCFQTGU
Una vez enfatizados los módulos y programas del soporte lógico de un
computador, que facilitan el proceso de programación, en este epígrafe trataremos
la parte del soporte lógico que concierne al uso de las redes de computadores, ya
que éstas, en la actualidad, han revolucionado el uso de la tecnología
computacional. Aplicaciones que dependían de un sistema centralizado con una
macrocomputadora y una serie de varias terminales, en la actualidad usan redes, en
las cuales cada usuario cuenta con un ordenador propio.
40703" UQRQTVG"NłIKEQ"DıUKEQ
2.5.1.1" PAQUETES
De la misma forma que cuando alguien escribe una carta, envía el texto
metiéndolo en un sobre, generalmente de tamaño estándar. Un principio similar se
usa en muchos sistemas de comunicación. Los datos se transmiten, no carácter a
carácter, ni en grupos de caracteres, sino en paquetes. Un paquete es un conjunto
de datos para transmitir, que se incluyen en una entidad mayor, en la que se
encuentran datos para el correcto enrutamiento del paquete por la red de
comunicaciones sobre la que se mueve, así como mecanismos (bastante
sofisticados por cierto) para la detección y corrección de errores. Los datos que se
incluyen en los paquetes siguen unas normas estrictas, ya que todos los dispositivos
de una red envían y reciben los datos, utilizando paquetes del mismo tipo. Los
paquetes se han transformado en la unidad de transmisión y recepción de datos
dentro de muchas redes de comunicación de datos (denominadas redes de
conmutación de paquetes).
2.5.1.2" PROTOCOLOS DE RED
El tipo y topología de una red establecen su estructura básica, pero aún así,
cada computadora necesita el hardware para transmitir y recibir información. El
dispositivo que lleva a cabo esta función es la tarjeta de interfaz de red (NIC =
network interface card). La NIC es un tipo de tarjeta de circuitos impresos, que se
instala en una de las ranuras de expansión de la computadora y proporciona un
puerto en la parte trasera de la PC al cual se conecta el cable de la red. La
computadora también requiere del software que le indique cómo usar la NIC.
72
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Ambos, el software de la red y la NIC, se tienen que adherir al protocolo de la red,
que es el conjunto de estándares para la comunicación. Un protocolo de red es
como un lenguaje para la comunicación de información ya que para que dos
máquinas intercambien información, deben hablar el mismo idioma. Como ocurre a
menudo, los protocolos están en continuo estado de cambio, ya que cada vez que
aparece un nuevo estándar, alguien inventa otro que hace el trabajo más rápido y en
forma más fiable. Veamos los protocolos mas comunes (cada uno para cierta
topología de red y con ciertas características estándar):
2.5.1.2.1" Ethernet
Ethernet es actualmente el protocolo de red más común, que al basarse en
la topología de bus lineal resulta de bajo costo y relativamente simple. Sin
embargo, con un bus lineal, cada nodo de la red debe tomar su turno para enviar
información y al igual que en una línea telefónica, que solo una persona puede
usarla a la vez, cada vez que una máquina necesite enviar información a otra,
primero deberá revisar si la red está disponible. Si la red está siendo utilizada por
otra estación, espera brevemente y lo intenta de nuevo; como se adivina, cuando
haya muchas computadoras en una red Ethernet, el tiempo de acceso se hace
notoriamente lento.
Afortunadamente existen configuraciones que permiten utilizar el Ethernet en bus
lineal lógico en lugar de uno lineal físico, llamado 10 base-T, que utiliza un equipo
que proporciona las ventajas de una topología en estrella centralizada con la
flexibilidad y capacidad de un bus lineal. En cualquier caso los buses de la red
Ethernet están limitados a 2 500 pies (762 metros) de distancia y corren a 10 Mbits
por segundo.
2.5.1.2.2" Token Ring
El protocolo de red Token Ring, como indica su nombre, se basa en la
topología de anillo. Su característica consiste en que tiene un hardware de control
que transmite direcciones electrónicas, por la red, muchas veces por segundo. Cada
nodo examina estas direcciones para determinar si alguna le pertenece. En caso
negativo, las direcciones siguen viajando por la red sin alteración. Si la dirección
concuerda, el nodo puede anexarle un paquete de información y hacerlo llegar a
otro nodo de la red y, a la inversa un ordenador de la red puede leer el contenido de
un paquete relacionado con su dirección. Este proceso de hacer circular un grupo
de paquetes dirigidos a cada estación para cogerlos o pasarlos, simula la acción de
pasar una señal (token), de ahí el nombre de Token Ring.
SOPORTE LÓGICO DE UN COMPUTADOR
73
Las redes Token-Ting, aunque caras, tienen la ventaja de que la información viaja
de una manera controlada a través del anillo en una dirección. Con este enfoque, la
información no puede chocar y la red puede operar a mayores velocidades
(probablemente pronto veamos velocidades de hasta 100 Mbits por segundo).
2.5.1.2.3" ARCNET
La ARCNET se basa en la topología de estrella o estrella distribuida, con
una topología y protocolo propios, utiliza cable coaxial y la estrella es perpetuada
mediante el uso de paneles de control conectados a la red. La ARCNET es mas
lenta, cerca de 2.5 Mbits por segundo, aunque barata, confiable y fácil de instalar y
expandir.
2.5.1.3" MODELO DE CAPAS ISO
Una de los metas principales para la interconexión de distintos equipos
informáticos (diversos fabricantes, modelos, etc.) es conseguir la utilización de
sistemas y procedimientos de intercambio de información comunes. En definitiva,
el primer problema es establecer los interfaces y protocolos de interconexión, para
ser fijados existen asociaciones internacionales especializadas como la ISO
(International Standard Organization). Esta ha establecido una arquitectura para los
sistemas de comunicación (Modelo ISO), que utiliza la sistemática de considerar el
problema de análisis y diseño de redes de computadoras por capas (o niveles). Así
para la interconexión de dos equipos informáticos, A y B, se definen 7 niveles, que
se encargan de llevar a cabo la transmisión (Ver Figura 2.6). Cada nivel
“proporciona” o “se relaciona” con el nivel superior por medio de interfaces, y las
relaciones entre los dos equipos en cada nivel se efectúan a través de protocolos.
En esencia, en cada capa o nivel i:
a)
se diseña el protocolo nivel i (conexión Ai, Bi), utilizando las interfaces
proporcionadas por el nivel inferior (i-1).(Niveles Ai - 1 y Bi - 1);
b)
se diseña la interfaz de nivel i como servicio para el nivel i+1 (relaciones Ai
con Ai + 1, y Bi con Bi + 1), utilizando las interfaces proporcionadas por el
nivel inferior (i-1) (Niveles Ai - 1 y Bi - 1).
74
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Fig.2.6. Esquema de protocolos en el Modelo de capas ISO para la interconexión
de dos sistemas A y B.
En la Figura 2.6, puede verse un esquema simplificado del Modelo de referencia
ISO En los extremos figuran los sistemas entre los que se requiere efectuar la
conexión (Sistemas A y B). En el centro figuran otros elementos que intervienen
sólo con objeto de efectuar la transmisión (fundamentalmente equipos terminales
de las líneas de comunicaciones e interfaces de procesadores de comunicaciones).
Las capas o niveles conceptuales del modelo ISO son las siguientes:
Nivel 1: CAPA FÍSICA. En este nivel se especifican los parámetros mecánicos,
eléctricos, etc., de la interconexión entre el equipo terminal de datos y el equipo
terminal de la línea de comunicaciones. Las unidades de información son bits y su
misión es asegurar que si un emisor envía un 1 al receptor le llega un 1.
Evidentemente, su relación con el soporte lógico del ordenador, no es muy
relevante.
Nivel 2. CAPA DE ENLACE DE DATOS. Es la capa, encargada de transmitir sin
errores, ya no bits, sino bloques de información (llamadas tramas) entre dos puntos
físicos de la red. Para realizar esto, distribuye las cadenas de bits proporcionadas
por el nivel 1 en tramas de datos, emitiéndolas secuencialmente y comprobando si
hay errores en la transmisión.
Nivel 3. CAPA DE RED. Este nivel controla las operaciones en la red de
transmisión. Los elementos de información que trata son paquetes, que están
SOPORTE LÓGICO DE UN COMPUTADOR
75
compuestos de tramas. Su responsabilidad por tanto es la de planificar el trayecto
que deben seguir los paquetes en el interior de la red y de controlar la conmutación
de los circuitos.
Nivel 4. CAPA DE TRANSPORTE. Se encarga del transporte eficiente de la
información, desde la fuente el destino, a través de la red de conmutación de
paquetes. En este nivel, al igual que los de mayor nivel, las interacciones
(protocolos) se realizan entre los equipos informáticos fuente y destino, frente a los
protocolos de los niveles 1, 2 y 3 que se realizan entre equipos de nodos vecinos,
sean o no fuente o destino. Las unidades de información que considera son
mensajes , que están constituidos por paquetes.
Nivel 5. CAPA DE SESION. Cada vez que se desea efectuar una comunicación
entre dos sistemas o usuarios, debe establecerse una sesión de comunicaciones
entre ambos. Este nivel es el responsable de la realización y control del diálogo
entre procesos de distintos nudos: establecer la comunicación, sincronizar los
diálogos, cerrar la sesión, etc. Para establecer una sesión el usuario debe
proporcionar una dirección del equipo remoto al cual pretende conectarse
(dirección de sesión). Este nivel, se encarga de transformar las direcciones de
sesiones en direcciones de transporte, facilitándolas al nivel 4.
Nivel 6. CAPA DE PRESENTACIÓN. Es el nivel responsable de la forma (o
formato) de la estructura de datos intercambiados entre los procesos que dialogan.
Se encarga de: interpretar las estructuras de las informaciones intercambiadas por
los procesos de la aplicación, gestionar las terminales, transferir los archivos,
comprimir los datos y en su caso de las transformaciones criptográficas que
hubiera. Esta capa trata de homogeneizar los formatos de intercambio de
información entre equipos de la red al objeto de facilitar las tareas de la capa de
sesión.
Nivel 7. CAPA DE APLICACIÓN. Este nivel es el que está en contacto con el
usuario de toda la red, únicamente “ve” o “se las entiende” con esta capa. Los
usuarios utilizan aplicaciones informáticas , las cuales al ejecutarse , quedan
constituidas por conjuntos de tareas que requieren determinados recursos. Tanto
estas tareas como los recursos , se hallan distribuidas a lo largo y ancho de la red.
El nivel de aplicación se encarga de las funciones específicas de intercambio y
cooperación tanto entre los procesos como entre los recursos , que utilizan la
aplicación.
40704" TGNCEKQPGU"GP"WPC"TGF
Al describir una red como LAN (Local Area Network) o WAN (Wide Area
Network) se define el área geográfica que la red cubre. El segundo escalón es
76
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
describir cómo las computadoras individuales ó nodos, pueden interactuar con
otras computadoras en la red , esto es de que manera están organizadas.
2.5.2.1" LA RELACIÓN CLIENTE-SERVIDOR
Una manera de organizar redes es llamada cliente-servidor, una estrategia
jerárquica en la cual una computadora en particular sirve a las necesidades de
almacenamiento, y algunas veces a las necesidades de proceso, de todos los nodos
de la red. El tipo más común de instalación de cliente-servidor es una LAN,
compuesta de PC o estaciones de trabajo conectadas a un servidor de red, el cual
puede o no, también ser usado como el dispositivo de almacenamiento principal de
la red. Un programa cliente corriendo en uno de los nodos puede requerir
información específica del servidor. El programa del servidor puede traer la
información solicitada de sus bases de datos y pasársela al cliente.
2.5.2.2" COMPUTACIÓN PAR A PAR
Otra distribución es la computación par a par, una estrategia de red en la
cual las computadoras pueden actuar como cliente y servidores a la vez. En otras
palabras, cada nodo tiene acceso a todos o a algunos de los recursos de los otros
nodos. Por ejemplo, con la versión de Windows para trabajo en grupo, los usuarios
tienen acceso a los discos duros e impresoras conectados a otras computadoras del
grupo de trabajo.
Una LAN par a par permite a los usuarios compartir periféricos, incluyendo el
disco de almacenamiento, de tal forma que pueden tener acceso a la misma
información y a los mismos programas. Algunas redes par a par, de alto
rendimiento, tales como las redes de computadoras Unix, permiten la computación
distribuida; esto es, permite que el usuario de una máquina tenga a su disposición
la capacidad de proceso de otras computadoras de la red. Eso significa que se
puede transferir aquellas tareas que requieran muchos recursos de CPU, a
computadoras que en este momento estén disponibles, liberando a su propia
máquina.
40705" RTQITCOCU"FG"CRNKECEKQPGU"FG"NCU"EQOWPKECEKQPGU
Desde hace años los usuarios han reconocido el valor de intercambiar datos
y software. La respuesta a esta demanda vino dada por Hayes Microcomputer
Products, quien desarrolló en 1978, el Smartmodem, el primer módem para
computadoras personales. Con él se introdujo una nueva industria que actualmente
SOPORTE LÓGICO DE UN COMPUTADOR
77
proporciona toda clase de servicios para ordenadores con módem, cosa que ha
hecho que su soporte lógico se tuviera que adaptar a estas nuevas posibilidades.
Correo electrónico.Una de las aplicaciones de mayor alcance en las comunicaciones de datos
es el correo electrónico (e-mail), un sistema para intercambiar mensajes escritos
(y crecientemente, mensajes de voz) a través de una red. E-mail es algo así como
una mezcla entre el sistema postal y un contestador telefónico, donde cada usuario
tiene una dirección única. Para enviar un mensaje e-mail a alguien, se teclea la
dirección del destinatario y después el mensaje. Cuando se termina, el mensaje se
envía a la dirección. Cuando aquél acceda al sistema e-mail, se le informa que le ha
llegado correo. Después de leer el mensaje, el destinatario puede guardarlo,
borrarlo, hacerlo llegar a alguien más o responderlo enviando un mensaje de
respuesta. Además de enviar texto, muchos sistemas permiten anexar información
como hojas de cálculo o documentos como complemento al mensaje. Una red local
puede tener conexión a las grandes redes de información, lo que proporciona al
usuario de red acceso por correo a literalmente millones de usuarios e-mail en todo
el mundo.
El correo electrónico es eficiente y de bajo costo. Los usuarios pueden enviar
mensajes escritos sin preocuparse de que el destinatario esté o no usando la
computadora en ese momento. A través de las redes centralizadas, el mensaje es
remitido casi instantáneamente y además, una vez que se ha instalado la red, el
correo electrónico es muy barato.
Computadoras de acceso remoto.Uno de los grandes beneficios de un módem es que permite acceder a
computadoras remotas desde cualquier teléfono, no importa donde se encuentre. Al
marcar con un módem el número de la red se puede obtener información, acceder a
archivos e intercambiar mensajes por correo electrónico. Con una ordenador y un
módem, todo esto es posible y el ordenador debe estar preparado para esta nueva
situación, a fin de obtener las ventajas y evitar los inconvenientes que pueden
darse.
Transferencia de archivos.Por transferencia de archivos entenderemos, simplemente, enviar un
archivo de una computadora a otra y es la aplicación mas frecuente de los módem.
Para que un archivo pueda ser transferido de una computadora a otra, ambas deben
utilizar el mismo protocolo de transferencia de archivos. Como sus homólogos de
redes, los protocolos de transferencia de archivos deben ser acordados previamente
(por ejemplo Kermit, Xmodem etc.). Una de sus funciones de más importancia es
78
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
revisar los errores mientras se está enviando el archivo. Normalmente, la
comunicación del módem es bidireccional, lo cual significa que la computadora
que recibe puede responder a la que envía para asegurarse de que la información
que recibe no contiene errores. Si existe algún error, la computadora que envía la
información, transmite de nuevo, cualquier parte que sea incorrecta.
Internet.Internet es una enorme red de redes que se enlaza a muchas de las redes
científicas, y de investigación alrededor del mundo, así como a un número
creciente de redes comerciales. La Internet, a menudo llamada “ la red” (“the net”),
fue iniciada en 1969 por el Departamento de Defensa de EEUU y creció
gradualmente hasta convertirse, en una red mundial para investigación científica.
Ahora es mucho más que eso. La mayoría de la universidades están conectadas a la
Internet, así como muchas compañías y la mayoría de compañías que proporcionan
servicios de información en línea.
Es difícil definir a la Internet, de hecho es como un gran servicio de información,
que ofrece correo electrónico, boletines electrónicos y servicios de acceso de
información que ponen a disposición del usuario directorios de archivos y bases de
datos a nivel mundial. Se puede decir que la Internet es la más poderosa
herramienta de investigación y búsqueda jamás creada y está creciendo a pasos
agigantados. Por ello no hay que extrañarse, que los nuevos soporte lógicos para
ordenadores, como Windows 95, incluyan ya el acceso a Internet como una de las
utilidades incluidas en sus características.
SOPORTE LÓGICO DE UN COMPUTADOR
79
2.1. CONCEPTO DE SOPORTE LÓGICO .......................................................45
2.2. AYUDAS PARA LA PROGRAMACIÓN ...................................................47
2.2.1 TRADUCTORES...........................................................................................47
2.2.2 TIPOS DE LENGUAJES DE ALTO NIVEL................................................52
2.2.3 UTILIDADES Y FASES EN LA EJECUCIÓN DE UN PROGRAMA .......53
2.3. PROGRAMA DE ARRANQUE ...................................................................55
2.4. SISTEMAS OPERATIVOS (SO) .................................................................56
2.4.1 FUNCIONES DE LOS SISTEMAS OPERATIVOS. ...................................57
2.4.2 LA ESTRUCTURA DE UN SISTEMA OPERATIVO TÍPICO...................58
2.4.3 ADMINISTRACIÓN DEL HARDWARE ....................................................60
2.4.4 ADMINISTRACIÓN DEL SISTEMA DE ARCHIVOS...............................62
2.4.5 APOYO A LA EJECUCIÓN DE PROGRAMAS DE APLICACIÓN..........62
2.4.6 MÓDULOS PARA LA GESTIÓN DE REDES ............................................63
2.4.7 EJEMPLOS DE SISTEMAS OPERATIVOS................................................64
2.5. SOPORTE LÓGICO DE LAS REDES DE COMPUTADORES ..............71
2.5.1 SOPORTE LÓGICO BÁSICO ......................................................................71
2.5.2 RELACIONES EN UNA RED ......................................................................75
2.5.3 PROGRAMAS DE APLICACIONES DE LAS COMUNICACIONES .......76
CAPITULO 3
ALGORITMOS Y PROGRAMAS
Este capítulo trata de ser una introducción a la metodología y tecnología de la
programación, con el objetivo de proporcionar al lector los procedimientos y
técnicas para el desarrollo de programas.
No por obvio, hay que olvidar que los programas se escriben con el ánimo de
resolver problemas, con ayuda de las computadoras y que la primera medida a
considerar, es el análisis del problema en cuestión y la obtención, en su caso, de un
algoritmo adecuado. Por este punto empezaremos nuestra exposición, hasta llegar a
los métodos y etapas a seguir para obtener una aplicación informática.
Si bien los conceptos que aquí se introducen son fundamentales para la realización
de programas, este capítulo no debe leerse como si se tratara de un manual de
programación, sino como una fundamentación de lo que llamamos programación
estructurada, mas allá de la sintaxis y de la semántica de un lenguaje de
programación concreto.
5030" EQPEGRVQ"FG"CNIQTKVOQ
Sabemos que para que un ordenador pueda llevar adelante una tarea
cualquiera, se tiene que contar con un algoritmo que le indique, a través de un
programa, que es lo que debe hacer con la mayor precisión posible. Quizás esta
afirmación debería ser revisada desde la óptica de la Inteligencia Artificial, pero
por el momento la mantendremos como válida dentro del carácter introductorio de
este curso. Consecuencia de lo anterior es la importancia del estudio de los
algoritmos dentro de las Ciencias de la Computación. Recordemos que un
algoritmo es “una sucesión finita de pasos no ambiguos que se pueden ejecutar en
un tiempo finito”, cuya razón de ser es la de resolver problemas; por tanto
“problema” para nosotros, serán aquellas cuestiones, conceptuales o prácticas ,
cuya solución es expresable mediante un algoritmo. Afortunadamente, son muchos
los problemas cuya solución puede describirse por medio de un algoritmo y ésta es
81
82
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
una de las razones subyacentes a la necesidad de que aprendamos a programar y a
manejar un ordenador.
Nótese que no es redundante el hecho de exigir que un conjunto finito de pasos o
instrucciones acaben en un tiempo finito, pues una sola instrucción del tipo: “hacer
acción A1 hasta que se cumpla la condición C1”, acaba dando lugar a un proceso
infinito, si no llega a darse nunca la condición C1. El término ‘no ambiguo’
significa que la acción, a desarrollar en cada paso de la secuencia, viene
unívocamente determinada, tanto por la instrucción como por los datos disponibles
en este momento, de forma que en cada momento se sepa qué acción única, se tiene
que llevar a cabo.
5040" NC" TGUQNWEKłP" FG" RTQDNGOCU" [" GN" WUQ" FGN
QTFGPCFQT
Antes de entrar en la codificación de la resolución de un problema, hemos
de contar con una idea bastante precisa de cómo podemos llegar a esta solución. La
experiencia personal de todos nosotros nos dice que la sistematización para la
resolución de problemas no es fácil.
Resolución de
un problema
Análisis del
problema
Fig. 3.1.
Diseño del
algoritmo
Programación
del algoritmo
La resolución de un problema en Informática
En esta línea, el matemático G. Poyla propuso, a finales de 1940, una metodología
general para la resolución de problemas matemáticos, que ha sido adaptada para el
caso en que se cuente con un ordenador como recurso. Esta sistemática, de forma
muy esquematizada, se puede dividir en tres fases (Ver Figura 3.1):
1. Análisis del problema
2. Diseño del algoritmo
3. Programación del algoritmo
50403" CPıNKUKU"FGN"RTQDNGOC
ALGORITMOS Y PROGRAMAS
83
El objetivo del análisis del problema, es ayudar al programador a llegar a
una cierta comprensión de la naturaleza del mismo. Este análisis supone, en
particular, la superación de una serie de pasos (Ver Figura 3.2):
-
Definir el problema con total precisión.
Especificar los datos de partida necesarios para la resolución del
mismo (especificaciones de entrada).
Especificar la información que debe proporcionarse al resolverse
(especificaciones de salida).
Análisis del
problema
Definición
del problema
Especificaciones
Especificaciones
de entrada
de salida
Fig. 3.2.
Análisis del problema
Ejemplo 1:
Elaborar el análisis para obtener el área y la longitud de una circunferencia.
1.2.3.-
Utilizar las fórmulas del área y la circunferencia en función del radio.
Las entradas de datos se reducen al dato correspondiente al radio del
círculo. Dada la naturaleza del mismo y el procesamiento al cual lo
someteremos, su tipo de dato debe ser un número real.
Las salidas serán dos variables también reales: área y circunferencia.
La finalización de la fase de análisis del problema nos llevaría al siguiente
resultado:
Entradas:
Salidas:
Variables:
Radio del círculo (variable RADIO).
Superficie del círculo (variable AREA).
Circunferencia del círculo (variable CIRCUNFERENCIA).
RADIO, AREA, CIRCUNFERENCIA: tipo real.
50404" FKUGÜQ"FGN"CNIQTKVOQ
Diseñar un algoritmo puede ser una tarea difícil y su aprendizaje no es
inmediato, ya que requiere una buena dosis de experiencia y creatividad. Hace ya
100 años, un matemático de la talla de Henri Poincare, que no sólo trabajó en temas
84
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
relacionados con la física, el álgebra y el análisis, sino también sobre la filosofía de
la ciencia, trató de explicar sus experiencias personales de cómo un problema, a
cuya resolución había dedicado mucho tiempo sin éxito, podía aparecer tiempo
después resuelto repentinamente en su cabeza, incluso cuando se estaba dedicando
a proyectos distintos. Desgraciadamente sus resultados en este empeño, distaron
mucho de la brillantez de sus logros como físico y matemático. El periodo que
existe entre el análisis de un problema y el diseño de su solución recibe el nombre
de periodo de incubación y el proceso mental, que se da durante el mismo sigue
siendo un tema de investigación para los psicólogos. Estamos por tanto en el
terreno de la inspiración y la madurez mental. Seamos optimistas y pensemos que
vamos a tener la capacidad de tener ideas, propias o adquiridas, para desarrollar
algoritmos que nos permitan actuar ante los problemas que se nos planteen.
Para diseñar algoritmos hay que tener presente los requisitos siguientes:
• indicar el orden de realización de cada paso,
• estar definido sin ambigüedad y
• ser finito
Ejemplo 2:
Averiguar si un número es primo o no, suponiendo que razonamos de la siguiente
forma: “Del análisis del hecho de que un número N es primo si sólo puede
dividirse por sí mismo y por la unidad, un método que nos puede dar la solución
sería dividir sucesivamente el número por 2, 3, 4..., etc. y, según el resultado,
podríamos resolver el problema”. Un diseño del mismo sería:
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
Inicio
Poner X igual a 2 (X = 2, X, variable que representa a los posibles
divisores de N)
Dividir N por X (N/X)
Si el resultado es entero, entonces N no es primo, y saltar al punto 9
(en caso contrario continuar el proceso en el siguiente punto, 5)
Incrementar X en una unidad
Si X es menor que N saltar al punto 3
(en caso contrario continuar el proceso en el siguiente punto, 7)
Declarar N es primo;
Saltar al Fin (punto 10)
Declarar N no es primo
Fin
Como parte del diseño de algoritmo está la selección de uno que sea
razonablemente aceptable, entre todos los muchos posibles que resuelven el mismo
problema (el ejemplo que acabamos de dar es claramente mejorable, pues si N no
era divisible por 2 no tiene mucho sentido volverse a preguntar si lo es por 4).
ALGORITMOS Y PROGRAMAS
85
Durante el diseño es posible y aconsejable, realizar comparaciones entre algoritmos
que resuelven el mismo problema. La bondad de un algoritmo puede medirse por
dos factores:
- El tiempo que se necesita para ejecutarlo. Para tener una idea aproximada
de ello, basta con saber el número de instrucciones de cada tipo necesarias
para resolver el problema.
- Los recursos que se necesitan para implantarlo.
Así, una vez diseñado un primer algoritmo, conviene realizar una evaluación del
mismo, cuestión a veces nada banal y sobre la que volveremos en capítulos
posteriores. Si se decide que éste no es eficiente será necesario o bien diseñar uno
nuevo o bien optimizar el original. Optimizar un algoritmo consiste en introducir
modificaciones en él, tendentes a disminuir el tiempo que necesita para resolver el
problema o a reducir los recursos que utiliza. (En el ejemplo 2 el algoritmo se
optimiza, si N se declara como primo cuando X supera a N/2).
3.2.2.1" Diseño Descendente o Modular
Los problemas complejos se pueden resolver más eficazmente cuando se
descomponen en subproblemas que sean más fáciles resolver el original. Este
método se denomina divide y vencerás y consiste en convertir un problema
complejo en otros más simples que, una vez resueltos, en su conjunto nos
solucionen el original. Al procedimiento de descomposición de un problema en
subproblemas más simples, (llamados módulos) para, a continuación, seguir
dividiendo estos subproblemas en otros más simples, se le denomina diseño
descendente. Las ventajas más importantes de este tipo de diseño son:
1)
2)
3)
El problema se comprende más fácilmente al dividirse en módulos o partes
más simples. Adelantemos que cuando demos el salto a la programación,
utilizaremos esta idea constantemente, de forma que hablaremos también
de procedimientos, o subprogramas.
Las modificaciones en los módulos son más fáciles, pues estamos ante
algoritmos más sencillos.
La comprobación del problema se puede realizar más fácilmente, al poder
localizar los posibles fallos con mayor precisión.
3.2.2.2" Refinamiento por pasos
Durante el diseño, entenderemos por refinamiento por pasos, la
metodología por la que en un primer esbozo del algoritmo nos limitamos a señalar
86
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
o describir un reducido numero de pasos, que deberán ser expresados con mayor
detalle posteriormente. Tras esta primera descripción, éstos se especifican con
mayor minuciosidad, de forma más extensa y con más pasos específicos. En cada
nivel de refinamiento hay que considerar dos fases: ¿Qué hace el módulo? para a
continuación responder a ¿Cómo lo hace?.
Como es natural, dependiendo de la complejidad del problema se necesitarán
diferentes y sucesivos niveles de refinamiento antes de que pueda obtenerse un
algoritmo con suficiente nivel de detalle. Así en el Ejemplo 1, del cálculo de la
longitud y superficie de un círculo, a pesar de presentar un bajo nivel de
complejidad, en su diseño, se puede descomponer en subproblemas más simples:
1) leer datos de entrada,
2) calcular superficie y longitud,
3) escribir resultados.
El ejemplo siguiente, nos muestra el diseño de un algoritmo para un problema de
carácter no numérico
Ejemplo 3:
Diseñar un algoritmo que responda a la pregunta: ¿Qué debo hacer para ver la
película XYZ?.
Un primer análisis nos conduce a un esbozo de solución, descomponiéndolo en
cuatro módulos sucesivos:
1
2
3
4
ir al cine donde proyectan XYZ
comprar una entrada
ver la película
regresar a casa
Estos cuatro pasos se pueden refinar un poco más y así este problema lo
podríamos descomponer de la siguiente forma:
inicio
{algoritmo para ver la película XYZ}
consultar la cartelera de cines
si proyectan “XYZ” entonces
ir al cine correspondiente
si_no proyectan “XYZ”
declarar el fracaso del objetivo y terminar
acudir al cine correspondiente
si hay cola entonces ponerse en ella
ALGORITMOS Y PROGRAMAS
87
mientras haya personas delante en la cola hacer
avanzar en la cola
preguntar si quedan entradas
si hay entradas entonces
comprar una entrada
si_no quedan entradas
declarar el fracaso del objetivo, regresar a casa y terminar
encontrar el asiento correspondiente
mientras proyectan la película hacer
ver la película
abandonar el cine
regresar a casa
fin
Algunas de estas acciones son primitivas para nosotros, es decir, no es necesario
descomponerlas más, como el abandonar el cine. Sin embargo hay otras acciones
que son susceptibles de mayor descomposición. Este es el caso de la acción:
“encontrar el asiento correspondiente”
si los números de los asientos están impresos en la entrada, esta acción compuesta
se resuelve con el siguiente algoritmo:
inicio {algoritmo para encontrar el asiento del espectador}
caminar hasta llegar a la primera fila de asientos
repetir
comparar número de fila con número impreso en billete
si no son iguales, entonces pasar a la siguiente fila
hasta_que se localice la fila correcta
mientras número de asiento no coincida con número de billete
hacer avanzar a través de la fila a la siguiente butaca
sentarse en la butaca
fin
De esta forma, podríamos seguir hasta la descomposición de las distintas acciones
en instrucciones susceptibles de ser interpretadas, directamente por el ordenador.
50405" RTQITCOCEKłP"FGN"CNIQTKVOQ
Una vez que el algoritmo está diseñado y representado, se debe pasar a la
fase de resolución práctica del problema con el ordenador. Esta fase se descompone
a su vez en las siguientes subfases: (Ver Figura 3.3)
88
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
1. Codificación del algoritmo en un programa.
2. Ejecución del programa.
3. Comprobación del programa.
Programación
del algoritmo
Codificación
en un programa
Ejecución
del programa
Comprobación
del programa
Fig. 3.3 Programación del algoritmo
La fase de conversión de un algoritmo en instrucciones de un lenguaje de
programación, como sabemos, se denomina codificación. El código deberá estar
escrito de acuerdo con la sintaxis del lenguaje de programación ya que solamente
las instrucciones sintácticamente correctas pueden ser interpretadas por el
computador.
Nótese que durante el proceso de programación, se debe separar el diseño del
algoritmo de su posterior implementación en un lenguaje de programación
específico. Por ello distinguimos entre el concepto más general de programación y
el más particular de codificación, que depende del lenguaje de programación
utilizado. Al llegar a este punto, se supone que el lector conoce al menos uno de
estos lenguajes y éste es el momento en el que tiene que mostrar sus habilidades
para efectuar una codificación lo más correcta y eficiente posible.
Tras la codificación del programa, éste deberá ejecutarse en un computador. El
resultado de esta primera ejecución es incierto, ya que existe una alta posibilidad de
que aparezcan errores, bien en la codificación bien en el propio algoritmo. Por
tanto, el paso siguiente consiste en comprobar el correcto funcionamiento del
programa y en asegurarse, en la medida de lo posible, de la validez de los
resultados proporcionados por la máquina.
5050" TGRTGUGPVCEKłP"FG"CNIQTKVOQU
Un algoritmo es algo puramente conceptual que necesita una forma de
representación, bien para comunicarlo a otra persona bien para ayudar a convertirlo
en un programa. De hecho, la codificación en un lenguaje de programación, es una
representación muy utilizada de un algoritmo, sin embargo tiene el inconveniente
de que no todas las personas conocen el lenguaje que se haya elegido. Por ello,
ALGORITMOS Y PROGRAMAS
89
existen diferentes métodos que permiten que se pueda independizar el algoritmo de
su correspondiente codificación. Veamos dos de ellos:
50503" RUGWFQEQFKIQ
El pseudocódigo es un lenguaje de especificación de algoritmos (no de
programación) basado en un sistema notacional, con estructuras sintácticas y
semánticas, similares a los lenguajes procedurales, aunque menos formales que las
de éstos, por lo que no puede ser ejecutado directamente por un computador. El
pseudocódigo utiliza para representar las sucesivas acciones, palabras reservadas similares a sus homónimas en los lenguajes de programación-, tales como start,
end, stop, if-then-else, while-do, repeat-until, (inicio, fin, parar, si-entoncessino, mientras-hacer, repetir-hasta), etc. A lo largo de este capítulo, a medida
que vayamos describiendo las estructuras de control utilizadas en los programas,
iremos haciendo una lista de las instrucciones más usuales del pseudocódigo. La
ventajas del uso del pseudocódigo residen en:
- Su uso en la planificación de un programa; permitiendo que el programador se
pueda concentrar en la lógica y en las estructuras de control y no tenga que
preocuparse, por ahora de detalles acerca de las reglas sintácticas y semánticas
de un lenguaje específico. Consiguientemente es más fácil de modificar, en el
caso de que se descubran errores o anomalías en la lógica del algoritmo.
- Aunque el pseudocódigo es independiente del lenguaje de alto nivel que vaya a
utilizarse, un algoritmo expresado en pseudocódigo puede ser traducido más
fácilmente a muchos de ellos.
Ejemplo 4:
Supongamos que tenemos un algoritmo para averiguar si un número es par, que
puede ser descrito narrativamente de la siguiente forma: “Si restando
consecutivamente doses del número se obtiene el numero 2, es par, si se obtiene
otro valor (el 1), entonces es impar”. Este algoritmo escrito en pseudocódigo sería:
leer N
mientras N > 2 hacer
N←N-2
si N = 2 entonces
escribe “es par”
sino
escribe “es impar”
90
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
fin
Nótese que en este ejemplo y en otros anteriores hemos utilizado dos
estructuras que son muy usadas en programación: mientras-hacer y si-entoncessi_no; y que la escritura del pseudocódigo usa normalmente la indentación (sangría
en el margen izquierdo) de diferentes líneas para ayudar a delimitar visualmente
cada una de las estructuras utilizadas.
50504" QTICPKITCOCU
Para ganar claridad expositiva se han desarrollado una serie de símbolos
gráficos que permiten representar los algoritmos y que son universalmente
reconocidos. Veamos algunos ejemplos:
Fig. 3.4.
Símbolos usados para confeccionar organigramas
Los organigramas o diagramas de flujo son herramientas gráficas utilizadas tanto
para representar algoritmos, como en la ayuda en el diseño de programas. Están
compuestos por una serie de símbolos, unidos con flechas, donde cada símbolo
representa una acción distinta y las flechas el orden de realización de las acciones.
Cada símbolo, por tanto, tendrá al menos una flecha que conduzca a él y una flecha
que parta de él, exceptuando el comienzo y final del algoritmo. En la Figura 3.4, se
muestran los símbolos utilizados habitualmente en la confección de organigramas,
cuyo significado completaremos más adelante.
La Figura 3.5. representa, en forma de organigrama, el algoritmo del Ejemplo 4 que
ha sido expresado en pseudocódigo en la sección anterior.
ALGORITMOS Y PROGRAMAS
Fig. 3.5.
91
Organigrama del Ejemplo 4
5060" GUVTWEVWTCU"FG"EQPVTQN
En el Capítulo 1, vimos los elementos básicos constitutivos de un programa:
- palabras reservadas (inicio, si-entonces, etc.)
- identificadores (nombres de variables, procedimientos, etc.)
- caracteres especiales (coma, punto y coma, apóstrofo, etc.)
- constantes
- variables
- expresiones
- instrucciones
Sin embargo como hemos visto al diseñar algoritmos para escribir un programa,
además de estos elementos básicos, hemos de conocer determinadas estructuras,
cuyo objetivo es controlar su ejecución y sin cuya comprensión es imposible
programar.
Llamaremos estructuras de control a las acciones que tienen por objeto marcar el
orden de realización de los distintos pasos de un programa ó algoritmo. Cada
estructura tiene un punto de entrada y uno de salida, lo que facilita la depuración de
posibles errores. Estas son de tres tipos:
• estructuras secuenciales
92
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
• estructuras selectivas
• estructuras repetitivas
y vamos a estudiarlas con un cierto detalle. El uso de las estructuras de control es
una de las características de la programación estructurada que constituye la
principal orientación de este texto, aunque otros lenguajes procedurales no
estructurados también utilizan estas estructuras.
50603" GUVTWEVWTCU"UGEWGPEKCNGU
Son aquéllas en las que una acción (instrucción) sigue a otra de acuerdo con su
orden de escritura. Las tareas se suceden de tal modo que tras la salida (final) de
una se efectúa la entrada (principio) en la siguiente y así sucesivamente hasta el fin
del proceso. Su organigrama obedece al esquema de la Figura 3.6:
Fig. 3.6.
Esquema de una estructura secuencial
Las estructuras secuenciales se codifican de forma directa en cualquier lenguaje de
programación, pues como sabemos el orden de ejecución de todo programa es
precisamente, salvo orden en sentido contrario, de arriba abajo. A pesar de su
simplicidad, ya sabemos, que algunos problemas se pueden resolver con la sola
utilización de esta estructura, como por ejemplo el cálculo del volumen del cilindro
visto en el Capítulo 1, y codificado en los cuatro lenguajes de programación.
50604" GUVTWEVWTCU"UGNGEVKXCU
Como hemos tenido ocasión de comprobar, la especificación formal de
algoritmos tiene utilidad real, cuando éstos requieren una descripción más
complicada que una simple secuencia de instrucciones. Uno de estos casos se
ALGORITMOS Y PROGRAMAS
93
produce cuando existen varias alternativas, resultantes de la evaluación de una
determinada condición, como ocurre, por ejemplo, al resolver una ecuación de
segundo grado, donde el procedimiento a seguir es distinto según el discriminante
sea positivo, nulo ó negativo. Las estructuras selectivas en un programa se utilizan
para tomar decisiones, de ahí que se suelan denominar también estructuras de
decisión o alternativas. En estas estructuras se evalúa una condición, especificada
mediante expresiones lógicas, en función de cuyo resultado, se realiza una opción u
otra. En una primera aproximación, para esta toma de decisiones, podemos pensar
en una variable interruptor o conmutador (switch), que representa un estado y
por tanto puede cambiar de valor a lo largo de la ejecución regulando el paso a una
u otra parte del programa, lo que supone una bifurcación en el flujo del programa,
dependiendo del valor que tome el conmutador. Los interruptores pueden tomar
dos valores diferentes, frecuentemente 1 y 0, de ahí su nombre de interruptor
(“encendido”/“apagado”, “abierto”/“cerrado”). En la Figura 3.7, si SW es igual a 1,
se ejecuta la acción S1; y si SW es igual a 0, se ejecuta la acción S2.
Fig. 3.7.
Funcionamiento de un interruptor
Ejemplo 5:
Sea un archivo formado por un conjunto de registros constituidos por dos
campos, M y N. Se desea listar el campo M de los registros pares y el campo N de
los registros impares. Expresar el algoritmo correspondiente en forma de
organigrama (Ver Figura 3.8).
94
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Fig. 3.8.
Organigrama del Ejemplo 3
En el ejemplo SW es un interruptor que se inicializa con un valor determinado (0
en este caso) y luego se va modificando su valor alternativamente a medida que se
leen los registros. De este modo, cuando SW = 0 se leerán las fichas impares y
cuando SW = 1 se leerán las fichas pares.
3.4.2.1" Alternativas simples (si-entonces/if-then)
La estructura alternativa más sencilla, es la llamada simple y se representa
por si-entonces. Su efecto es el de ejecutar una determinada acción cuando se
cumple una cierta condición y en caso contrario seguir el orden secuencial. La
selección si-entonces evalúa la condición y de acuerdo con su resultado:
-
Si es verdadera, entonces ejecuta una o varias acciones (S1).
ALGORITMOS Y PROGRAMAS
-
95
Si es falsa, entonces no hace nada y sigue la ejecución normal del
programa, pasando a la instrucción siguiente a la finalización de la
estructura selectiva. Para ello es necesario que ésta venga claramente
delimitada, cosa que se hace en pseudocódigo con fin_si.
Su expresión en Pseudocódigo (para S1 compuesta de varias acciones) es:
si <condición> entonces
<acciones>
fin_si
FORTRAN
BASIC
IF logico
IF (condición) S
IF (condicion) GOTO etiqueta
IF expresión THEN numero linea
IF expresión THEN GOTO etiqueta
IF condición THEN
S1
S2
.
Sn
END IF
IF condición THEN
S1
S2
.
Sn
END IF
RCUECN
C
kh condicion vjgp
dgikp
S1
S2
.
Sn
....gpf
if (condicion)
{
S1
S2
...
Sn
};
3.4.2.2" Alternativas dobles (si-entonces-si_no/if-then-else)
La estructura anterior es muy limitada y muchas veces se necesitará una
estructura que permita elegir entre dos opciones o alternativas posibles en función
del cumplimiento o no de una condición, que juega el papel de un interruptor. Si la
condición es verdadera, se ejecuta la acción o acciones S1, y si es falsa, se ejecuta
la acción ó acciones S2, pasando en cualquier caso a la instrucción siguiente a la
finalización de la estructura selectiva. El pseudocódigo correspondiente es el
siguiente
96
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
si <condición> entonces
<acciones S1>
si_no
<acciones S2>
fin_si
FORTRAN
BASIC
IF condición THEN
acciones S1
ELSE
acciones S2
END IF
IF condición THEN
acciones S1
ELSE
acciones S2
END IF
RCUECN
C
kh condicion vjgp
dgikp
acciones S1
gpf
gnug
dgikp
acciones S2
gpf
if (condicion)
{
acciones S1
}
else
{
acciones S2
}
Ejemplo 6:
Informar si un estudiante ha superado o no un determinado examen consistente en
20 preguntas de igual valor y calcular su nota en caso de aprobar.
leer num_correctas
si num_correctas < 10 entonces
escribir “no ha superado Vd. el examen”
faltan ← 10 - num_correctas
escribir “le faltaron” , faltan
si_no
nota ← num_correctas / 2
escribir “aprobó Vd. con un” , nota
fin_si
ALGORITMOS Y PROGRAMAS
97
3.4.2.3" Alternativas múltiples (según_sea, en_caso_de)
Con frecuencia existen más de dos elecciones posibles (por ejemplo, en la
resolución de la ecuación de segundo grado hay tres casos). La estructura de
alternativa múltiple evaluará una expresión que podrá tomar n valores (o grupos de
valores) distintos e1, e2,....,en. Según el valor que tome la condición, se realizará
una de las n acciones posibles, o lo que es lo mismo, el flujo del algoritmo seguirá
un determinado camino entre los n posibles (Ver Figura 3.9).
Fig. 3.9.
Esquema de una alternativa múltiple
La estructura de decisión múltiple en pseudocódigo se puede representar de
diversas formas, aunque la más simple es la siguiente (donde e1, e2, ....., en son los
distintos valores (o grupos de ellos) que puede tomar la evaluación de la expresión
que sirve de condición):
según_sea expresión (E) hacer
e1: <acciones S1>
e2: <acciones S2>
.
en: <acción Sn>
fin_según
Ejemplo 7:
Escribir un algoritmo que permita obtener las raíces reales de la ecuación de
segundo grado, ax2 + bx + c.
algoritmo RESOL2
inicio
leer a,b,c
D ← b^2-4*a*c
segun_sea D hacer
D<0: escribir “raíces complejas”
{no existen raíces reales}
98
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
D=0: x ← -b/2a
escribir x , “raiz doble”
D>0: rc← raizcua(D)
x1← (-b-rc)/2a
x2 ←(-b+rc)/2a
escribir x1,x2
fin_segun
fin
Para implementar esta estructura de alternativas múltiples hemos de recurrir a
estructuras alternativas simples o dobles, adecuadamente enlazadas. Las estructuras
de selección si-entonces y si_entonces_sino implican la selección de una de dos
alternativas y utilizándolas debidamente, es posible diseñar con ellas estructuras de
selección que contengan más de dos posibilidades. Una estructura si-entonces
puede contener otra y así sucesivamente cualquier número de veces (se dice que las
estructuras están anidadas o en cascada). El esquema es del tipo:
si (condición e1) entonces
<acciones S1>
sino
si (condición e2) entonces
<acciones S2>
sino
si (condición e3) entonces
<acciones S3>
sino
...
<acciones Sn>
fin_si
fin_si
fin_si
50605" GUVTWEVWTCU"TGRGVKVKXCU
El computador está especialmente diseñado para aplicaciones en las que una
operación o un conjunto de ellas deben repetirse muchas veces. En este sentido,
definiremos bucle o lazo (loop), como un segmento de un programa cuyas
instrucciones se repiten bien un número determinado de veces o mientras se
cumpla una determinada condición.
Es imprescindible que se establezcan mecanismos para controlar esta tarea
repetitiva, ya que si éstos no existen, el bucle puede convertirse en un proceso
ALGORITMOS Y PROGRAMAS
99
infinito. Así, en el bucle representado por el organigrama de la Figura 3.10, se
observa que las instrucciones incluidas en él se repiten indefinidamente. El
mecanismo de control citado se establece mediante una condición que se
comprueba en cada paso o iteración del bucle. En la Figura 3.11, se coloca una
condición tras la lectura de la variable N (comprobar si su valor es cero), de forma
que tenemos la oportunidad de que el bucle deje de ser infinito, ya que podrá
interrumpirse cuando la condición sea verdadera.
Fig. 3.10
Bucle infinito
Fig. 3.11
Bucle con condición de salida
Los procesos que se repiten varias veces en un programa necesitan en
muchas ocasiones contar el numero de repeticiones habidas. Una forma de hacerlo
es utilizar una variable llamada contador, cuyo valor se incrementa o decrementa
en una cantidad constante en cada repetición que se produzca. La Figura 3.12
presenta un diagrama de flujo para un algoritmo en el que se desea repetir 50 veces
un grupo de instrucciones, que llamaremos cuerpo del bucle, donde el contador se
representa con la variable CONT. La instrucción que actualiza al contador es la
asignación:
CONT ← CONT+1.
100
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Fig. 3.12
Ejemplo de bucle con contador positivo
El contador puede ser positivo (incrementos de uno en uno) o negativo
(decrementos de uno en uno). En la Figura 3.12, el contador cuenta desde 1 a 50 y
deja de repetirse cuando la variable CONT toma el valor 51 y termina el bucle. En
la Figura 3.13 se muestra un algoritmo que efectúa la operación de multiplicación n
x m, sumando m un número n de veces. En él, el contador se decrementa: comienza
a contar en n y se va decrementando hasta llegar a cero; en ese momento se termina
el bucle y se realiza la acción escribir.
ALGORITMOS Y PROGRAMAS
Fig. 3.13
101
Ejemplo de bucle con contador negativo
Otro tipo de variable, normalmente asociada al funcionamiento de un bucle
es un acumulador o totalizador, cuya misión es almacenar una cantidad variable,
resultante de operaciones sucesivas y repetidas. Un acumulador realiza una función
parecida a la de un contador, con la diferencia de que el incremento o decremento,
de cada operación es variable en lugar de constante. En la Figura 3.11 la
instrucción, SUMA ← SUMA + N, añade en cada iteración el valor de la variable
N, leída a través de un periférico, por lo que SUMA es un ejemplo de acumulador.
Una estructura repetitiva es aquella que marca la reiteración de una serie
de acciones basándose en un bucle. De acuerdo con lo anterior, esta estructura debe
constar de tres partes básicas:
- decisión (para finalizar la repetición)
- cuerpo del bucle (conjunto de instrucciones que se repiten)
- salida del bucle (instrucción a la que se accede una vez se decide finalizar)
Tomando el caso de la Figura 3.11, donde para obtener la suma de una
serie de números, hemos utilizado la estrategia siguiente: tras leer cada número lo
añadimos a una variable SUMA que contenga las sucesivas sumas parciales
(SUMA se hace igual a cero al inicio). Observemos que el algoritmo
correspondiente deberá utilizar sucesivamente instrucciones tales como:
leer número
si N < 0 entonces
escribir SUMA
si-no
SUMA ←SUMA+número
fin-si
que se pueden repetir muchas veces; éstas constituyen el cuerpo del bucle.
Una vez se ha decidido el cuerpo del bucle, se plantea la cuestión de
cuántas veces se debe repetir. De hecho conocemos ya la necesidad de contar con
una condición para detener el bucle. En el Ejemplo 8, se pide al usuario el número
N de números que desea sumar, esto es, el número de iteraciones del bucle.
Usamos un contador de iteraciones, TOTAL, que se inicializa a N y a continuación
se decrementa en uno cada vez que el bucle se repite; para ello introducimos una
acción más al cuerpo del bucle: TOTAL ← TOTAL -1. También podríamos
inicializar la variable TOTAL en 0 o en 1, e ir incrementándolo en uno, en cada
iteración, hasta llegar al número deseado N.
102
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Ejemplo 8:
Hallar la suma de N números, a través de una estructura repetitiva
algoritmo suma_números
{leer número total de números a sumar en variable N}
TOTAL ← N
SUMA ← 0 { la suma parcial es 0 al inicio}
{comienzo de bucle}
mientras que TOTAL > 0 hacer
leer número
SUMA ← SUMA+número
TOTAL ← TOTAL-1
fin_mientras
{fin del bucle}
escribir “la suma de los” , N , “números es “ , SUMA
Aunque la condición de finalización puede evaluarse en distintos lugares
del algoritmo, no es recomendable que ésta se pueda efectuar a mitad del cuerpo
del bucle, por lo que es bueno que se produzca al principio o al final del mismo.
Según donde se sitúe la condición de salida, dará lugar a distintos tipos de
estructuras repetitivas que analizaremos a continuación: estructura desde-hasta,
estructura mientras y estructura repetir-hasta_que.
3.4.3.1" ESTRUCTURA DESDE-HASTA
Esta estructura consiste en que la condición de salida se basa en un
contador que cuenta el número de iteraciones. Por ejemplo, el ejemplo 8 podría
hacerse de la siguiente manera:
desde i = 1 hasta N con_incremento 1 hacer
leer número
SUMA ← SUMA + número
fin_desde
donde i es un contador que cuenta desde un valor inicial (1) hasta el valor final (N)
con los incrementos que se consideren (de uno en uno en este caso). Esta es la
llamada estructura Desde (“for”), que es la más simple desde el punto de vista de
la condición de salida, ya que viene predeterminada por el código. Su utilidad
reside en el hecho de que, en muchas ocasiones, se conoce de antemano el número
ALGORITMOS Y PROGRAMAS
103
de iteraciones. Esta estructura ejecuta las acciones del cuerpo del bucle, un número
especificado de veces y de modo automático controla el número de iteraciones. Su
formato en pseudocódigo es:
desde v=vi hasta vf hacer
<acciones>
.
.
fin_desde
v: variable índice
vi, vf: valores inicial y final de la variable
La variable índice o de control normalmente será de tipo entero y es normal
emplear como identificador, las letras I,J,K como herencia de los índices y
subíndices utilizados en cálculo científico. El incremento de la variable índice es 1
en cada iteración si no se indica expresamente lo contrario. Si debemos expresar
incrementos distintos de +1 el formato de la estructura es:
desde v = vi hasta vf inc incremento hacer
<acciones>
si vi > vf entonces usar
.
en lugar de
inc incremento
.
la expresión
dec decremento
fin_desde
Obviamente, si el valor inicial de la variable índice es menor que el valor
final, los incrementos deben ser positivos, ya que en caso contrario la secuencia de
acciones no se ejecutaría. De igual modo si el valor inicial es mayor que el valor
final, el incremento debe ser en este caso negativo. Así:
desde I=20 hasta 10 hacer
<acciones>
fin_desde
no ejecutaría nunca el cuerpo del bucle.
FORTRAN
BASIC
DO n I =M1, M2, M3
<acciones>
n CONTINUE
FOR V = Vi TO Vf
<acciones>
NEXT V
n : etiqueta de fin de bucle
M1: valor inicial del contador
M2: valor final del contador
M3: valor de incremento (+ ó -)
FOR V = Vi TO Vf STEP X
<acciones>
NEXT V
PASCAL
C
104
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
for v:=vi to vt do
<accion o bloque de acciones>
for(v=vi; v<=vf; vt+=step)
<accion o bloque de acciones >
(más genéricamente)
for(inicio;condición;actualización)
for v:=vi downto vt do
<accion o bloque de acciones >
<accion o bloque de acciones >
3.4.3.2" ESTRUCTURA MIENTRAS
Cuando la condición de salida del bucle se realiza al principio del mismo,
éste se ejecuta mientras se verifica una cierta condición. Es la llamada estructura
repetitiva mientras (“while”); en ella el cuerpo del bucle se repite mientras se
cumple una determinada condición. Su pseudocódigo es:
mientras condición hacer
<acciones>
fin_mientras
Cuando se ejecuta la instrucción mientras, la primera cosa que sucede es la
evaluación de la condición. Si es falsa, no se ejecuta ninguna acción y el programa
prosigue en la siguiente instrucción a la finalización del bucle; si la condición es
verdadera, entonces se ejecuta el cuerpo del bucle. No todos los lenguajes incluyen
la estructura mientras.
PASCAL
C
while (condicion) do
<accion o bloque de acciones>
while (condicion)
<accion>
Obsérvese que en una estructura mientras si la primera evaluación de la condición
es falsa, el cuerpo del bucle nunca se ejecuta. Puede parecer inútil ejecutar el
cuerpo del bucle cero veces, ya que no tendrá efecto en ningún valor o salida; sin
embargo, puede ser una acción deseada. Por ejemplo el siguiente bucle para
procesar las notas de unos examenes contando el número de alumnos presentados
dejará de ejecutarse cuando el numero leído sea negativo. Si la primera nota
introducida fuera negativa, la acción deseada es, efectivamente, que no se ejecute el
bucle ninguna vez.
C←0
leer nota
mientras nota ≥ 0 hacer
{procesar nota}
ALGORITMOS Y PROGRAMAS
105
C ← C+1
leer nota
fin_mientras
3.4.3.3" ESTRUCTURA REPETIR-HASTA_QUE
En esta estructura la condición de salida se sitúa al final del bucle; el bucle se
ejecuta hasta que se verifique una cierta condición. Es la llamada estructura
Repetir-hasta (“repeat-until”). Existen muchas situaciones en las que se desea
que un bucle se ejecute al menos una vez, antes de comprobar la condición de
repetición. Para ello la estructura repetir-hasta_que se ejecuta hasta que se cumpla
una condición determinada que se comprueba al final del bucle. En pseudocódigo
se escribe:
repetir
<acciones>
hasta_que <condición>
PASCAL
C
repeat
<accion>
...<accion>
until (condicion);
do
<accion o bloque>
while (condicion);
(*)
* (en C se “dice” mientras se cumpla
la condición, no hasta que se cumpla)
El bucle repetir-hasta_que se repite mientras la condición sea falsa, justo lo
opuesto a la estructura mientras. Sea el siguiente algoritmo:
inicio
contador ←1
repetir
leer número
contador ←contador+1
hasta_que contador > 30
escribir “números leídos: 30”
fin
106
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Este bucle se repite hasta que el valor de variable contador exceda a 30, lo que
sucederá después de 30 ejecuciones del mismo. Nótese que si en vez de 30
pusiéramos 0, el cuerpo del bucle se ejecutará siempre al menos una vez.
Ejemplo 9:
Calcular el factorial de un número N, usando la estructura repetir.
inicio
leer N
Factorial ←1
I←1
repetir
Factorial← Factorial * I
I ← I+1
hasta_que I > N
escribir “el factorial del número”, N, “es”, Factorial
fin
Las tres estructuras repetitivas son susceptibles de intercambio entre ellas,
así por ejemplo es posible, sustituir una estructura desde, por una mientras; con
incrementos positivos o negativos de la variable índice. En efecto, la estructura
desde con incremento positivo es equivalente a la estructura mientras marcada con
la A), y la estructura desde con incremento negativo es equivalente a la estructura
mientras marcada con la B).
A)
v ← vi
mientras v < = vf hacer
<acciones>
v ← v + incremento
fin_mientras
B)
v ← vi
mientras v > = vf hacer
<acciones>
v ← v - decremento
fin_mientras
3.4.3.4" Anidamiento de estructuras repetitivas
En un algoritmo pueden existir varias estructuras repetitivas, siendo sus
bucles respectivos anidados o independientes. Se dice que los bucles son anidados
cuando están dispuestos de tal modo que unos son interiores a otros. Nótese que, en
ningún caso, se admite que sean cruzados, pues su ejecución sería ambigua (Ver
Figura 3.14 donde las líneas indican el principio y el fin de cada bucle).
ALGORITMOS Y PROGRAMAS
Fig. 3.14.
107
Posiciones relativas de los bucles
En las estructuras repetitivas anidadas, la estructura interna debe estar
incluida totalmente dentro de la externa, no pudiendo existir solapamiento entre
ellas. Las variables índices o de control de los bucles toman valores tales que por
cada valor de la variable índice del ciclo externo se ejecuta totalmente el bucle
interno.
Ejemplo 10:
Calcular los factoriales de n números leídos por el teclado.
El problema consiste en realizar una primera estructura repetitiva de n iteraciones
del algoritmo de cálculo del factorial, que a su vez se efectúa con una segunda
estructura repetitiva.
inicio
leer n
{lectura de la cantidad de números}
desde i = 1 hasta n hacer
leer NUMERO
FACTORIAL ← 1
desde j = 1 hasta NUMERO hacer
FACTORIAL ←FACTORIAL *j
fin_desde
escribir “el factorial del número”, NUMERO, “es”, FACTORIAL
fin_desde
fin
108
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Nótese que cada valor del contador i, el bucle interno cuyo contador es j, se ejecuta
totalmente por lo que las variables que sirven de contadores en ambos bucles deben
ser distintas. (No es necesario que las estructuras anidadas sean iguales; podríamos
haber anidado un mientras o un repetir dentro del desde).
3.4.3.5" Bucles infinitos
A pesar de lo dicho hasta ahora, podemos encontrarnos en la práctica con
bucles que no exigen una finalización y otros que no la incluyen en su diseño. Por
ejemplo, un sistema de reservas de líneas aéreas puede repetir de forma
indeterminada un bucle que permita al usuario añadir o borrar reservas sin ninguna
condición de finalización. El programa y el bucle se ejecutan siempre, o al menos
hasta que el computador se apaga. En otras ocasiones, un bucle no se termina
porque nunca se cumple la condición de salida. Un bucle de este tipo se denomina
bucle infinito o sin fin. Los bucles infinitos no intencionados, causados por errores
de programación, pueden provocar bloqueos en el programa (Ver Ejemplo 11).
Ejemplo 11:
Escribir un algoritmo que permita calcular el interés producido por un capital a las
tasas de interés comprendidos en el rango desde 10 a 20 % de 2 en 2 puntos, a
partir de un capital dado.
leer capital
tasa ←10
mientras tasa < > 20 hacer
interés← tasa *0.01*capital { tasa*capital/100=tasa*0.01*capital}.
escribir “interés producido”, interés
tasa ←tasa+2
fin_mientras
escribir “continuación”
Los sucesivos valores de la tasa serán 10, 12, 14, 16,18,20, de modo que al
tomar ‘tasa’ el valor 20 se detendrá el bucle y se escribirá el mensaje
“continuación”. Supongamos que ahora nos interesa conocer este dato de 3 en 3
puntos; para ello se cambia la última línea del bucle por tasa← tasa+3. Ahora los
valores que tomará tasa serán 10, 13, 16, 19 saltando a 22 y nunca será igual a 20,
dando lugar a un bucle infinito y nunca escribiría “continuación”. Para evitarlo
deberíamos cambiar la condición de finalización por una expresión del tipo:
tasa < 20 o bien tasa ≤ 19
ALGORITMOS Y PROGRAMAS
109
El Ejemplo 11, sugiere además que, a la hora de expresar las expresiones
booleanas de la condición del bucle, se utilice mayor o menor en lugar de igualdad
o desigualdad.
3.4.3.6" Terminación de bucles con datos de entrada
En el caso, necesariamente muy frecuente, de que leamos una lista de
valores por medio de un bucle, se debe incluir algún tipo de mecanismo para
terminar la lectura. Existen cuatro métodos para hacerlo:
1.Simplemente preguntar con un mensaje al usuario, si existen más entradas.
Así en el problema de sumar una lista de números el algoritmo sería:
inicio
Suma ←0
escribir “existen más números en la lista s/n”
leer Resp {variable Resp, tipo carácter}
mientras Resp = “S” o Resp =“s” hacer
escribir “numero”
leer N
Suma ←Suma +N
escribir “existen más números (s/n)”
leer Resp
fin_mientras
fin
Este método a veces es aceptable e incluso útil, pero es tedioso cuando
trabajamos con grandes listas de números, ya que no es muy aconsejable tener que
contestar a una pregunta cada vez que introducimos un dato.
2.Conocer desde el principio el número de iteraciones que ya ha sido visto en
los ejemplos anteriores y que permite emplear a una estructura desde-hasta.
3.Utilizar un valor “centinela”, un valor especial usado para indicar el final
de una lista de datos. En estos casos es especialmente importante, de cara al
usuario, advertir la forma de terminar la entrada de datos, esto es, que valor o
valores indican el fin de la lista.
Por ejemplo, supongamos que se tienen unas calificaciones, comprendidas entre 0
y 100; un valor centinela en esta lista puede ser -999, ya que nunca será una
calificación válida y cuando aparezca se deberá terminar el bucle. Si la lista de
datos son números positivos, un valor centinela puede ser un número negativo que
110
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
indique el final de la lista. El siguiente ejemplo realiza la suma de todos los
números positivos introducidos desde el teclado:
suma ← 0
leer numero
mientras numero >= 0 hacer
suma ← suma + número
leer número
fin_mientras
Obsérvese la ventaja, en este caso, de utilizar una estructura “mientras”,
puesto que el último número leído de la lista no se añade a la suma, si es negativo,
ya que se sale fuera del bucle.
4.Por agotamiento de datos de entrada, consiste en simplemente comprobar
que no existen más datos de entrada. Ello es posible cuando los datos se obtienen a
partir de un fichero, donde se puede detectar el agotamiento de los datos gracias al
signo de fin de fichero (EOF “end of file”). En este caso la lectura de un EOF
supone la finalización del bucle de lectura. En el caso de estar recibiendo datos de
otro computador, el cierre de la conexión también supone el agotamiento de los
datos de entrada.
5070" RTQITCOCEKłP"OQFWNCT
Una vez estudiadas las estructuras de control, hemos de ver cómo se
implementa la descomposición en módulos independientes denominados
subprogramas o subalgoritmos. Un subprograma es una colección de instrucciones
que forman una unidad de programación, escrita independientemente del programa
principal, con el que se asociará a través de un proceso de transferencia, de forma
que el control pasa al subprograma en el momento que se requieran sus servicios y
volverá al programa principal cuando aquél se haya ejecutado. Esta
descomposición nos interesa por dos razones:
1)
Esta asociada al diseño descendente en la programación estructurada, ya
que un subprograma, a su vez, puede llamar a sus propios subprogramas e incluso a
sí mismo, recursivamente.
2)
Permite reutilizar un programa dentro de la resolución de otros problemas
distintos, puesto que los subprogramas se utilizan por el programa principal para
ciertos propósitos específicos, aquellos pueden haber sido escritos con anterioridad
para resolver otros problemas diferentes.
ALGORITMOS Y PROGRAMAS
111
El subprograma recibe datos desde el programa y le devuelve resultados. Se dice
que el programa principal llama o invoca al subprograma. Este, al ser llamado,
ejecuta una tarea y devuelve el control al programa principal. La invocación puede
suceder en diferentes lugares del programa. Cada vez que el subprograma es
llamado, el control retorna al lugar desde donde fue hecha la llamada. Algunos
subprogramas son tan comunes, que están incluidos en el lenguaje de
programación, para ser utilizados directamente en los programas, esto incluye, los
propios operadores aritméticos, operaciones sobre cadenas de caracteres, manejo
del cursor, etc.
Para poder utilizar esta aproximación, hay que respetar una determinada
metodología, denominada abstración procedimental y que consta de dos etapas:
1) Asignar un nombre que identifique e independice cada módulo.
2) Parametrizar adecuadamente la entrada y la salida, a fin de que los datos que
manda al programa principal puedan ser adecuadamente interpretados por el
subprograma y viceversa.
Existen dos tipos de subprogramas: funciones y rutinas o procedimientos, aunque
no todos los lenguajes distinguen entre ellos. Aquí mantendremos esta distinción,
con objeto de facilitar la exposición de la programación modular.
50703" HWPEKQPGU
Matemáticamente una función es una operación que a partir de uno o más
valores, llamados argumentos, produce un valor denominado resultado o valor de
la función, por medio de ciertas operaciones sobre los argumentos. Consideremos
la función:
f ( x) =
x
1+ x2
‘f’ es el nombre de la función y, ‘x’ es el argumento. Para evaluar ‘f’ debemos
darle un valor a ‘x’. Así con x=3 se obtiene el valor 0,3 que se expresa
escribiendo: f (3) = 0, 3 .
Una función puede tener varios argumentos. La función F(x,y) =
x + x − 2 y − y es una función con dos argumentos. Sin embargo, solamente un
único valor se asocia con la función, con independencia del número de argumentos
que tenga ésta.
Todos los lenguajes de programación tienen la posibilidad de manejar funciones,
bien estén ya incorporadas en origen, por el propio lenguaje, bien sean definidas
por el usuario. Las funciones están diseñadas para realizar tareas específicas a
112
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
partir de una lista de valores (argumentos) y devolver un único valor al programa
principal. Se llama o evoca una función, utilizando su nombre en una expresión
con los argumentos encerrados entre paréntesis, que deben coincidir en cantidad,
tipo y orden con los que la función fue definida en su momento.
Supongamos que durante la ejecución del programa principal nos encontramos con
una instrucción, y = raízcua (A + cos (x)). El control, entonces, pasará a evaluar la
función raizcua. Al hacerlo, se pasa primero al subprograma (función) coseno y se
calcula cos (x). Una vez obtenido A+cos (x) donde A es una constante, este valor
se utiliza como argumento de la función raizcua, que evalúa el resultado final
según las instrucciones que la definan. El resultado correspondiente devolverá al
lugar desde donde fue llamada para ser almacenado en la variable ‘y’ del programa
que la ha llamado. Las funciones incorporadas al lenguaje en origen se denominan
funciones internas o intrínsecas (caso de sen, cos, etc.), mientras que las funciones
definidas por el programador se deben codificar mediante una definición de
función por parte del mismo. Se supone que la relación de funciones internas de
cada lenguaje es conocida por el programador que sólo debe llamarlas cuando las
necesite, pero no definirlas. El mayor interés para el programador reside por tanto
en las funciones definidas por el usuario.
3.5.1.1" Definición de funciones
Una función, como tal subprograma, tiene una constitución similar a un
programa. Por consiguiente, constará de una cabecera con el nombre y los
argumentos de la función, seguida por el cuerpo de la función, formado por una
serie de acciones o instrucciones cuya ejecución produce un valor, el resultado de
la función, que se devolverá al programa principal. La expresión de una función es:
función nombre-función(par1,par2,par3...)
<acciones>
fin función
par1,par2, ,
lista de parámetros formales o argumentos: son nombres
de identificadores que sólo se utilizan dentro del cuerpo
de la función.
nombre-función
nombre asociado con la función, que será un nombre de
identificador válido sobre el que se almacenará el
resultado.
<acciones>
instrucciones que constituyen la función, y que deben
contener al menos una acción que asigne un valor como
resultado de la función.
ALGORITMOS Y PROGRAMAS
113
En pseudocódigo antes del final debe aparecer nombre-función ← expresión.
Ejemplo 12:
Escribir la función factorial
función factorial (X)
F←1
desde j=1 hasta X hacer
F←F*j
fin-desde
factorial ← F
fin
Obsérvese que se ha utilizado el identificador que devuelve el valor de la función al
acabar la ejecución de la misma, en lugar de haber utilizado este identificador
sustituyendo la variable F, con lo que nos ahorraríamos una línea de código. Esto
es una exigencia de algunos compiladores.
3.5.1.2" Invocación a las funciones
Una función puede ser llamada sólo mediante una referencia directa a la
misma de la forma siguiente:
nombre-función (lista de parámetros actuales)
nombre función
función que es invocada.
lista de parámetros actuales
constantes, variables, expresiones, valores de
funciones, nombres de subprogramas, que se
corresponden con los parámetros formales, que
hemos visto durante en la declaración de funciones.
Al invocar una función, hay que pasarle una serie de parámetros, a fin de
proporcionarle los argumentos de entrada necesarios para poder ejecutar sus
acciones, para ello distinguiremos entre los argumentos de la definición de la
función (parámetros formales o mudos) y los argumentos utilizados en su
invocación (parámetros actuales). Cada vez que se llama a una función, se
establece sistemáticamente una correspondencia entre parámetros formales y
actuales. En consecuencia, debe haber exactamente una correspondencia, tanto en
114
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
número como en tipo, de los parámetros actuales con los formales presuponiéndose
una correspondencia, uno a uno, de izquierda a derecha entre ambos. Una llamada
a la función implica los siguientes pasos:
1.
2.
3.
A cada parámetro formal se le asigna el valor real de su
correspondiente parámetro actual.
Se ejecuta el cuerpo de acciones de la función.
Se devuelve el valor de la función y se retorna al punto de llamada.
Ejemplo 13:
Escribir la función: y = xn (potencia n de x, tanto si es positiva, como negativa) y
utilizarla para calcular 1/(2.5)3
función potencia (x, n)
inicio
parámetros formales (real y entero)
y←1
función interna (valor absoluto)
desde i = 1 hasta abs(n) hacer
y←y*x
fin_desde
si n < 0 entonces y ← 1/y
potencia ← y
fin
Su utilización sería:
z ← potencia (2.5, -3)
parámetros actuales
Transferencia: Una vez que los parámetros formales toman los valores de sus
correspondientes parámetros actuales x←2.5 , n←3, se ejecuta el cuerpo de la
función, devolviendo sus resultados al programa principal, resultando: z←0.064
50704" RTQEGFKOKGPVQU"Q"UWDTWVKPCU
Aunque las funciones son herramientas de programación muy útiles para la
resolución de problemas, su alcance está limitado por el hecho de devolver un solo
valor al programa principal. Con frecuencia se requieren subprogramas que
intercambien un gran número de parámetros, por lo que existen procedimientos o
subrutinas, subprogramas que ejecutan un módulo o proceso específico, sin que
ningún valor de retorno esté asociado con su nombre. Un procedimiento se invoca
normalmente, desde el programa principal mediante su nombre (identificador) y
ALGORITMOS Y PROGRAMAS
115
una lista de parámetros actuales; en algunos lenguajes se tiene que hacer a través de
una instrucción específica llamar_a (call). Las funciones devuelven un sólo valor,
mientras las subrutinas pueden devolver ninguno o varios.
La forma de expresión de un procedimiento es similar a la de funciones:
procedimiento nombre(lista de parámetros formales)
<acciones>
fin_procedimiento
El procedimiento se llama mediante la instrucción:
[llamar_a] nombre (lista de parámetros actuales)
Ejemplo 14:
Usar un procedimiento que escriba en la pantalla tantos signos # como el
valor del cociente de sus dos argumentos, y tantos signos $ como el resto de la
división entera, escribiendo un programa que muestre del modo gráfico indicado el
cociente y el resto de: M/N y de (M+N)/2, usando el procedimiento.
Procedimiento
Algoritmo
principal
procedimiento división(DIVIDENDO, DIVISOR)
COCIENTE ← DIVIDENDO/DIVISOR {división entera}
RESTO ← DIVIDENDO - COCIENTE * DIVISOR
desde i=1 hasta COCIENTE hacer
escribir ‘#
fin-desde
desde i=1 hasta RESTO hacer
escribir ‘$
fin-desde
fin
algoritmo aritmética
inicio
leer M, N
llamar_a división(M, N)
llamar_a división(M+N, 2)
fin
Como ocurre con las funciones, cuando se llama a un procedimiento, cada
parámetro formal se sustituye por su correspondiente parámetro actual. Así, en la
primera llamada, se hace DIVIDENDO←M y DIVISOR←N.
116
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
En programación modular, es un buen consejo incluir comentarios y
documentación que describan brevemente lo que hace la función, lo que
representan sus parámetros o cualquier otra información que explique la definición
de la función, y que facilite su utilización. Esto es útil, ya que, es normal que un
programador cuente con un buen número de funciones, ya codificadas con
anterioridad, a las que puede recurrir para la resolución de distintos problemas,
durante su trabajo de programación.
50705" ıodkvq"fg"ncu"Xctkcdngu
Para ser consecuente con la abstracción procedimental, en la que se basa la
programación modular, hemos de garantizar la independencia de los módulos
exigiendo dos condiciones básicas, no siempre fáciles de cumplir:
a) Cada módulo se diseña sin conocimiento del diseño de otros módulos.
b) La ejecución de un subprograma particular no tiene por qué afectar a los
valores de las variables que se usan en otros subprogramas.
La programación modular permite, en muchos casos, el anidamiento de
subprogramas, de forma que el programa principal llama a un subprograma, éste a
su vez lo hace a un segundo que puede ser el mismo y así sucesivamente. En cada
una de estas llamadas se establece la necesaria correspondencia entre parámetros
actuales del programa llamante y los parámetros formales del programa invocado.
En este proceso de ejecución de procedimientos anidados, es necesario considerar
el ámbito de actuación de cada identificador, ya que finalmente en el programa
ejecutable se unirán en un bloque de código único; al juntarse, programa principal
y sus subprogramas, que han sido escritos de forma independiente, puede plantear
problemas relacionados con los identificadores de variables utilizados en las
distintas partes del código. Para resolver este problema, las variables utilizadas en
los programas principales y subprogramas se clasifican en dos tipos:
Una variable local es aquella que está declarada y es utilizada dentro de un
subprograma y es distinta de las posibles variables que con el mismo nombre,
pueden estar declaradas en cualquier otra parte del programa. Por tanto su
significado y uso se confina al procedimiento o función en que está declarada; esto
significa que cuando otro subprograma utiliza el mismo nombre, en realidad se
refiere a una posición diferente en memoria. Se dice entonces que tales variables
son locales al subprograma en el que están declaradas. Si un subprograma asigna
un valor a una de sus variables locales, este valor no es accesible al resto de
subprogramas, a menos que demos instrucciones en sentido contrario.
ALGORITMOS Y PROGRAMAS
117
Una variable global es aquella que está declarada para el programa o algoritmo
completo, esto es, tiene validez para el programa principal y todos sus
subprogramas. Las variables globales tienen la ventaja de permitir a los diferentes
subprogramas compartir información, sin que tengan que figurar en las
correspondientes listas de transferencia de parámetros entre programas.
El uso de variables locales tiene ventajas, siendo la más importante el hecho de
facilitar el uso de subprogramas independientes, siempre que la comunicación entre
el programa principal y los subprogramas funcione adecuadamente, a través de las
listas de parámetros actuales y formales. Para utilizar un procedimiento, ya
utilizado y comprobado, sólo necesitamos conocer que hace, sin tenernos que
preocupar por los detalles de su codificación interna (¿Cómo lo hace?). Esta
característica hace posible por un lado dividir grandes proyectos en módulos
autónomos que pueden codificar diferentes programadores que trabajan de forma
independiente y por otro facilitan la reusabilidad del software.
Llamaremos ámbito (scope) de un identificador, sea variable, constante o
procedimiento, a la parte del programa donde se le reconoce como tal. Si un
procedimiento está definido localmente respecto a otro procedimiento, tendrá
significado sólo dentro del ámbito de ese procedimiento. A las variables les sucede
lo mismo; si están definidas localmente dentro de un procedimiento, su significado
o uso se confina a cualquier función o procedimiento que pertenezca a esa
definición. Los lenguajes que admiten variables locales y globales suelen tener la
posibilidad explícita de definir dichas variables como tales en el cuerpo del
programa, o lo que es lo mismo, ofrecen la posibilidad de definir su ámbito de
actuación. Para ello se utilizan las cabeceras de programas y subprogramas, donde
figuran declaradas las variables, de donde se puede extraer el ámbito
correspondiente de cada una. (Ver Figura 3.15)
118
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
programa XX
variables A,B
procedimiento P1 (x,y)
variables D
funcion F (u,v)
variable G
inicio
<cuerpo F>
fin
inicio
<cuerpo F>
fin
ıodkvq
Kfgpvkhkecfqt
Cuerpo del programa
Cuerpo de P1
Cuerpo de F
Cuerpo de P2
A, B, P1, P2
A, B, D, x, y, F, P1, P2
A, B, D, G, x, y, u v, F, P1
A, B, I, J, r, s, P1, P2
procedimiento P2 (r,s)
variable I,J
inicio
<cuerpo P2>
fin
inicio
<cuerpo programa>
fin
Fig. 3.15
Ejemplo de ámbito de definición de variables
Las variables definidas en un ámbito son accesibles en él y en todos sus
procedimientos interiores. Así la Figura 3.15 muestra el esquema de un ejemplo de
un programa principal con diferentes subprogramas y el ámbito correspondiente de
sus identificadores, señalando las partes del programa a las que tienen acceso los
diferentes identificadores (variables, procedimientos y funciones). Nótese que es
perfectamente posible que P2 sea accesible por P1 y viceversa, y que un
subprograma sea accesible por sí mismo, (a esta posibilidad le dedicaremos la
sección siguiente: recursividad).
Ejemplo 15:
Considérese el siguiente programa y ejecútese paso a paso:
algoritmo XXX
{variable global A}
{variables locales: X, Y}
inicio
X← 5
A← 10
Y← F(X)
escribir X,A,Y
fin {algoritmo}
función F(N)
ALGORITMOS Y PROGRAMAS
119
{comienzo función}
{variable global A}
{variable local X}
inicio
A← 6
X←12
F←N+5+A
fin {función}
A la variable global A se puede acceder desde el algoritmo XXX y desde la
función F. Sin embargo, X representa a dos variables distintas: una local al
algoritmo que sólo se puede acceder desde él y otra local a la función. Al ejecutar
el algoritmo XXX se obtendrían los siguientes resultados:
1)
X←5, A←10, Y←F(5), la invocación de la función F(N) da lugar al paso
del parámetro actual X al parámetro formal N.
2)
Al ejecutarse la función, se hace N←5 ya que el parámetro actual en la
llamada del programa principal F(X) se asigna al parámetro formal N.
A←6, cosa que modifica el valor de A en el algoritmo principal por ser A
global.
X←12 sin que se modifique el valor X en el algoritmo principal, porque X
es local.
F←16 (5+5+6)
3)
El resultado de la función se almacena en Y, de forma que Y←16.
4)
El resultado final, es que se escriba la línea
5 6 16
ya que X es el valor de la variable local X en el módulo principal; A toma
el valor de la última asignación (que fue dentro de la función) e Y toma el
valor de la función F(X).
Del Ejemplo 15 sacamos la conclusión de que, en general, toda la información que
intercambia un programa con sus subprogramas, debe vincularse a través de la lista
de parámetros, y no mediante variables globales. Si se usa este último método, se
corre el riesgo de obtener resultados inesperados, indeseables en muchos casos,
llamados efectos laterales; En el Ejemplo 15, posiblemente en contra de nuestros
deseos, la variable global A ha cambiado de valor al ejecutarse la función, cosa que
no ha ocurrido con X.
50706" Rcuq"fg"rctâogvtqu
120
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Los parámetros que intervienen en programación modular pueden jugar distintos
papeles:
entrada: Proporcionan valores desde el programa que llama y que se
utilizan dentro de un subprograma. Las entradas de un subprograma se
dice, en general, que son sus argumentos.
salida: Corresponden a los resultados del subprograma. En el caso de una
función el valor de retorno, se utiliza como salida.
entrada/salida: Un mismo parámetro se utiliza tanto para mandar
argumentos, como para devolver resultados.
Como veremos a continuación, el papel que juega cada parámetro no es suficiente
para caracterizar su funcionamiento ya que los distintos lenguajes de programación
utilizan distintos métodos para pasar o transmitir parámetros, entre un programa y
sus subprogramas. Es el correcto intercambio de información, a través de
parámetros, quien hace que los módulos sean independientes, siendo preciso
conocer el método utilizado por cada lenguaje particular, ya que esta elección
afecta a la propia semántica del lenguaje. Dicho de otro modo, un mismo programa
puede producir diferentes resultados, bajo diferentes sistemas de paso de
parámetros. Veamos los principales métodos de transmisión de parámetros.
3.5.4.1" Paso por valor
El paso por valor se utiliza en muchos lenguajes de programación, la razón
para ello es la analogía que presenta con los argumentos de una función, donde los
valores se proporcionan para el cálculo de resultados. Los parámetros se tratan
como variables locales de forma que los parámetros formales reciben como valores
iniciales los valores de los parámetros actuales. A partir de ellos se ejecutan las
acciones descritas en el subprograma. Otra característica es que no tiene relevancia
el que los argumentos sean variables, constantes o expresiones, ya que sólo importa
el valor de la expresión que constituye el argumento o parámetro formal.
A←5
B←7
llamar
PROC1
(A, 18, B * 3 + 4)
5
18
25
procedimiento PROC1 (X, Y, Z)
Fig. 3.16
Ejemplo de paso por valor
ALGORITMOS Y PROGRAMAS
121
La Figura 3.16 muestra el mecanismo de paso por valor de un procedimiento con
tres parámetros, que se resume así. En el momento de invocar a PROC1 la
situación es ésta:
Primer parámetro: valor de la variable A = 5;
Segundo parámetro: valor constante = 18;
Tercer parámetro: valor de la expresión B* 3+4 = 25.
El paso por valor asigna estos tres, respectivamente a los parámetros formales X,
Y, Z al iniciar la ejecución del procedimiento PROC1.
Aunque el paso por valor es sencillo, tiene una limitación importante: no existe
ninguna posibilidad de otra conexión con los parámetros actuales, y por tanto los
cambios que se produzcan por efecto del subprograma no producen cambios en los
argumentos originales. Por consiguiente, no se pueden devolver valores de retorno
al punto de llamada. Es decir, todos los parámetros son solo de entrada y el
parámetro actual no puede modificarse por el subprograma, ya que cualquier
cambio realizado en los valores de los parámetros formales durante la ejecución del
subprograma se destruye cuando finaliza éste. Así, en el ejemplo de la figura 3.16,
aunque X, Y, Z variasen en el interior del procedimiento, A y B seguirían valiendo
5 y 7, en el programa principal.
Esta limitación, no obstante, constituye al mismo tiempo una ventaja en
determinadas circunstancias, ya que asegura que las variables de un módulo no
serán modificadas al invocar a una subrutina o función, hagan éstas lo que hagan.
Ejemplo 16:
Escribir un programa y una función que por medio del paso por valor obtenga el
máximo común divisor de dos números.
algoritmo Maximo_comun_divisor
inicio
leer (x, y)
m ← mcd (x, y)
escribir (x, y, m)
fin
funcion mcd(a, b): entero
{a, b: enteros}
inicio
mientras a <> b hacer
si a > b
entonces a ← a - b
sino b ← b - a
fin_si
122
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
fin_mientras
mcd ← a
fin
Al ejecutarse este algoritmo se producirán los siguientes resultados:
x
10
Variable del algoritmo
y
m
25
Variables de la función
a
b
mcd
10
25
10
15
10
5
5
5
5
5
Obsérvese que el paso de mcd desde la función al programa principal es posible
gracias a que ambos comparten el identificador mcd.
3.5.4.2" Paso por referencia
En numerosas ocasiones se requiere que ciertos parámetros sirvan como parámetros
de salida o de entrada/salida, es decir, se devuelvan los resultados a la unidad o
programas que llama al subprograma. Este método se denomina paso por
referencia. El programa que llama pasa al subprograma llamado la dirección de
memoria donde se halla almacenado el parámetro actual (que está en el ámbito de
la unidad llamante), es decir, se pasa una referencia a la variable, no el valor que
contiene. Toda referencia al correspondiente parámetro formal se trata como una
referencia a la variable, cuya dirección se ha pasado. Con ello, una variable pasada
como parámetro actual es compartida, es decir, también se puede modificar
directamente por el subprograma (además de utilizar su valor). Si comparamos la
Figura 3.16 con 3.17, observamos que en esta última los parámetros formales se
utilizan para referirse a las posiciones de memoria de los parámetros actuales. Por
tanto utilizamos esta referencia para pasar información de entrada y/o salida.
Nótese que un cambio en el parámetro formal durante la ejecución del
subprograma, se refleja en un cambio en el correspondiente parámetro actual (ver
Ejemplo 17), ya que ambos se refieren a la misma posición de memoria.
A←5
B←7
C←B*3+4
llamar_a PROC1(
A,
B,
C)
5
7
25
procedim PROC1(REF X, REF Y, REF Z)
direcciones o
posiciones
de memoria
ALGORITMOS Y PROGRAMAS
Fig. 3.17.
123
Paso por referencia
Cuando un parámetro se pase por valor lo denotaremos, en pseudocódigo poniendo
REF delante del parámetro formal.
Ejemplo 17:
Dado el siguiente esquema de programa, analizar las dos llamadas al
procedimiento, asumiendo que el paso de parámetros se efectúa por referencia.
programa XYZ
{parámetros actuales a, b, c y d paso por referencia}
procedimiento PP(REF x, REF y)
inicio
{procedimiento}
{proceso de los valores de x e y}
fin
(1)
(2)
inicio
{programa}
...
prueba (a,c)
...
prueba (b,d)
..
fin
La primera llamada en (1) conlleva que los parámetros formales x e y se refieran a
los parámetros actuales a y c. Si los valores de x o y se modifican dentro de esta
llamada, los valores de a o c en el algoritmo principal también lo habrán hecho. De
igual modo, cuando x e y se refieren a b y d en la llamada (2) cualquier
modificación de x o y en el procedimiento afectará también a los valores de b o d
en el programa principal.
Nótese, por tanto, que mientras en el paso por valor los parámetros actuales podían
ser variables, constantes o expresiones (pues lo que se pasa es su valor), cuando un
parámetro se pasa por referencia el parámetro actual indicado en la invocación
debe ser siempre una variable que es la forma de referirse a una posición de
memoria.
124
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
3.5.4.3" Comparaciones de los métodos de paso de parámetros.Para examinar de modo práctico los diferentes métodos, consideremos los ejemplos
18 y 19, en los que podemos observar los diferentes valores que toman los
parámetros del mismo programa según sea el método de paso que utilicemos
Ejemplo 18:
Consideremos los siguientes algoritmos y el valor que toman sus variables:
algoritmo ABC
inicio
A ←3
B←5
C ←17
llamar_a SUB(A, B, C)
escribir A,B,C
fin
algoritmo ABC
inicio
A ←3
B←5
C ←17
llamar_a SUB(A, B, C)
escribir A,B,C
fin
procedimiento SUB(x,y,z)
procedimiento SUB(REF x,REF y,REF
z)
inicio
x ← x+1
z ← x+y
fin
inicio
x ← x+1
z ← x+y
fin
(a)
(b)
a) Paso por valor:
No se transmite ningún resultado desde SUBR, por consiguiente ni A, ni B, se
modifican y se escribirá 3, 5, 17, al ejecutarse el programa ABC.
b) Paso por referencia:
Al ejecutar el procedimiento ejecutará:
x=x+1=3+1=4 (almacenado en la posición de A)
z=x+y=4+5=9 (almacenado en la posición de C)
Por lo tanto, el programa escribirá 4, 5, 9.
Es importante señalar que un mismo subprograma puede tener simultáneamente
parámetros pasados por valor y parámetros pasados por referencia, como podemos
ver en el Ejemplo 19.
Ejemplo 19:
ALGORITMOS Y PROGRAMAS
125
Consideremos el siguiente programa M con un subprograma N que tiene dos
parámetros formales: i pasado por valor, y j, por referencia.
programa M
inicio
A←2
B←3
llamar_a N(A,B)
escribir A,B
fin {programa M}
procedimiento N(i, REF j)
{ i por valor, j por referencia}
inicio
i ← i+10
j ← j+10
escribir i , j
fin {procedimiento N}.
Al ejecutar el programa M, se escribirán: A y B en el programa principal e i y j en
el procedimiento N. Como i es pasado por valor, se transmite el valor de A a i, es
decir, i=A=2. Cuando i se modifica (por efecto de la instrucción, i ← i+10) a 12 , A
no cambia, y por consiguiente a la terminación de N, A sigue valiendo 2. El
parámetro B se transmite por referencia. Al comenzar la ejecución de N, el
parámetro j se refiere a la variable B, y cuando se suma 10 al valor de j, el valor de
B se cambia a 13. Cuando los valores i, j se escriben en N, los resultados son: 12 y
13.
Cuando retornamos al programa M y se imprimen los valores de A y B, sólo ha
cambiado el valor B. El valor de i=12 se pierde en N cuando éste termina. El valor
de j también se pierde, pero éste es una dirección, no el valor 13. Se escribirá como
resultado final (de la instrucción escribir A,B) 2, 13.
Señalemos finalmente que muchos lenguajes de programación permiten pasar
parámetros por valor y por referencia, especificando cada modalidad. La elección
entre un método u otro viene determinado por cada programa en particular y por el
objetivo de evitar efectos laterales no deseados.
5080" EQPEGRVQ"FG"RTQITCOCEKłP"GUVTWEVWTCFC
126
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Cuando introdujimos las estructuras de control indicamos que la orientación
no excluyente de este texto iba hacia la programación estructurada, sin detallar en
qué consistía este enfoque. Ahora estamos en condiciones de hacerlo.
Llamaremos programa propio a un programa que cumpla las siguientes
características:
1.2.3.-
Posee un solo punto de entrada y uno de salida.
Existen caminos que van desde la entrada hasta la salida, que pasan por
todas las partes e instrucciones del programa.
Todas sus instrucciones son ejecutables y no presenta bucles infinitos.
Desde 1966, gracias a diferentes trabajos teóricos, sabemos que un programa
propio puede ser escrito utilizando solamente los tres tipos de estructura de control
que hemos analizado (secuenciales, selectivas, repetitivas). Llamaremos
programación estructurada a un conjunto de técnicas de programación que
incluye :
• Uso del diseño descendente.
• Descomposición modular, con independencia de los módulos.
• Utilización de las tres estructuras de control citadas.
•
La programación estructurada, gracias a la utilización exclusiva de las tres
estructuras de control, permite realizar fácilmente programas legibles.
Sin embargo, en determinadas circunstancias, parece necesario realizar
bifurcaciones incondicionales, no incluidas en las estructuras de control estudiadas,
para lo que hay que recurrir a la instrucción ir_a (goto).
FORTRAN
BASIC
GO TO etiqueta
GOTO nº de linea
PASCAL
C
goto etiqueta
GOTO etiqueta
Esta instrucción siempre ha sido problemática para los programadores y se
recomienda evitar su utilización. Aunque ir_a es una instrucción incorporada por
todos los lenguajes de programación, existen algunos lenguajes como FORTRAN y
BASIC que dependen más de ella que otros. En general, no existe ninguna
necesidad de utilizarla, ya que cualquier algoritmo o programa escrito con
ALGORITMOS Y PROGRAMAS
127
instrucciones ir_a se puede reescribir de forma que lleve a cabo las mismas tareas
prescindiendo de bifurcaciones incondicionales. Sin embargo, esta instrucción es
útil en algunas situaciones excepcionales, como en ciertas salidas de bucles o
cuando se encuentra un error u otra condición brusca de terminación. La
instrucción ir_a puede ser utilizada para saltar directamente al final de un bucle,
subprograma o procedimiento; la instrucción a la cual se salte debe tener una
etiqueta o numero de referencia. Por ejemplo, un programa puede diseñarse de
forma que finalice cuando se detecte un determinado error, de la forma:
si <condición error>
entonces ir a 100
.
100 fin
En cualquier caso y para preservar las ventajas de la programación estructurada,
conviene saber que en los lenguajes más desarrollados existen instrucciones
específicas de ir_a_fin_de_bucle, continuar_bucle e ir_a_fin_de_rutina para
evitar usos indiscriminados de los saltos incondicionales.
5090" TGEWTUKXKFCF
Entenderemos por recursividad la propiedad que tienen muchos lenguajes de
programación de que los subprogramas puedan llamarse a sí mismos. Esta idea es
interesante pues es una alternativa a la repetición, si nos enfrentamos a problemas
con “estructura de solución recursiva”. Esta estructura recursiva se presenta en
situaciones como la siguiente: Sea un problema A; al diseñar su algoritmo
conseguimos dividirlo en dos partes B y C. Si una de estas partes, por ejemplo C,
es formalmente idéntica a A, el problema es recursivo ya que la resolución de A se
basa en C, que a su vez se descompone de la misma forma y así sucesivamente. En
términos de programación esto supone utilizar un procedimiento para computar el
problema, que va a llamarse a sí mismo para resolver parte de ese problema. La
potencia de la recursión reside en la posibilidad de definir un número
potencialmente infinito de operaciones de cálculo mediante un subprograma
recursivo finito. Para que esta solución sea aceptable debe haber un momento en
que ya no sea necesario que el procedimiento se llame a sí mismo ya que si la
recursión continuara por siempre, no hablaríamos de un genuino algoritmo.
Insistamos que la solución recursiva no es nunca única, ya que siempre es posible
utilizar una estructura repetitiva, en lugar del planteamiento recursivo. No obstante,
en algunos casos la solución recursiva es la solución natural del problema, y por
tanto la más clara. Veamos algunos ejemplos:
128
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Ejemplo 20:
Obtener una función recursiva que calcule el factorial de un entero no negativo.
Este problema ya ha sido resuelto de forma no recursiva, ahora lo haremos
utilizando la condición recursiva: n! = n * (n-1) ! si n = > 0 y n! = 1 si n = 0
función Factorial (n)
inicio
si n = 0
entonces Factorial ←1
sino Factorial ← n * Factorial (n-1)
fin_si
fin
Para demostrar cómo esta versión recursiva de FACTORIAL calcula el valor de n!,
consideremos el caso de n = 3. Un proceso gráfico se representa en la Figura 2.18.
Los pasos sucesivos extraídos de la Figura 2.18 son:
5
como n no es 0 se genera
otra operacion
8
HCEVQTKCN
4
4
HCEVQTKCN
3
2
Fig. 2.18.
FACTORIAL (2) = FACTORIAL (1) * 2 = 2
3
HCEVQTKCN
como FACTORIAL de 0 es
siempre 1, este valor se
asignara a la variable
FACTORIAL, y ahora se
realizara el proceso en sentido
contrario ascendente
FACTORIAL (3) = FACTORIAL (2) * 3 = 2.3 = 6
FACTORIAL (1) = FACTORIAL (0) * 1 = 1
3
HCEVQTKCN
Secuencia para el cálculo recursivo de factorial de n
Ejemplo 21:
Leer una lista de números de un fichero y escribirlos en orden inverso.
ALGORITMOS Y PROGRAMAS
129
Para resolver este problema se podrían leer todos los números, invertir su orden y
escribirlos. No obstante, se podría pensar en una solución más sencilla si se hace
una descomposición recursiva del problema. El problema se podría resolver con el
siguiente algoritmo:
algoritmo escribir_en_orden_inverso
leer N
{ Primer número }
leer el resto de los números y escribir_ en_orden_inverso
escribir N {El primer número se escribe el último }
El algoritmo consta de tres acciones, una de las cuales -la segunda- es
semejante al problema inicial. La necesidad de llamar al procedimiento desaparece
cuando no quedan más números por leer, esto es, cuando se ha llegado al fin de
fichero (FF). El algoritmo quedará, por tanto, como:
algoritmo INVERTIR
inicio
leer N
si (N <> FF) entonces
INVERTIR
escribir N
fin
{ hay más números }
Observar que el primer número que se escribirá es el último leído, después de que
el número de llamadas a INVERTIR, sea igual a la cantidad de números que
contiene el archivo. Consecuentemente, el primer número leído será escrito en
último lugar, después de que la llamada recursiva a INVERTIR haya leído y escrito
el resto de los números. Esto supone que el programa, al ejecutarse, deberá guardar
tantas copias del subprograma y sus datos como sean necesarios.
La forma como hace esto el lenguaje de programación no debe importarnos, salvo
que este proceso sature la memoria y aparezca el correspondiente error.
Ejemplo 22:
Escribir una función que calcule recursivamente el término n-esimo de la serie de
Fibonacci, dada por la expresión:
fib(1) = 1
fib(2) = 1
130
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
fib(n) = fib(n-1) + fib(n-2) para n>2
Esta serie fue concebida originalmente como modelo para el crecimiento de una
granja de conejos (proceso claramente recursivo) por el matemático italiano del
siglo XVI, Fibonacci. Como no podía ser menos, esta serie crece muy rápidamente.
Como ejemplo, el término 15 es 610.
función FIBONACCI(n)
inicio
si (n=1) o (n=2)
entonces
FIBONACCI ← 1
sino
FIBONACCI ← FIBONACCI (n-2) + FIBONACCI (N-1)
fin_si
fin_función
La recursión es una herramienta muy potente y debe ser utilizada como una
alternativa a la estructura repetitiva. Su uso es particularmente idóneo en aquellos
problemas que pueden definirse de modo natural en términos recursivos. El caso de
la función factorial es un ejemplo claro.
Insistamos en que, para evitar que la recursión continúe indefinidamente, es preciso
incluir una condición de terminación. Como veremos en el capítulo siguiente, la
posibilidad de implementar la recursividad se debe a la existencia de estructuras de
datos específicos del tipo pila.
50:0" FGUCTTQNNQ"["IGPGTCEKłP"FGN"UQHVYCTG
Una vez hemos visto cómo se podían implementar las estructuras modulares
y de control sobre las que descansa la programación estructurada, volvamos al
problema de la resolución de un problema por medio de un ordenador. De acuerdo
con lo que allí afirmamos, cuando se ha comprobado el programa, éste se podría
dar, en principio, por terminado y el problema abordado como resuelto. Sin
embargo, un programa no puede darse como totalmente terminado hasta que no ha
sido depurado y contrastado con toda una batería de datos de entrada distintos.
Además, una vez se está razonablemente seguro de su funcionamiento, debe
documentarse para que pueda ser utilizado por cualquier usuario, al tiempo que hay
que tomar toda una serie de medidas que faciliten su actualización y
ALGORITMOS Y PROGRAMAS
131
mantenimiento, ya que un programa, siempre debe estar en condiciones de mejorar
sus prestaciones y de adaptarse a pequeños cambios, sin tener que proceder a su
reescritura completa. Aunque estas últimas fases están fuera de la óptica de este
capítulo, conviene retener la totalidad de fases que constituyen el proceso completo
de generación del software y que se esquematiza en la Figura 3.18.
Fig. 3.18
El proceso completo de programación
Para completar el capítulo, demos algunas ideas relacionadas con la programación
de aplicaciones complejas, que dan lugar a la generación de una gran cantidad de
líneas de código.
50:03" KPIGPKGT¯C"FGN"UQHVYCTG
Conviene saber que la tarea de diseño y construcción de un programa
puede ser, en algunos casos, bastante compleja. En las aplicaciones reales, no es
usual que la resolución de un problema implique el desarrollo de un solo programa.
Normalmente cualquier aplicación práctica requiere de más de un programa
individual y conviene considerar alguna de las características que hay que tener en
cuenta al enfrentarse a ellas desde un punto de vista profesional:
A)
Volumen: un proyecto, en la práctica, suele ser grande (decenas de miles
de líneas de código) lo que presenta problemas de:
- Complejidad: El software es complejo y resulta difícil que una única
persona conozca todos los detalles de una aplicación.
- Coordinación: En el desarrollo de una aplicación intervienen muchas
personas. Hay que coordinar el trabajo de todos, de forma que al final
los distintos componentes y módulos encajen.
132
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
B)
Evolución: El software no es estático. Evoluciona con las necesidades del
usuario, los cambios del entorno (nuevo hardware, nueva legislación,
nuevas necesidades, ampliaciones, etc.) deben ser tenidos en cuenta.
C)
Comunicación: Cuando se desarrolla una aplicación es porque, de una
forma u otra, hay alguien interesado en usarla. Antes de comenzar el
desarrollo habrá que concretar con el futuro usuario las características de la
aplicación. Esta comunicación conlleva problemas, pues normalmente el
informático no conoce en profundidad las necesidades del cliente y éste no
sabe discernir la información que es útil para el informático de la que no lo
es.
La ingeniería del software se ocupa del estudio de estos problemas y de sus
soluciones. Se puede definir la ingeniería del software como la disciplina que se
ocupa del establecimiento y uso de principios de ingeniería para obtener software
económico que sea fiable y funcione eficientemente en las máquinas que estén
disponibles en cada momento. La ingeniería del software se ocupa de: la
planificación y estimación de proyectos, análisis de requisitos, diseño del software,
codificación, prueba y mantenimiento. Para realizar estas tareas propone una serie
de métodos, como cualquier otra ingeniería. No obstante, existen grandes
diferencias con éstas, la principal de las cuales procede de la ausencia del proceso
de fabricación que se da en el caso del desarrollo de software. Cuando se
construyen automóviles, una vez diseñados se fabrican. La ausencia de proceso de
fabricación en la ingeniería software hace que el coste de la producción sea
fundamentalmente el coste del diseño.
Por otra parte, el mantenimiento del software es muy diferente al del hardware (o
cualquier otro sistema físico en ingeniería), ya que el software no se desgasta con
el tiempo. El mantenimiento del software tiene que ver con la detección de fallos o
con la necesidad de adaptarlo a unas nuevas circunstancias. En ambos casos el
proceso de mantenimiento no consiste en la sustitución de un componente por otro,
sino en la repetición de parte del proceso de desarrollo.
50:04" EKENQ"FG"XKFC"FGN"UQHVYCTG
La creación de cualquier sistema software implica la realización de tres
pasos genéricos: definición, desarrollo y mantenimiento.
En la fase de definición se intenta caracterizar el sistema que se ha de construir.
Esto es, se trata de determinar qué información ha de usar el sistema, qué funciones
ha de realizar, qué condiciones existen, cuáles han de ser las interfaces del sistema
ALGORITMOS Y PROGRAMAS
133
y qué criterios de validación se usarán. En resumen; se debe contestar
detalladamente a la pregunta: ¿qué hay que desarrollar?.
En la fase de desarrollo se diseñan las estructuras de datos (bases de datos o
archivos) y de los programas; se escriben y documentan éstos y se prueba el
software.
La fase de mantenimiento comienza una vez construido el sistema, coincidiendo
con su vida útil. Durante ella, el software es sometido a una serie de
modificaciones y reparaciones.
La detección de errores durante la definición y el desarrollo se realiza mediante
revisiones de la documentación generada en cada fase. En estas revisiones se
pueden detectar fallos o inconsistencias que obliguen a repetir parte de la fase o
una fase anterior. Este esquema general se puede detallar más, dando lugar a
modelos concretos del ciclo de vida del software. Dos son los paradigmas usados
más frecuentemente: el ciclo de vida clásico y el de prototipos.
3.8.2.1" Ciclo de vida clásico
El ciclo de vida clásico consta de fases, que siguen un esquema en cascada,
análogo al esquema general que acabamos de ver. Este paradigma contempla las
siguientes fases:
Análisis del sistema: El software suele ser parte de un sistema mayor formado
por hardware, software, bases de datos y personas. Por él, se debe
comenzar estableciendo los requisitos del sistema, asignando funciones a
los distintos componentes y definiendo las interfaces entre componentes.
Análisis de los requisitos del software: Antes de comenzar a diseñar el
software se deben especificar las funciones a realizar, las interfaces que
deben presentarse y todos los condicionantes, tales como rendimiento,
utilización de recursos, etc. Como fruto de este análisis se genera un
documento conocido como especificación de requisitos del software.
Diseño: El diseño del software consiste en construir una estructura para el
software que permita cumplir los requisitos con la calidad necesaria. El
diseño concluye con la confección de un documento de diseño. A partir de
él, se debe responder a la pregunta ¿cómo se ha de construir el sistema?.
Codificación: Consiste en plasmar el diseño en programas, escritos en un
lenguaje de programación adecuado.
134
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Prueba: Cuando se han escrito los programas es necesario probarlos. En las
pruebas se debe comprobar que los programas se corresponden con el
diseño, realizan correctamente sus funciones y que el sistema satisface los
requisitos planteados. Es decir, se ha de contestar a la pregunta ¿se ha
construido el sistema que se deseaba?.
Mantenimiento: Esta fase se corresponde con la fase de mantenimiento del
esquema general. Dependiendo de la naturaleza y motivación de cada
operación de mantenimiento concreta, será necesario revisar desde la
codificación, desde el diseño o desde la fase de análisis.
El conjunto de la documentación generada en todas las fases constituye la
configuración del software. Un buen sistema no es solamente un conjunto de
programas que funcionan, sino también una buena documentación. La
documentación es fundamental para un buen desarrollo y es esencial en el proceso
de mantenimiento del software.
3.8.2.2" Ciclo de vida de prototipos
Hay situaciones en que no es posible usar el ciclo de vida clásico,
fundamentalmente debido a la dificultad de establecer los requisitos del software a
priori. En estas situaciones es posible seguir el modelo de ciclo de vida de
prototipos. En esencia, este paradigma se basa en la construcción de un prototipo
durante las primeras etapas del ciclo de vida. Un prototipo es un modelo “a escala
reducida” del sistema que se va a construir. El prototipo incorpora sólo los aspectos
relevantes del sistema y se utiliza como ayuda en la especificación del software,
sirviendo como base tangible sobre la que discutir con el usuario final.
El ciclo de vida comienza con la realización de un breve análisis de los requisitos,
tras el cual se diseña y codifica el prototipo. Sobre el prototipo se discuten y
detallan las especificaciones, modificando el prototipo de acuerdo con éstas,
siguiendo un proceso cíclico. El resultado de este proceso es el documento de
especificación de requisitos del software. Normalmente se desecha posteriormente
el prototipo, diseñándose el sistema definitivo. A partir de este punto se puede
seguir el mismo esquema que un ciclo clásico.
Es posible que el lector quede abrumado por toda esta metodología cuando se está
introduciendo en las técnicas de programación. Sin embargo, es posible que estas
reflexiones le puedan ser de utilidad cuando se enfrente a la tarea de programar
algún problema no trivial y se encuentre con que algo no funciona como debe.
Construir software es una ingeniería y hemos tratado de esbozar sus normas.
ALGORITMOS Y PROGRAMAS
135
3.1. CONCEPTO DE ALGORITMO ..................................................................81
3.2. LA RESOLUCIÓN DE PROBLEMAS Y EL USO DEL ORDENADOR 82
3.2.1 ANÁLISIS DEL PROBLEMA ......................................................................82
3.2.2 DISEÑO DEL ALGORITMO .......................................................................83
3.2.3 PROGRAMACIÓN DEL ALGORITMO......................................................87
3.3. REPRESENTACIÓN DE ALGORITMOS .................................................88
3.3.1 PSEUDOCODIGO.........................................................................................89
3.3.2 ORGANIGRAMAS .......................................................................................90
3.4. ESTRUCTURAS DE CONTROL ................................................................91
3.4.1 ESTRUCTURAS SECUENCIALES .............................................................92
3.4.2 ESTRUCTURAS SELECTIVAS ..................................................................92
3.4.3 ESTRUCTURAS REPETITIVAS .................................................................98
3.5. PROGRAMACIÓN MODULAR ...............................................................110
3.5.1 FUNCIONES ...............................................................................................111
3.5.2 PROCEDIMIENTOS O SUBRUTINAS .....................................................114
3.5.3 ÁMBITO DE LAS VARIABLES ........................................................................116
3.5.4 PASO DE PARÁMETROS .................................................................................119
3.6. CONCEPTO DE PROGRAMACIÓN ESTRUCTURADA .....................125
3.7. RECURSIVIDAD.........................................................................................127
3.8. DESARROLLO Y GENERACIÓN DEL SOFTWARE...........................130
3.8.1 INGENIERÍA DEL SOFTWARE ...............................................................131
3.8.2 CICLO DE VIDA DEL SOFTWARE .........................................................132
CAPÍTULO 4
ARITMÉTICA Y REPRESENTACIÓN DE LA
INFORMACIÓN EN EL COMPUTADOR
Dos de los aspectos básicos que se presentan en el tratamiento de la información
son cómo representarla (de lo cual dependerá sus posibilidades de manipulación) y
cómo almacenarla físicamente. La primera se resuelve recurriendo a un código
adecuado a las posibilidades internas del computador, que abordaremos en el
presente capítulo. La segunda tiene que ver con los llamados soportes de
información y es una cuestión que pertenece al ámbito del soporte físico del
ordenador.
En la raíz de los desarrollos informáticos está el hecho de que todo dato puede ser
representado por un conjunto de bits, circunstancia que permite a la ALU realizar
un gran número de operaciones básicas utilizando su representación binaria. El
paso a códigos binarios es una misión que el computador lleva a cabo
automáticamente, por lo que el usuario puede despreocuparse de este proceso. Sin
embargo es conveniente tener algunas ideas acerca de la forma como el
computador codifica y opera internamente, cuestión indispensable para comprender
determinados comportamientos de la máquina. Para ello empezaremos recordando
algunos conceptos relativos al sistema de numeración binario y a las
transformaciones entre éste y el sistema decimal.
6030" UKUVGOCU"FG"PWOGTCEKłP"GP"KPHQTOıVKEC
Llamaremos sistema de numeración en base b, a la representación de
números mediante un alfabeto compuesto por b símbolos o cifras. Así todo número
se expresa por un conjunto de cifras, contribuyendo cada una de ellas con un valor
que depende:
a) de la cifra en sí,
b) de la posición que ocupa dentro del número.
En el sistema de numeración decimal, se utiliza, b = 10 y el alfabeto está
constituido por diez símbolos, denominados también cifras decimales:
137
138
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} (3.1)
y, por ejemplo, el número decimal 278.5 puede obtenerse como suma de:
200
70
8
0 .5
278 .5
es decir, se verifica que:
278.5 = 2×102 + 7×101 + 8×100 + 5×10-1
Cada posición, por tanto, tiene un peso específico (en el sistema decimal, cada
posición además tiene un nombre):
valor en el ejemplo
nombre
posición 0 peso b0
posición 1 peso b1
posición 2 peso b2
8
7
2
unidades
decenas
centenas
posición -1 peso b-1
...............................................
5
décimas
Generalizando, se tiene que la representación de un número en una base b:
N ≡ ... n4 n3 n2 n1 n0 . n-1 n-2 n-3 ...
(3.2)
es una forma abreviada de expresar su valor, que es:
N ≡ ... n4b4 + n3b3 + n2b2 + n1b1 + n0b0 + n-1b-1 ...
(3.3)
donde el punto separa los exponentes negativos de los positivos.
Nótese que el valor que tome b determina la longitud de la representación; así, por
un lado, resulta más cómodo que los símbolos (cifras) del alfabeto sean los menos
posibles, pero, por otra parte, cuanto menor es la base, mayor es el número de
cifras que se necesitan para representar una cantidad dada. Como ejemplo veamos
cual es el número decimal correspondiente de 175372, en base 8, (cuyo alfabeto es
{0, 1, 2, 3, 4, 5, 6, 7} y recibe el nombre de sistema octal).
ARITMÉTICA Y REPRESENTACIÓN DE INFORMACIÓN EN EL COMPUTADOR
139
175372)8 = 1×85 + 7×84 + 5×83 + 3×82 + 7×81 + 2×80 =
= 6×104 + 4×103 + 2×102 + 5×101 + 0×100 = 64250)10
60303" FGHKPKEKłP"FGN"UKUVGOC"DKPCTKQ
En el sistema de numeración binario b es 2, y se necesita tan sólo un
alfabeto de dos elementos para representar cualquier número: {0,1}. Los elementos
de este alfabeto se denominan cifras binarias o bits. En la Tabla 4.1 se muestran los
números enteros binarios que se pueden formar con 3 bits, que corresponden a los
decimales de 0 a 7.
binario
decimal
Tabla 4.1.- Números binarios del 0 al 7
000
001
010
011
100
101
0
1
2
3
4
5
110
6
111
7
60304" VTCPUHQTOCEKQPGU"GPVTG"DCUGU"DKPCTKC"["FGEKOCN
Para transformar un número binario a decimal:
Basta tener en cuenta las expresiones (3.2) y (3.3), en las que b = 2.
Ejemplo 1:
Transformar a decimal los siguientes números binarios:
110100; 0.10100; 10100.001
110100)2 = (1×25) + (1×24) + (1×22) = 25 + 24 + 22 = 32 + 16 +4 = 52)10
0.10100)2 = 2-1 + 2-3 = (1/2) + (1/8) = 0.625)10
10100.001)2 = 24 + 22 + 2-3 = 16+4+(1/8) = 20125)10
Observando el Ejemplo 1 se deduce que se puede transformar de binario a decimal
sencillamente sumando los pesos de las posiciones en las que hay un 1, como se
pone de manifiesto en el Ejemplo 2.
Ejemplo 2:
Transformar a decimal los números: 1001.001 )2 y 1001101 )2
140
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
1001.001 )2
pesos →
1
8
0
4
0
2
1
1
0
1/2
0
1/4
1001101 )2
pesos →
1
64
0
32
0
16
1
8
1
4
0
2
1 = 8 + 1 + 1/8 = 9125 )10
1/8
1
1
= 64 + 8 + 4 + 1 = 77 ) 10
Para transformar un número decimal a binario:
a)
La parte entera del nuevo número (binario) se obtiene dividiendo la parte
entera del número decimal por la base, 2, (sin obtener decimales en el cociente) de
partida, y de los cocientes que sucesivamente se vayan obteniendo. Los residuos de
estas divisiones y el último cociente (que serán siempre menores que la base, esto
es, 1 o 0), en orden inverso al que han sido obtenidos, son las cifras binarias.
Ejemplo 3:
Pasar a binario el decimal 26
26
0
26 )10 = 11010 )2
2
13
2
1
6
2
0
3
2
1
1
b)
La parte fraccionaria del número binario se obtiene multiplicando por 2
sucesivamente la parte fraccionaria del número decimal de partida y las partes
fraccionarias que se van obteniendo en los productos sucesivos. El número binario
se forma con las partes enteras (que serán ceros o unos) de los productos obtenidos,
como se hace en el siguiente ejemplo.
Ejemplo 4:
Para pasar a binario el decimal 26.1875 separamos la parte fraccionaria: 0.1875 y
la parte entera: 26 (ya transformada en el Ejemplo 3).
0.1875
×2
0.3750
0.3750
×2
0.7500
0.7500
×2
1.5000
0.5000
×2
1.0000
Por tanto, habiéndonos detenido cuando la parte decimal es nula, el número
decimal 26.1875 en binario es:
26.1875)10 = 11010.0011)2
ARITMÉTICA Y REPRESENTACIÓN DE INFORMACIÓN EN EL COMPUTADOR
141
NOTA: un número real no entero presentará siempre cifras después del punto
decimal, pudiendo ser necesario un número finito o infinito de éstas, dependiendo
de la base en que se represente; por ejemplo el número 1.6)10 representado en
binario sería 1.100110011001...)2, requiriendo infinitas cifras para ser exacto, como
por otra parte ocurre con muchos números representados en decimal.
60305" EłFKIQU"KPVGTOGFKQU
Como acabamos de comprobar, el código binario produce números con muchas
cifras, y para evitarlo utilizamos códigos intermedios que son bases mayores, que
no se alejen de la binaria. Estos se fundamentan en la facilidad de transformar un
número en base 2, a otra base que sea una potencia de 2 (22=4; 23=8; 24=16, etc.), y
viceversa. Usualmente se utilizan como códigos intermedios los sistemas de
numeración en base 8 (u octal) y en base 16 (o hexadecimal).
4.1.3.1" BASE OCTAL
Un número octal puede pasarse a binario aplicando los algoritmos ya vistos en
4.1.2. No obstante, al ser b=8=23, el proceso es más simple puesto que, como puede
verse
n525 + n424 + n323 + n222 + n121 + n020 + n-12-1 + n-22-2 + n-32-3 =
(n522 + n421 + n320)× 23 + (n222 + n121 + n020)× 20 + (n-122 + n-221 + n-320)× 2-3 =
(m1)× 81 + (m0)× 80 + (m-1)× 8-1
Cada 3 símbolos binarios (3 bits) se agrupan para formar una cifra de la
representación en octal, por tanto en general puede hacerse la conversión
fácilmente, de la forma siguiente:
Para transformar un número binario a octal se forman grupos de tres cifras binarias
a partir del punto decimal hacia la izquierda y hacia la derecha (añadiendo ceros no
significativos cuando sea necesario para completar grupos de 3). Posteriormente se
efectúa directamente la conversión a octal de cada grupo individual de 3 cifras, y
basta con memorizar la Tabla 4.1 para poder realizar rápidamente la conversión.
Así por ejemplo
10001101100.1101)2 =
010 001 101 100 . 110 100
2
1
5
4
6
4 = 2154.64)8
.
De octal a binario se pasa sin más que convertir individualmente a binario (tres
bits) cada cifra octal, manteniendo el orden del número original. Por ejemplo:
142
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
537.24 )8 =
5
101
3
011
7 . 2
4
111 . 010 100
= 101011111.0101 )2
Para transformar un número de octal a decimal se aplica la expresión (3.3) con
b=8.
Para transformar un número de decimal a octal se procede de forma análoga a
como se hizo para pasar de decimal a binario dividiendo o multiplicando por 8 en
lugar de por 2.
Así se puede comprobar que 1367.25)8 = 759.328125)10 ó que 760.33)10
=1370.2507...)8
4.1.3.2" BASE HEXADECIMAL
Para representar un número en base hexadecimal (esto es, b=16) es necesario
disponer de un alfabeto de 16 símbolos:
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F}
Tabla 4.2.- Números binarios del 0 al 7
hexadec. 0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
decimal
0
1
2
3
4
5
6
7
8
9 10 11 12 13 14 15
binario 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
Al ser b=16=24, de modo similar al caso octal, cada símbolo hexadecimal se
corresponde con 4 símbolos binarios (4 bits) y las conversiones a binario se
realizan agrupando o expandiendo en grupos de 4 bits. Se pueden comprobar las
transformaciones siguientes:
10111011111.1011011 )2 =
1A7.C4 )H =
0101 1101 1111 . 1011 0110
5
D
F . B
6
1
A
7 . C
4
0001 1010 0111 . 1100 0100
= 5DF.B6)H
= 110100111.110001)2
De la misma forma que manualmente es muy fácil convertir números de binario a
octal, y viceversa, y de binario a hexadecimal, y viceversa, también resulta sencillo
efectuar esta operación electrónicamente o por programa, por lo que a veces la
computadora utiliza este tipo de notaciones intermedias como código interno o de
entrada/salida, y también para visualizar el contenido de la memoria o de los
registros.
ARITMÉTICA Y REPRESENTACIÓN DE INFORMACIÓN EN EL COMPUTADOR
143
Para transformar un número de hexadecimal a decimal se aplica la expresión (2.3)
con b=16. Para pasar un número de decimal a hexadecimal se hace de forma
análoga a los casos binario y octal: la parte entera se divide por 16, así como los
cocientes enteros sucesivos, y la parte fraccionaria se multiplica por 16, así como
las partes fraccionarias de los productos sucesivos.
Así se puede comprobar que 12A5.7C)H = 4773.484375)10 ó que 16237.25)10 =
3F6D.4)H
6040" QRGTCEKQPGU"CTKVOÖVKECU"["NłIKECU
El procesamiento de la información incluye realizar una serie de
operaciones con los datos; estas operaciones y las particularidades de las mismas
en su realización por el computador son el objeto de los próximos apartados.
60403" QRGTCEKQPGU"CTKVOÖVKECU"EQP"PðOGTQU"DKPCTKQU
Las operaciones aritméticas básicas (suma, resta, multiplicación y división)
en sistema binario se realizan en forma análoga a la decimal aunque, por la
sencillez de su sistema de representación, las tablas son realmente simples:
Tabla 4.3.- Operaciones básicas en binario
Suma aritmética
Resta aritmética
0+0=0
0+1=1
1+0=1
1 + 1 = 0 y llevo 1(*)
Producto aritmético
0-0=0
0 - 1 = 1 y debo 1 (*)
1-0=1
1-1=0
0.0=0
0.1=0
1.0=0
1.1=1
(*) Llamado normalmente acarreo. En binario 1+1=10 (es 0 y me llevo 1),
igual que en decimal 6+6=12 (es 2 y me llevo 1)
Ejemplo 5:
Efectuar las siguientes operaciones aritméticas binarias:
1110101
+1110110
11101011
1101010
-1010111
0010011
1101010
×11
1101010
1101010_
100111110
1010011
×10
0000000
1010011_
10100110
110.01
10
010
10
00010
10
00
10
11.001
144
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
A partir del ejemplo anterior, se observa que multiplicar por 10)2 (es decir, por 2 en
decimal) equivale a añadir un cero a la derecha, o desplazar el punto decimal a la
derecha, siendo esto similar a multiplicar por 10)10 un número decimal. De la
misma forma dividir por 10)2 = 2)10 equivale a eliminar un cero a la derecha, o
desplazar el punto decimal a la izquierda.
Por ejemplo:
1010011)2 × 2 = 10100110)2
10101.01)2 × 2 = 101010.1)2
1.101101)2 × 25 = 110110.1)2
1010100)2 / 2 = 101010)2
110.01)2 / 2 = 11.001)2
10101.101)2 / 26 = 0.010101101)2
60404" XCNQTGU"DQQNGCPQU"["QRGTCEKQPGU"NłIKECU
Un dígito binario, además de representar una cifra en base dos, también
puede interpretarse como un valor booleano o dato lógico (en honor a George
Boole, citado en el capítulo 1), entendiendo como tal una cantidad que solamente
puede tener dos estados (Verdadero/Falso, SI/NO, 1/0, etc.) y por tanto con
capacidad para modelizar el comportamiento de un conmutador. Así, además de las
operaciones aritméticas con valores binarios, se pueden llevar a cabo operaciones
booleanas o lógicas en las que estos valores se consideran señales generadas por
conmutadores. Las operaciones booleanas más importantes son:
OR lógico (también denominado unión, suma lógica (+) o función O),
AND lógico (también intersección, producto lógico ( . ) o función Y)
la complementación ( - ) (o inversión, negación, o función NOT o NO).
Nótese que las dos primeras son operaciones de dos operandos o binarios mientras
que la complementación es unaria. Estas operaciones se rigen según la Tabla 4.4.
Tabla 4.4.- Operaciones lógicas
OR
0+0=0
0+1=1
1+0=1
1+1=1
AND
0.0=0
0.1=0
1.0=0
1.1=1
NOT
0=1
1=0
Como puede observarse, el AND y OR lógicos se corresponden parcialmente con
el producto y suma binarios, y lo más significativo, es la posibilidad de
ARITMÉTICA Y REPRESENTACIÓN DE INFORMACIÓN EN EL COMPUTADOR
145
implementar estas operaciones lógicas, y por tanto las aritméticas binarias, en
forma de circuitos.
60405" RWGTVCU"NłIKECU
Necesitamos examinar la realización en hardware de algunas de las
operaciones máquina básicas. Para poder hacer esto, vamos a diseñar y “construir”
algunos de esos circuitos. A lo largo de este recorrido se irá poniendo de manifiesto
la importancia de la lógica, en el proceso de diseño de componentes hardware.
Tenemos tendencia a considerar a los números y a la aritmética como las entidades
básicas de la informática. Después de todo, los números y las operaciones
aritméticas es lo primero que se estudia en los cursos elementales. Sin embargo,
tanto la suma como el resto de las operaciones de la máquina se tienen en términos
de la lógica. Las computadoras trabajan con la lógica. Sabemos que el sistema
binario se utiliza para representar números (o, de hecho, también otro tipo de
información) en la computadora. Sin embargo, utilizar la codificación binaria es
equivalente a definir los números en términos de las entidades lógicas básicas
verdadero y falso. Por ejemplo 5)10 es 101)2. Pero esto es lo mismo que decir
verdadero falso verdadero si asimilamos 1=verdadero y 0=falso. Parece, pues,
apropiado comenzar nuestro proyecto de construcción con las operaciones lógicas
and, not y or.
Para ello, necesitamos entender la operación y conocer qué circuitos podemos
construir. Las operaciones and y or son binarias: tiene dos entradas u operandos, y
de ellos se obtiene una salida. Para poder determinar qué componentes pueden ser
de utilidad en la construcción de estos circuitos and y or, conviene recordar que
representamos la información como una secuencia de dos estados (verdadero/falso,
0/1). Por tanto, el elemento básico tiene que ser algún tipo de conmutador, es decir,
algún dispositivo que pueda representar los dos estados, un simple interruptor1
puede hacerlo. Trabajaremos ahora con electricidad para simular la lógica, por lo
que utilizaremos hilos en lugar de variables lógicas, cada hilo tiene voltaje o no lo
tiene (1/0).
En la Figura 4.1. pueden verse los circuitos buscados a los que denominaremos
puertas lógicas (en general, dispositivos físicos que realizan operaciones lógicas).
1
En la práctica un interruptor resulta demasiado lento, por lo que necesitamos algún tipo de conmutador que pueda
cambiar de estado a velocidad electrónica. El transistor es este dispositivo; se trata de un conmutador que
interrumpe o permite el paso de corriente eléctrica y utiliza la electricidad para realizar la conmutación. Este es el
elemento activo de la CPU (más recientemente el circuito integrado; sin embargo, un circuito integrado no es más
que una pequeña “tableta” de circuitería que incluye transitores y algunos otros componentes electrónicos básicos,
como condensadores y resistencias).
146
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Circuito OR
a: abierto (0)
b: cerrado (1)
salida: luce (1)
( 0 OR 1 = 1 )
Fig. 4.1.
Circuito AND
a: abierto (0)
b: cerrado (1)
salida: no luce (0)
( 0 AND 1 = 0 )
Circuitos eléctricos cuyo comportamiento puede
describirse mediante las funciones OR y AND.
Obsérvese que existen dos operandos de entrada y uno de salida. En el caso del
circuito and, solo si los dos conmutadores están cerrados, (las entradas son
verdadero) existirá voltaje a la salida, lo que se interpreta como verdadero (o 1).
Análogamente, se reproduce con este circuito, el resto de filas de la tabla de verdad
de la operación and.
Otra operación muy utilizada es el llamado or-exclusivo, simbolizada por xor, se
definido mediante la ecuación
a xor b = (a or b) and not (a and b)
Informalmente significa “a o b, pero no ambos”. Obsérvese que no es necesario
construir un circuito diferente para ella, ya que un circuito que realice esta función
puede conseguirse enlazando puertas elementales not, and y or, combinándolas
como se hace en el lado derecho de la ecuación que la define.
60406" CTKVOÖVKEC"EQP"RWGTVCU"NłIKECU
Las operaciones lógicas básicas, raramente se usan de forma aislada. Se puede
imaginar las combinaciones de estas operaciones como conexiones de una puerta
lógica a la entrada de otra de tal manera que al atravesar el circuito una corriente
eléctrica, se van abriendo o cerrando hasta obtener la operación deseada. Algunos
de los circuitos lógicos, incluso en los computadores más sencillos, son
extremadamente complejos y no es objeto de este curso entrar en este tema, propio
ARITMÉTICA Y REPRESENTACIÓN DE INFORMACIÓN EN EL COMPUTADOR
147
de arquitectura de computadores, sin embargo es importante retener la idea de que
los elementos lógicos pueden combinarse para realizar operaciones mas complejas
y que la tabla de verdad de una combinación de ellas puede determinarse a partir de
las tablas de las puertas elementales.
A modo de ejemplo, ahora que conocemos las puertas lógicas básicas, abordamos
el diseño de una unidad que sea capaz de sumar dos enteros en binario. Por
ejemplo, podríamos querer realizar la suma de la tabla 4.5, siguiendo el algoritmo
de suma tradicional, sumando primero los números de la columna de más a la
derecha. Para realizar este proceso, primero calculamos la suma de la primera
columna, sumando los bits 1+1. Después de hacer eso, resulta evidente que se nos
produce un arrastre. Por tanto, la segunda cosa que debemos hacer para conseguir
sumar enteros es calcular el arrastre.
Tabla 4.5.- Suma en binario
001001
010101
011110
Esta primera suma nos confirma que la suma binaria debe considerar una doble
salida: el resultado de aplicar la tabla de sumar y los posibles acarreos (“llevar” de
una posición a otra). Así, las reglas para la suma de dos dígitos binarios se dan en
la Tabla 4.6:
Tabla 4.6.- Resultados de la suma en binario
Sumandos
0 0
0 1
1 0
1 1
Suma
0
1
1
0
Acarreo
0
0
0
1
Puede notarse que la columna Suma puede obtenerse mediante una puerta XOR
mientras que la del acarreo coincide con una puerta AND. En la Figura 4.2 se
muestra un circuito lógico con estas puertas. Un circuito de este tipo se denomina
semisumador.
148
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Fig. 4.2. Esquema de un semisumador La puerta de arriba representa
la puerta lógica XOR y la de abajo la puerta lógica AND
Sin embargo, todavía no hemos terminado. Volviendo a la suma anterior,
recordemos que debemos continuar con el proceso de suma, procediendo de
derecha a izquierda a través de una serie de bits. El problema es que algunas de
esas sumas producen un arrastre que debe incluirse en la siguiente suma de la
izquierda. En la tabla 4.5., esto ocurre en la primera suma, es decir, la suma de los
dígitos de más a la derecha, puesto que 1+1=0 mas un arrastre de 1. Este bit
arrastrado debe considerarse en la suma siguiente. ¡Parece que sólo hemos
realizado la mitad del trabajo!. Si queremos extender nuestro semisumador a un
sumador, el problema que nos encontramos es que necesitamos poder sumar a la
vez tres bits, en lugar de dos. Necesitamos una circuiteria con tres entradas (el
arrastre y los dos operandos) y dos salidas (el arrastre de salida y el bit suma). Esto
puede hacerse con dos semisumadores y una puerta or, como se muestra en la
Figura 4.3.
Fig. 4.3. Esquema de un sumador completo, construido a partir de dos
semisumadores. La puerta que proporciona el resultado del acarreo es una puerta
lógica OR
Es fácil ver cómo el sumador produce el bit suma. El primer semisumador produce
el dígito resultante de la suma de los operandos y el segundo semisumador suma a
este resultado el bit de arrastre proveniente del sumador anterior. Que el sumador
produce el bit de arrastre correcto es un poco más difícil de ver. Básicamente, el
ARITMÉTICA Y REPRESENTACIÓN DE INFORMACIÓN EN EL COMPUTADOR
149
sumador debe producir un bit de arrastre 1, bien si la suma de los operando es
mayor que 1, bien cuando el resultado que se produce al sumar el arrastre anterior
es mayor que 1. En términos del diagrama de la Figura 4.3, significa que siempre
que cualquier semisumador produzca un arrastre de 1, se debe producir una salida 1
del bit de arrastre. Este es exactamente el efecto que produce la puerta or. Esta
explicación no constituye una demostración de que el sumador trabaje
correctamente, ya que para demostrar que el circuito es correcto, necesitaríamos
aplicarle cada uno de las ocho posibles combinaciones para los valores de los
operandos y del bit de arrastre de entrada.
Nuestro objetivo de diseñar una unidad operativa para sumar enteros, no está aún
alcanzado, puesto que nuestro sumador todavía solo suma correctamente una
posición de un número binario. Sin embargo, puesto que sabemos que el proceso
de suma es idéntico para todas las posiciones, es fácil construir la unidad operativa,
pues basta encadenar juntos un número apropiado de sumadores. Por ejemplo, si
nuestros números binarios tuvieran 4 bits, podemos construir un sumador de
números de 4 bits utilizando cuatro sumadores en cascada. Este sumador puede
verse en la Figura 4.4. En este diagrama, las tres entradas para cada bit se
encuentran en la parte de arriba de la caja negra correspondiente, y las dos salidas
se encuentran en la parte de abajo. Obsérvese que los sumadores se han conectado
de manera que simulan la forma en que realizamos la suma binaria; el bit de
arrastre de cada sumador se conecta al bit de entrada de arrastre del sumador de su
izquierda. Este diseño se conoce como sumador helicoidal, debido a la forma en
que se produce la propagación hacia la izquierda del bit de arrastre. De forma
análoga, es posible construir sumadores para enteros con mayor número de bits.
Fig. 4.4.
Esquema de un sumador en paralelo para cuatro bits.
Nótese que existe un retraso asociado al paso de los datos a través de cada puerta
lógica de un circuito. Aunque los circuitos de la figura operan en paralelo, puede
ser necesario pasar un acarreo a través de todos los sumadores del circuito. Lo que
supone un retraso considerable y la suma deja de ser “en paralelo”.
Afortunadamente existen procedimientos para resolver estos problemas.
150
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
6050" TGRTGUGPVCEKłP"FG"KPHQTOCEKłP"GP"GN
EQORWVCFQT
Empecemos recordando que toda información que maneja y almacena el
computador, (programas y datos) se introduce por los mismos dispositivos,
utilizando un mismo alfabeto o conjunto de caracteres. Para evitar este tipo de
problemas toda comunicación con el computador se realiza de acuerdo con los
caracteres que admiten sus dispositivos de Entrada/Salida, y solo a partir de ellos,
pueden los usuarios expresar cualquier dato o instrucción. Es decir, toda
instrucción o dato se representará por un conjunto de caracteres tomados del
alfabeto definido en el sistema a utilizar, lo que origina que algunos caracteres a
veces no puedan reconocerse ( la letra ñ por ejemplo). Los caracteres reconocidos
por los dispositivos de entrada/salida suelen agruparse en cuatro categorías,
dejando aparte los caracteres gráficos:
Caracteres alfabéticos: Son las letras mayúsculas y minúsculas del abecedario:
A, B, C,...,X,Y,Z,
a,b,c,...,x,y,z
Caracteres numéricos: Están constituidos por las diez cifras decimales:
0,1,2,3,4,5,6,7,8,9
Caracteres de control: Representan órdenes de control, como el carácter indicador
de fin de línea o el carácter indicador de sincronización de una transmisión o de
que se emita un pitido en un terminal, etc. Muchos de los caracteres de control son
generados e insertados por el propio computador y otros lo son por el usuario
como por ejemplo, el carácter producido por la tecla de borrar. Estos caracteres
suelen carecer de representación visual o impresa, pero desencadenan diferentes
procesos cuando aparecen.
Caracteres especiales: Son los símbolos no incluidos en los grupos anteriores,
entre otros, los siguientes:
) ( , ; . : -_ ! * + = Ç ¿ ? ^ SP (espacio blanco, que separa dos palabras).
A los caracteres que no son de control, se les denomina caracteres-texto y al
conjunto de los dos primeros tipos se le denomina conjunto de caracteres
alfanuméricos.
60503" NC"EQFKHKECEKłP"GP"KPHQTOıVKEC
ARITMÉTICA Y REPRESENTACIÓN DE INFORMACIÓN EN EL COMPUTADOR
151
Vamos a presentar ahora la forma como se codifican tanto los datos como
las instrucciones, por lo que distinguiremos entre unos y otras aunque todas ellas
estén formados por caracteres. A la hora de codificar información (sean datos o
instrucciones), parece razonable aprovechar al máximo la memoria principal del
computador; por ello, el número de bits de una palabra es normalmente un múltiplo
entero del numero de bits con que se representa un carácter; desde el punto de vista
de la CPU, los intercambios de información con la memoria se hacen por palabras
y por caracteres y de esta forma para escribir o leer un dato o instrucción
almacenado en la memoria principal, basta con proporcionar la dirección de la
palabra correspondiente, para que se efectúe esta operación de escritura o lectura en
paralelo (de forma simultánea todos los bits que la constituyen) gracias al bus.
4.3.1.1" CÓDIGOS DE ENTRADA/SALIDA
Los códigos de entrada/salida (E/S) o códigos externos son códigos que
asocian a cada carácter (alfanumérico o especial) una determinada combinación de
bits. En otras palabras, un código de E/S es una correspondencia entre el conjunto
de todos los caracteres:
0,1,2,...9,A,B,...Y,Z.a,b,...y,z,*,”,%,...
y un conjunto de n-uplas binarias pertenecientes a:
{0,1}n,
El número de elementos, m, del primer conjunto depende del número de caracteres
que el dispositivo o sistema informativo utilice y n dependerá a su vez de m, ya que
con n bits se puede codificar m=2n símbolos o caracteres distintos, con lo que n
debe ser el menor número entero que cumpla:
n≥ log2 (m) = 3.32 log (m)
Tabla 4.7.- Equivalencia entre valor decimal y carácter según el código ASCII
Valor Carácter
Significado
dec. de control
0
NUL
Nulo
1
SOH
Comz. de cabecera
2
STX
Comienzo de texto
3
ETX
Fin de Texto
4
EOT
Fin de Transm
5
ENQ
Pregunta
6
ACK
Confirmación posit.
7
BEL
Pitido
8
BS
Espacio Atrás
9
HT
Tabulador Horiz.
10
LF
Salto de Línea
Valor Carácdecim.
ter
32
33
!
34
“
35
#
36
$
37
%
38
&
39
‘
40
(
41
)
42
*
Valor Carácdecim.
ter
64
@
65
A
66
B
67
C
68
D
69
E
70
F
71
G
72
H
73
I
74
J
Valor
decim.
96
97
98
99
100
101
102
103
104
105
106
Carácter
`
a
b
c
d
e
f
g
h
i
j
152
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
VT
FF
CR
SO
SI
DLE
DC1
DC2
DC3
DC4
NAK
SYN
ETB
CAN
EM
SUB
ESC
FS
GS
RS
US
Tabulador Vertical
Salto de Página
Retorno de Carro
Shift Out
Shift In
Escape unión datos
Contrl dispositivo 1
Contrl dispositivo 2
Contrl dispositivo 3
Contrl dispositivo 4
Confirm. negativa
Sincronización
Fin Bloque de Texto
Cancelar
Fin del Medio
Sustitución
Escape
Separad. de ficheros
Separad. de grupos
Separad de registros
Sep. de unidades
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
+
,
.
/
0
1
2
3
4
5
6
7
8
9
:
;
<
=
>
?
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
[
\
]
^
_
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
{
|
}
~
Delete
Nótese que con n=7, se puede representar hasta 128 caracteres, con lo que se puede
codificar además de los caracteres habituales, determinados caracteres de control y
gráficos. El más usado de estos códigos es el ASCII (American Standard Code for
Information Interchange) representado en la Tabla 4.7, que incluye además un
octavo bit para detectar posibles errores de transmisión o grabación.
4.3.1.2" DETECCIÓN DE ERRORES
La detección y corrección automáticas de los errores que se pueden
producir, especialmente durante la transmisión de datos, es una cuestión que
preocupa y como acabamos de indicar interviene incluso en la propia estructura del
código. Una técnica muy valiosa, que sirve de gran ayuda para conseguir este
objetivo, es el concepto de código redundante 2. Un código redundante es aquel
que contiene una cierta cantidad de información adicional embebida en la
expresión codificada de los datos, que permite determinar, a partir del análisis de
esta expresión, si los datos han sido codificados (o transmitidos) correctamente.
Los códigos redundantes más sencillos y comunes requieren la inclusión de un bit
de paridad en el código de cada dato. Así el bit de paridad se pone a 0 ó a 1, según
que el número de unos en el dato sea par, cuando se emplea paridad par, o impar,
cuando se emplea paridad impar. Por ejemplo, empleando paridad par y el bit más
2
Un ejemplo de código redundante es el N.I.F., en el que la letra depende de los dígitos del D.N.I. (en realidad es el
resto de dividir el número del D.N.I. por 23, asignando a cada número del 0 al 22 una letra distinta). Con esta letra
adicional es fácil detectar algunos errores de escritura (obviamente no todos).
ARITMÉTICA Y REPRESENTACIÓN DE INFORMACIÓN EN EL COMPUTADOR
153
significativo como bit de paridad, el número entero 0110101, al tener cuatro unos
pone el bit más a la izquierda (llamado bit más significativo) a 0 para codificarse
como el 00110101; mientras que el número 1001100, al tener tres unos, pone un 1
como bit más significativo para formar el 11001100 y tener un número par de unos.
De esta manera es fácil comprobar si la paridad de un dato es correcta
(comprobación de paridad). Estas comprobaciones se realizan sobre todo cuando se
han transmitido los datos para entrada o salida, hacia o desde un dispositivo de
almacenamiento masivo o a través de una red de comunicaciones, donde los errores
son más probables. Así por ejemplo, si recibimos el código 01001100 en un código
con paridad par, podemos afirmar que ha habido un error al tener un número impar
de unos.
4.3.1.3" ENCRIPTADO DE DATOS
Para muchas aplicaciones es esencial que los datos almacenados en disco o
transmitidos mediante redes de comunicaciones tengan un cierto nivel de
confidencialidad. Una técnica que proporciona un cierto grado de seguridad es el
encriptado de los datos, que consiste en modificar los bits que los representan de
modo que no sigan ningún código estándar y por consiguiente requieran una
decodificación secreta antes de poder ser interpretados. En todos los casos en que
los datos se encriptan de esta forma, la codificación y decodificación se realiza de
manera automática por el hardware o el software del sistema.
Las técnicas de encriptado son muy variadas. Algunas utilizan algoritmos que
codifican y decodifican los datos, empleando números aleatorios. Otras están
basadas en los restos que se obtienen cuando se dividen los valores de los datos
entre grandes números primos. La clave para códigos de esta naturaleza está
constituida por un gran número entero (con más de 100 dígitos decimales) que es el
producto de dos números primos, uno de los cuales se emplea para la división. Si el
número clave es desconocido para el intruso el proceso de factorización es muy
difícil, y toma tanto tiempo que, incluso utilizando los computadores más potentes,
cuando la información se decodifica ya es inútil, por obsoleta.
60504" TGRTGUGPVCEKłP"KPVGTPC"FG"FCVQU
La procedencia de los datos a ser procesados, puede ser muy distinta y
tener su origen en unidades muy diferentes del computador. Así, puede ser un
carácter leído de un teclado, estar almacenado en un disco o ser un número que se
encuentra en memoria principal. En cualquier situación, el dato tiene la misma
154
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
representación que dependerá de su naturaleza, que como sabemos puede ser:
numérica (enteros y reales), lógica y alfanumérica.
Los códigos de E/S, presentan problemas cuando los aplicamos a los datos
numéricos, con el objetivo de operar aritméticamente con ellos, ya que
desafortunadamente su representación binaria, obtenida por un código de E/S, no
es adecuada para estas operaciones. Por ejemplo basta con comparar la notación de
253 en código ASCII, con bit de paridad. 253= 10110010 00110101 00110011
y su representación binaria: 253=11111101)2 para darnos cuenta que el código de
E/S, utiliza un número excesivo de bits respecto a la representación del número en
sistema binario. La justificación de ello es que un código como el ASCII no está
pensando para representar solamente datos numéricos.
De acuerdo con lo anterior, existe la necesidad de llevar a cabo una conversión de
la representación simbólica de E/S de los datos a otra, que denominamos
representación interna, que depende tanto de las características del computador,
como del uso que el programador desee hacer con los datos. Con ello abrimos la
posibilidad de que los datos puedan codificarse de forma distinta, según estemos en
un proceso de E/S o consideremos los datos ya almacenados en una de las
memorias del computador. Ello supone la aparición de un nuevo problema: un
mismo conjunto de bits puedan interpretarse de forma distinta según sea la
situación, así por ejemplo, el valor binario 1010011 puede significar: el valor de 83
si lo consideramos como un entero positivo, el carácter “S” en ASCII, y ello sin
contar que podría ser una instrucción en vez de un dato, en cuyo caso, su
interpretación dependería del lenguaje máquina del procesador.
Afortunadamente, esta aparente complejidad se simplifica, gracias a la introducción
del concepto de tipo de dato que desarrollaremos al final de este capítulo, de forma
que para todo dato manejado, obligatoriamente se ha tenido que definir
previamente la naturaleza de su tipo. Esta definición implicará que su
representación interna será una u otra, al tiempo que determina, como ya veremos,
las operaciones que podemos realizar a partir de este dato concreto.
4.3.2.1" REPRESENTACIÓN DE DATOS ALFANUMÉRICOS
Los datos de tipo alfanumérico se representan internamente con el mismo
valor binario que le corresponde al dato, según el código de E/S que se utilice. Por
tanto en el caso alfanumérico, no hay diferencia entre su representación interna y la
derivada de su código de E/S.
ARITMÉTICA Y REPRESENTACIÓN DE INFORMACIÓN EN EL COMPUTADOR
155
4.3.2.2" REPRESENTACIÓN INTERNA DE DATOS NUMÉRICOS
El ordenador distingue entre números de tipo entero (sin decimales) y de
tipo real (con decimales) y utiliza representaciones internas distintas para ambos
tipos. Sin embargo, cualquiera que sea la forma empleada para representar los
números en un computador, hay siempre unos límites, superior e inferior, al valor
que pueda ser representado. Estos límites dependen tanto de la forma como se
representen como del número de bits asignados para cada número. Se emplea el
término overflow (desbordamiento) cuando una operación produce un número tan
grande que se sale de estos límites (el término underflow se usa en relación al
límite inferior). Por ejemplo, si un computador empleara ocho bits para almacenar
enteros positivos, el número más grande que podría almacenar sería 11111111
(binario) =255 (decimal). Cualquier intento de almacenar un número de más de
ocho bits produciría necesariamente un desbordamiento.
Al objeto de reducir los errores de desbordamiento, y de reducir el espacio que se
puede malgastar, (reservando un número excesivo de bits si éstos no son
necesarios), existe una cierta flexibilidad en la representación. Así por ejemplo, la
mayor parte de los computadores disponen de la posibilidad de representar los
números en simple y doble precisión, de forma que los números en doble precisión
ocupan más bits por lo que son más exactos. Afortunadamente los lenguajes de
programación permiten a los programadores tener la posibilidad de elegir el tipo de
representación más adecuada para cada número en función de como lo vayan a
manejar a lo largo del programa.
4.3.2.2.1" Representación de datos de tipo entero
Esta representación se basa en el sistema de numeración binario, basado en
la posición de cada dígito, en una palabra con un número de bits determinado.
Estos datos numéricos, se suelen denominar de punto fijo, en contraposición al
punto flotante, que utilizaremos para los datos numéricos reales. Existen dos
alternativas de representación, según tengan o no signo, reservando en este último
caso el bit más representativo para indicar una cantidad negativa. Los límites de
valores enteros que podemos representar, sin caer en un overflow, dependen
naturalmente de la longitudes de palabra que utilicemos. Es posible definir distintas
clases de datos de tipo entero de forma que cada una de ellas tenga un rango
numérico distinto. Así por ejemplo, con 16 bits se pueden representar los valores
de 0 a 65536, y con 32 bits se va desde 0 a 4294967296.
Nótese que al operar con aritmética de números enteros, se puede producir un
overflow cuando el resultado del cálculo excede el rango de números que pueden
representarse. No hay forma de prevenir los overflows, todo lo que los sistemas
156
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
operativos pueden hacer es detectarlos cuando ocurren y avisar al usuario de esta
circunstancia.
4.3.2.2.2" Representación en Complementos
Para representar un número entero negativo habitualmente recurrimos a añadir
el signo. Sin embargo hay otras alternativas para facilitar su utilización.
Normalmente se utiliza una representación diferente en binario, según que el
número sea positivo o negativo, de esta forma, como se verá más adelante, las
sumas y restas quedan reducidas a sumas, independientemente de los signos de los
operandos. Este sistema de representación es de sumo interés, ya que al utilizarlo se
reduce la complejidad de los circuitos de la ALU, pues no son necesarios circuitos
específicos para restar.
Llamaremos complemento a la base de un número, N, al número que resulta de
restar cada una de las cifras del número N a la base menos uno del sistema que se
esté utilizando y posteriormente sumar uno a la diferencia obtenida. A partir de él,
se puede dar la siguiente regla: Para restar dos números se puede sumar al
minuendo el complemento a la base del sustraendo despreciando, en su caso, el
acarreo del resultado.
Veamos, ejemplos para el caso decimal y binario:
a) En decimal (complemento a 10)
• Complemento a 10 del número 63 : 37.
• Complemento a 10 del número 16 : 84. En efecto:
99
- 63
36 +1 = 37
99
-16
83 +1 = 84
• Supongamos que queremos efectuar las operaciones: 77-63 y 97-16. Las
podemos realizar de dos formas, directamente: 77-63=14; 97-16=81 o
utilizando el complemento del sustraendo y despreciando los acarreos finales:
77
- 63
77
+ 37
(1)14
97
- 16
97
+ 84
(1)81
b) En binario (llamada representación en complemento a 2):
• Complemento a 2 del número 1010 : 0110.
•
ARITMÉTICA Y REPRESENTACIÓN DE INFORMACIÓN EN EL COMPUTADOR
157
• Complemento a 2 del número 0011 : 1101. En efecto:
1111
- 1010
0101 +1= 0110
1111
- 0011
1100 +1 = 1101
• Supongamos que queremos efectuar las operaciones: 1100-1010 y 0111-0011.
Las podemos realizar de dos formas, directamente o utilizando el complemento
del sustraendo y despreciando los acarreos finales:
1100
- 1010
1100
+ 0110
(1)0010
0111
- 0011
0111
+ 1101
(1)0100
Naturalmente los ceros a la izquierda del número no son necesarios y sólo se han
colocado por motivos de claridad en la exposición.
En el ejemplo anterior, observamos que para transformar un número binario, N, a
complemento a 2 basta con cambiar los ceros por unos y los unos por ceros de N y
sumar 1 al resultado. Esto es siempre cierto y por tanto, no es necesario hacer las
restas anteriores para calcular el complemento a 2, y se pueden restar dos números
sólo efectuando sumas.
La representación interna más común para los números enteros con signo es la
binaria de complemento a dos, donde si el bit más significativo es un 0 indica un
valor positivo y si es un 1 indica un entero negativo cuyo valor absoluto es el
complemento a 2 del número binario representado. Así por ejemplo, con 8 bits,
tendríamos que el número 00110011 en binario representa el valor +51, mientras
que el número 11001001 representa el entero negativo -55, ya que el bit más
significativo a 1 indica que es negativo y debemos hacer el complemento a 2 de
11001001 que es 00110111 (55 en decimal) De este modo, los valores que se
pueden representar van de -32768 a +32767 para el caso de 16 bits y de 2147483648 a +2147483647 usando 32 bits.
Quedaría la cuestión de como construir un circuito que calcule el complemento a
dos, sabemos que el complemento a dos es igual al complemento a uno al que se le
suma 1, basta con construir un circuito que calcule el complemento a uno. Para ello
basta con poner una serie de puertas not en paralelo, con una señal complementaria
que sirve para “disparar” la función. Es decir, cuando aparece un 1 en la línea de
señal, el complemento de todas las líneas de entrada se envía al de las salidas. En
caso contrario, los bits de entrada se envían a la salida sin sufrir alteración.
158
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
4.3.2.2.3" Representación de datos de tipo real
Al escribir un número en forma decimal, la cantidad de cifras decimales
indica la precisión del mismo. Sabemos que muchos reales no pueden representarse
mediante un número finito de cifras decimales. La precisión de una fracción
decimal es una medida de cuánto se aproxima la representación al valor exacto del
número. Por ejemplo, en base diez, el número racional 1/3 no puede representarse
de forma exacta. Sin embargo, la representación con cuatro decimales 0.3333 es
más precisa que la que sólo emplea dos: 0.33.
En las CPU las fracciones tienen necesariamente que almacenarse mediante un
número finito de dígitos binarios. Como en el caso de las fracciones decimales, esto
limita su precisión e implica que los cálculos que empleen estos números,
raramente proporcionarán un resultado exacto. Para representar números reales se
recurre a las técnicas basadas en el uso de números en punto flotante3 que
permiten expresar un rango mayor de los números que emplean un número dado de
bits. Este método es similar al empleado para representar números en base diez en
notación científica, denominada método estándar, que todo usuario de una
calculadora de bolsillo conoce. Un número, en método estándar, consta de dos
partes: la primera es una cantidad del intervalo [1, 10[, con posibles decimales, y la
segunda, una potencia de diez. Por ejemplo:
5.75 x 104 = 57 500
6.7 x 10-5 = 0.000 067
Nótese que el orden de magnitud del número está determinado por la potencia de
diez, y el número de cifras significativas, o precisión de número, está determinado
por el número de cifras decimales en la primera parte.
Para la representación interna de números en punto flotante, se emplea el mismo
principio, aunque en base dos. Así como en decimal, la primera parte es un numero
comprendido entre 100 y 101 , en binario un número se expresa como el producto
de dos partes: La primera es una fracción entre 1 (20 ) y 2 (21 ), llamada mantisa, y
la segunda, una potencia de 2 llamada, exponente. Obsérvese, que al exigir que la
mantisa esté comprendida entre 1 y 2, ello supone que escribiremos siempre los
números de la forma:
1.xxxxx * 2exponente
3
En España, la parte decimal se separa por una coma. Sin embargo, en los países anglosajones, y por ello en la
terminología informática, la parte decimal se señala con un punto. Es por ello, y para evitar confusiones, que en
este libro empleamos el término punto flotante y la notación con punto en lugar de la coma.
ARITMÉTICA Y REPRESENTACIÓN DE INFORMACIÓN EN EL COMPUTADOR
159
donde el numero de dígitos a la izquierda del punto en la mantisa, dependerá de los
bits que se hayan asignado a la representación interna de la misma)
Ejemplo 6:
Expresar en forma de mantisa y exponente, los siguientes números binarios:
100100 = 1.001 * 25
111.101 = 1.11101 * 22
0.00111 = 1.11 * 2-3
Como consecuencia de este convenio notacional, siempre estará presente, en la
representación del numero binario, el 1 de la parte entera de la mantisa, por lo que
podemos prescindir de su representación interna, pues siempre se supone que
existe; con ello nos ahorramos un bit en la representación binaria del mismo. Ello
nos hace insistir en la diferencia que existe entre el concepto de mantisa y la
representación interna que de ella hace el computador. Afortunadamente las
unidades operativas de la ALU, están diseñadas teniendo en cuenta esta diferencia.
Afinando mucho se observará que el número cero no puede ser representado
internamente, ello se soluciona dando una codificación especial para el 0, que
depende de cada ordenador y de cada lenguaje en particular.
Los siguientes ejemplos emplean cuatro bits para cada una de las partes,
representadas, empleando el método de codificación conocido por signo-ymagnitud, donde un bit indica el signo y el resto de bits indican el valor absoluto,
tanto de la mantisa como del exponente:
Signo
0
0
0
1
MANTISA
1/2 1/4
0
0
1
0
1
1
1
1
1/8
0
1
0
1
EXPONENTE
Signo
4
0
0
0
1
1
0
0
1
valor
2
0
0
1
1
1
1
0
0
0
= 1 x 21 = 2
= (1 + 5/8) * 24 = 26
= (1 + 3/4) * 2-2 = 7/16
= -(1 + 7/8) * 26 = -120
La forma de representar los números en punto flotante varían notablemente entre
los distintos tipos de computadores. La mantisa se codifica en signo-y-magnitud o
en complemento a dos. Además, el exponente se codifica a veces en exponentes
sesgados. En este método, se resta un valor fijo al código, que representa al
exponente, para determinar su valor real. Por ejemplo, si se emplean ocho bits para
representar el exponente, los valores almacenados pueden variar entre 0 y 255. Sin
embargo si se resta un valor prefijado, 128 (el sesgo), el rango de exponentes es de
-128 a 127.
160
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
El número de bits que se asignan a cada parte de un número de punto flotante
también varía entre los distintos computadores. El principio general es emplear el
doble o el triple de bits para la mantisa que para el exponente. Veamos un ejemplo
de codificación, empleando once bits para la mantisa y cinco para el exponente,
signo-y-magnitud, para ambas partes del número.
Signo
0
1/2
1
Signo
0
1/4
0
8
1
1/8
1
MANTISA
1/16 1/32 1/64
1
0
0
EXPONENTE
4
2
1
0
1/128 1/256 1/512 1/1024
0
0
0
0
1
0
=(1 + 1/2 + 1/8 + 1/16) x 212= 11/16 x 4096 = 6912
El mismo número con un exponente sesgado (con desplazamiento 16) es:
Signo
0
16
1
1/2
1
1/4
0
8
1
1/8
1
1/16
1
EXPONENTE
4
2
1
0
MANTISA
1/32 1/64
0
0
1/128 1/256 1/512 1/1024
0
0
0
0
1
0
El exponente almacenado es 11100)2= 28, 12 cuando se le resta el sesgo 16.
En cualquier caso, una mayor cantidad de bits en el exponente permite representar
un rango mayor de valores, mientras que una cantidad mayor de bits, dedicados a la
mantisa permite representar el número con mayor precisión (con más cifras
significativas).
Es por ello que se habla de números reales de simple precisión y de doble
precisión, al utilizar el doble de bits para representarlos. El número de bits
destinados a la mantisa y al exponente en cada caso dependerá de cada
computador. Por ejemplo utilizando un total de 4 bytes en simple precisión se
representan números en el rango de ± 3.4 . 1038 con 7 cifras significativas, mientras
que en doble precisión con 8 bytes el rango va de ± 1.7 . 10308 con 15 cifras
significativas.
ARITMÉTICA Y REPRESENTACIÓN DE INFORMACIÓN EN EL COMPUTADOR
161
4.3.2.2.4" Aritmética en punto flotante
Operar con números de punto flotante tiene una complejidad mayor que la que
vimos para números enteros, por lo que conviene que repasemos la forma como se
realizan las operaciones básicas, de lo cual sacaremos conclusiones importantes:
Suma de dos números
Dados dos números, x, y, expresados en punto flotante (recordando que sus
mantisas, pertenecen a [1, 2[) se pueden escribir de la forma:
x = d1 * 2n
y = d2 * 2m
la aritmética que utilizamos manualmente cumple que
si m = n
x+y = d1 2n + d2 2n = (d1 + d2) 2n
Por tanto, si los números tienen igual exponente, su suma tiene como mantisa la
suma de las mantisas y como exponente el mismo. Téngase en cuenta que el
resultado de (d1 + d2) puede ser mayor que 2, en cuyo caso habrá que modificar
debidamente su representación, esto es, si la suma de las mantisas “no cabe” en el
lugar asignado, basta con despreciar los dígitos sobrantes menos significativos
(“truncar”) e incrementar en uno el exponente de acuerdo con la siguiente
propiedad:
d * 2n = (d/2) * 2n+1 = (d/22) * 2n+2
Esta misma propiedad, es la que nos permite conseguir que los dos números
puedan expresarse con el mismo exponente, en caso de que no les coincidiera en la
representación original. En el siguiente ejemplo, vamos a analizar esta operación.
Ejemplo 7:
Sumar los decimales 26.1875 y 12.8, expresándolos en punto flotante, en un
ordenador que reserva 1 bit de signo y 5 bits para su mantisa y 1 bit de signo y 3
bits para el exponente:
En primer lugar hay que pasarlos a binario (Ver Ejemplo 4) y representarlos de
acuerdo con las condiciones del ordenador que manejamos, efectuando los
truncamientos que pudieran ser necesarios:
26.1875 = 11010.0011)2
= 1.10100)2* 24
162
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
12.8 = 1100.110011001..)2 = 1.10011)2 * 23
26.1875
12.8
Signo
0
0
1/2
1
1
Mantisa
1/4 1/8
0
1
0
0
1/16
0
1
1/32
0
1
Signo
0
0
Exponente
4
2
1
1
0
0
0
1
1
Una vez representados internamente, como el segundo número tiene el exponente
menor, se desplaza la mantisa un lugar a la derecha (perdiendo el último 1). Esto
es:
1.10011)2 * 23 = 0.110011)2 * 24 = (truncando) 0.11001)2 * 24
Una vez igualados los exponentes, se suman las mantisas, obteniendo:
[1.10100)2* 24 ] + [0.11001)2 * 24 ] = [1.10100)2 + 0.11001)2 ]* 24 = 10.01101
)2 * 2 4
Puesto que la mantisa desborda al intervalo [1, 2[, truncamos los bits que no
pueden representarse en el espacio disponible de la mantisa, quedando:
10.01101 )2 * 24 = 1.001101 )2 * 25 = (truncando) 1.00110 )2 * 25
Al final de la operación tendremos:
Signo
0
1/2
0
Mantisa
1/4 1/8
0
1
1/16
1
1/32
0
Signo
0
4
1
Exponente
2
1
0
1
Nótese que el numero arriba representado, equivale al decimal 38, cuando el
resultado de la suma es: 26.1875 + 12.8 = 38.9875. La diferencia entre el resultado
hallado y el correcto se debe a los dígitos perdidos en el proceso. La conclusión es
importante: la suma de dos números en punto flotante origina inexactitudes.
Producto de dos números:
Dados dos números en punto flotante, esta operación consiste en multiplicar las
mantisas de los números y sumar los exponentes, transformando el resultado en el
caso de que la mantisa desborde el intervalo [1, 2[. El signo del producto viene
dado por la utilización de una puerta xor sobre los bit de signo ( 0+0=0 ; 1+0=1 ;
0+1=1 ; 1+1=0)
Al igual, que en el caso de la suma, vamos a analizar esta operación a través de un
ejemplo.
ARITMÉTICA Y REPRESENTACIÓN DE INFORMACIÓN EN EL COMPUTADOR
163
Ejemplo 8:
Multiplicar los decimales 26.1875 y 6.4 en el mismo ordenador, usado en el
ejemplo anterior.
= 1.10100)2* 24
26.1875 = 11010.0011)2
6.4 = 110..110011001..)2 = 1.10011)2 * 22
Obsérvese que al ser el segundo factor, la mitad del sumando, utilizado en el
ejemplo anterior (6.4 = 12.8), la diferencia en binario entre ambos, se reduce a la
posición del punto.
[1.10100)2* 24] * [1.10011)2 * 22] = [1.10100)2 * 1.10011)2]*24+2
= 10.1001011100)2 * 26 =
Puesto que la mantisa debe pertenecer al intervalo [1,2[, en este ejemplo es
necesario desplazar la mantisa una posición a la derecha, e incrementar el
exponente en una unidad, para representar adecuadamente el producto; el resultado
se trunca al numero de bits disponibles para la mantisa:
= 10.1001011100)2 * 26= 1.01001011100)2 * 27 = (truncando) 1.01001)2 * 27
Al final de la operación tendremos:
Signo
0
1/2
0
Mantisa
1/4 1/8
1
0
1/16
0
1/32
1
Signo
0
4
1
Exponente
2
1
1
1
El numero arriba representado equivale al decimal (1 + 1/4 + 1/32) * 128 = 164,
mientras que el resultado del producto es 26.1875 * 6.4 = 167.6, de donde se
concluye que el producto de dos números en punto flotante también origina
inexactitudes.
Comparando la aritmética en punto flotante con la aritmética en punto fijo
obtenemos dos conclusiones:
•
•
La aritmética en punto flotante produce errores de truncamiento
La aritmética en punto flotante emplea más cálculo que la aritmética
binaria para la misma operación matemática.
Por tanto, la utilización de números reales producirá muchos más errores de cálculo
que el uso de números enteros, a la vez que empleará mayor tiempo de cómputo,
164
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
por lo que siempre que se pueda, es aconsejable utilizar números enteros. La
utilización de coprocesadores matemáticos, reduce el tiempo de cómputo, aunque
no los errores de truncamiento, que solo pueden ser reducidos incrementando el
numero de bits destinados a la representación de la mantisa.
4.3.2.2.5" Limitaciones de la representación y la aritmética en el computador
Hemos visto que, siendo una herramienta muy potente y casi
imprescindible para el cálculo, el uso del computador para representar valores
numéricos y operar con ellos, presenta ciertas limitaciones que no deben olvidarse
y que por su importancia pasamos a resumir:
rango: según la representación escogida, los valores que se pueden representar van
desde un mínimo hasta un máximo. Esta limitación existe tanto con números
enteros como con números reales.
precisión: con números reales, la limitación del número de dígitos significativos
implica que no todos los valores puedan representarse exactamente. De hecho,
dentro del rango de cada representación, habrá un número finito de
representaciones exactas, y los números reales se representarán por la más
próxima de aquellas.
overflow/underflow: estos errores se producen cuando al realizar una operación
con dos números en una representación determinada (forzosamente la misma
para los dos) el valor resultante cae fuera del rango de la misma y por tanto no
puede ser codificado en dicha representación (o es codificado incorrectamente).
El Sistema Operativo es el encargado de avisar de que se ha producido uno de
estos errores.
truncamiento: estos errores (o inexactitudes) se producen en las operaciones con
números reales donde la limitación en el número de bits que guarda la mantisa
limita la precisión del resultado, en el cual se pierden las cifras menos
significativas.
Acabemos esta sección, haciendo notar que tanto el software como el hardware
juegan un papel importante en esta aritmética. Operaciones como la suma de
números enteros se realizan directamente por hardware, mientras que las
operaciones que se realizan en función de otras operaciones son supervisadas por el
software de la máquina. De esta forma cada tipo de computador tiene su propia
mezcla de hardware y software para la ejecución de las operaciones aritméticas.
Este no es un tema menor, ya que está ligado al juego de instrucciones que
incorpora la circuiteria del procesador. Como ya vimos, a la hora de seleccionar
ARITMÉTICA Y REPRESENTACIÓN DE INFORMACIÓN EN EL COMPUTADOR
165
una CPU hay que optar entre CISC, una máquina compleja que sea capaz de
decodificar y ejecutar una mayor variedad de instrucciones o RISC un procesador
más simple con un conjunto limitado de instrucciones más utilizadas. Ambas
opciones tienen sus ventajas y sus inconvenientes y en la actualidad existen
máquinas con una u otra arquitectura.
4.3.2.3" REPRESENTACIÓN INTERNA DE DATOS LÓGICOS
Los datos de tipo lógico representan un valor binario, es decir falso (0) o
verdadero (1). Su representación varia de un computador a otro, sin embargo lo
mas común es representar el 0 lógico haciendo 0 todos los bits de la palabra y el
uno lógico con que al menos un bit de la palabra sea 1.
60505" TGRTGUGPVCEKłP"KPVGTPC"FG"RTQITCOCU
Desde el punto de vista de la representación, vamos a distinguir entre un
programa fuente y uno ejecutable. Un programa fuente representa las acciones que
debe realizar el computador expresadas en un determinado lenguaje de alto nivel y
como tal, es una información más, que se interpreta como un texto compuesto de
caracteres. Estos son codificados al introducirlos al computador según el
correspondiente código de E/S (usualmente el código ASCII) que más tarde el
traductor se encargará de transformar en un ejecutable, que se representa de
acuerdo con unos formatos previamente establecidos por el diseñador de la
máquina.
Un programa ejecutable representa las acciones a tomar ya codificadas como
conjunto de instrucciones máquina, y por tanto incomprensibles para el hombre, al
estar codificados con los formatos preestablecidos para la máquina concreta. El
programa adopta la forma de una sucesión de bits que engloba tanto el código
binario de las instrucciones máquina como datos o direcciones utilizados en el
programa.
Como sabemos, la forma que adopta habitualmente el código binario es la de
bloques o campos. El primero de ellos es el código de operación y después de este
pueden haber más campos, que indica la acción correspondiente a la instrucción.
Estos campos dependerán de la operación que se trate. La representación de cada
instrucción debe adecuar su formato a la función que realiza, así:
• Las instrucciones de transferencia deben indicar en los campos adicionales, la
fuente y el destino de su transferencia, que tendrá que ver con alguno de los
siguientes lugares:
166
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
- Un registro de la ALU, dando su número.
- La memoria principal, especificando el lugar (posición) de la memoria
donde se encuentra el dato con el que hay que operar o que hay que
transferir o donde hay que llevarlo.
- Un dispositivo de entrada o de salida, dando el número del dispositivo.
• En las instrucciones aritmético-lógicas, hay que indicar dónde se encuentran los
operandos y dónde hay que depositar el resultado.
• Para codificar una instrucción que bifurque, habrá que indicar en ella la dirección
a la que hay que saltar (esto es donde se encuentra la próxima instrucción a
ejecutar) o donde se encuentra esa dirección de salto.
• Las instrucciones de control son mas sencillas de representar, pues dan una
orden, que normalmente no depende de ningún parámetro (y puede no necesitar
más campo que el código de operación).
Al contrario de lo que ocurre con la representación interna de datos, en el caso de
la representación de instrucciones su relación con la longitud de palabra del
computador es mucho menos rígida, debido a los distintos tipos de instrucciones
que existen. Una instrucción máquina puede ocupar una o varias palabras de
memoria y en algunos computadores, con palabra de varios bytes, se pueden
empaquetar mas de una instrucción en una misma palabra. Además, la relación que
existe entre el lenguaje máquina y el hardware hace que la longitud y composición
de las instrucciones varíen considerablemente de un procesador a otro, aunque
siempre manteniendo las características comunes que acabamos de describir.
6060" GN"EQPEGRVQ"FG"VKRQ"FG"FCVQ
A lo largo del capítulo hemos establecido tanto cómo se representan
internamente en el computador los datos enteros, reales, lógicos y caracteres, como
la forma de operar con ellos. Más concretamente, hemos desarrollado distintos
procedimientos de suma y producto, según sean los datos de punto fijo o flotante.
Por otro lado, hemos visto que las variables son una forma de representar, a alto
nivel, las posiciones de memoria donde se guardan sus valores. Llegados a este
punto se hace evidente la necesidad de utilizar algún mecanismo para que auxilie al
ordenador en dos tareas: 1) Que al consultar el contenido de una variable o alterar
su valor, pueda saber cómo interpretar el valor contenido en la/s celda/s de
memoria correspondientes a esta variable. 2) Que dada una expresión aritmética,
exista un mecanismo para que pueda interpretar qué tipo de operación le está
permitido llevar a cabo con los operandos que le proporciona, en cada momento, la
ejecución del programa (p.e. la suma entera o la suma en punto flotante).
ARITMÉTICA Y REPRESENTACIÓN DE INFORMACIÓN EN EL COMPUTADOR
167
El mecanismo para resolver ambas cuestiones se basa en la introducción del
concepto de tipo de dato; entenderemos como tal, tanto la capacidad de
interpretación de un patrón de bits que representan datos, como las operaciones que
pueden ser llevadas a cabo por estos datos. Afortunadamente durante la parte
declarativa de un programa, existe la posibilidad de definir por parte del
programador la naturaleza de los datos que va a utilizar (p.e. real o entero) y, en
ciertos casos, la representación interna de cada uno de ellos (p.e. real de simple o
doble precisión), lo cual determina automáticamente las operaciones permitidas
entre ellos y la forma como se realizan éstas. Por tanto, los lenguajes de
programación deben facilitar este proceso de especificación, de forma que antes de
utilizar una variable, ésta deba declararse como perteneciente a un determinado
tipo. De esta forma, el computador no tendrá ninguna ambigüedad en la
representación interna de los valores de la variable ni en las operaciones a realizar
con ellos. Veamos el siguiente ejemplo:
caso a
tipo x: entero
tipo y: entero
tipo z: entero
caso b
tipo x: real
tipo y: real
tipo z: real
caso c
tipo x: caracter
tipo y: caracter
tipo z: caracter
caso d
tipo x: entero
tipo y: entero
tipo z: caracter
z←x*y
z←x*y
z←x*y
z←x*y
En el caso a), los valores de x, y, z serán representados internamente utilizando la
representación en punto fijo, y el producto se realizará con aritmética binaria. En el
caso b), los valores de las variables se representarán utilizando mantisa y
exponente, y el producto se realizará con aritmética de punto flotante. En el caso
c), la expresión entre las variables no tiene sentido, puesto que no podemos
multiplicar dos caracteres. En el caso d), la expresión z←x*y tampoco tiene
sentido, puesto que aunque es posible multiplicar los valores de x e y, su resultado
es entero y no puede asignarse a una variable de tipo caracter.
Así, la declaración de un tipo de dato en un programa, permite:
- Una forma inequívoca de representar, interpretar y tratar la información.
- Ahorrar memoria (eligiendo el tipo que, pudiendo representar los valores de
una variable, ocupa menos memoria)
- Efectuar las operaciones de la forma más eficiente (recuérdese que aunque
las operaciones parecen las mismas, la aritmética en punto flotante es más
costosa que la binaria).
168
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
- Evitar errores de truncamiento, utilizando la aritmética en punto flotante sólo
en los casos en que sea imprescindible.
- Detectar errores en las expresiones, sin conocer cual es su valor concreto en
un momento dado (casos c y d en el ejemplo anterior).
En algunos casos, existe una cierta flexibilidad y es posible efectuar operaciones
que involucren variables que no sean del mismo tipo. Consideremos la siguiente
situación:
Precio y Tasa: tipo entero
Total: tipo real
Total ← Precio + Tasa
en este caso el compilador utiliza la suma entera y su resultado lo recodificará en
un formato de punto flotante, antes de asignarlo a Total. Esta conversión implícita
entre tipos se llama coerción y depende de cada lenguaje el que avise de su
existencia.
Como veremos, los lenguajes de programación incorporan las definiciones de tipos
de datos, sin que el programador tenga que preocuparse por su representación
interna, por las operaciones permitidas o por la forma de llevarlas a cabo, ya que
todo ello queda encapsulado dentro de la instrucción tipo, facilitando en gran
medida la tarea de programación a alto nivel.
Veamos como se declaran las variables en los lenguajes que estamos considerando:
FORTRAN
BASIC
tipo lista de variables
tipo es INTEGER
DEFINT - enteras
DEFINT - simple precisión
DEFDBL - doble precisión
DEFSTR - cadena
REAL
DOUBLE PRECISION
LOGICAL
COMPLEX
CHARACTER * n
(n, longitud de la cadena)
DEF tipo rango letras,
letras...
tipo: INT, SNG, DBL, STR
rango
RCUECN
C
xct lista_de_nombres1: tipo1;
tipo1 lista_de_nombres1;
tipo2 lista_de_nombres2;
ARITMÉTICA Y REPRESENTACIÓN DE INFORMACIÓN EN EL COMPUTADOR
169
lista_de_nombres2: tipo2;
(Existe la posibilidad de definir tipos por el programador).
Es de destacar que, para obtener la mayor eficiencia en la representación de los
datos y su manejo, suelen suministrarse muchos tipos posibles. Por ejemplo, el
lenguaje Pascal tiene 5 tipos de enteros y 5 tipos de reales. Por poner un ejemplo
más concreto, un determinado compilador de lenguaje C con palabras de 16 bits
permite los siguientes tipos de datos simples numéricos
char
unsigned char
int
unsigned int
long
1 byte
1 byte
2 bytes
2 bytes
4 bytes
complemento a 2
sin signo
complemento a 2
sin signo
complemento a 2
unsigned long
float
double
long double
4 bytes
4 bytes
8 bytes
10 bytes
sin signo
simple precisión
doble precisión
doble precisión
enteros de -128 a 127
enteros de 0 a 255
enteros de -32 768 a 32 767
enteros de 0 a 65 535
enteros de -2 147 483 648 a
2 147 483 647
enteros de 0 a 4 294 967 295
reales (7 dígitos) en ± 3.4 . 1038
reales (15 dígitos) en ± 1.7 .10308
reales (19 dígitos) en ± 1.2 104932
Los vistos a lo largo de este capítulo son los llamados datos de tipo simple:
enteros, lógicos, reales y alfanuméricos (algunos lenguajes como el C tienen un
tipo simple adicional, el tipo puntero, que es un valor numérico entero sin signo
para guardar una dirección de memoria - se dice que ‘apunta’ a una posición de la
memoria). A partir de la agrupación de datos de tipo simple se pueden construir
tipos compuestos, dotados de una cierta estructura. Sin embargo desde el punto de
representación interna, el computador lo tratará siguiendo los principios que hemos
descrito hasta aquí.
170
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
4.1. SISTEMAS DE NUMERACIÓN EN INFORMÁTICA ...........................137
4.1.1 DEFINICIÓN DEL SISTEMA BINARIO...................................................139
4.1.2 TRANSFORMACIONES ENTRE BASES BINARIA Y DECIMAL.........139
4.1.3 CÓDIGOS INTERMEDIOS ........................................................................141
4.2. OPERACIONES ARITMÉTICAS Y LÓGICAS ......................................143
4.2.1 OPERACIONES ARITMÉTICAS CON NÚMEROS BINARIOS .............143
4.2.2 VALORES BOOLEANOS Y OPERACIONES LÓGICAS ........................144
4.2.3 PUERTAS LÓGICAS ..................................................................................145
4.2.4 ARITMÉTICA CON PUERTAS LÓGICAS ...............................................146
4.3. REPRESENTACIÓN DE INFORMACIÓN EN EL COMPUTADOR ..150
4.3.1 LA CODIFICACIÓN EN INFORMÁTICA ................................................150
4.3.2 REPRESENTACIÓN INTERNA DE DATOS ............................................153
4.3.3 REPRESENTACIÓN INTERNA DE PROGRAMAS ................................165
4.4. EL CONCEPTO DE TIPO DE DATO.......................................................166
CAPÍTULO 5
ESTRUCTURAS DE DATOS
En la práctica, la mayor parte de información útil no aparece aislada en forma de
datos simples, sino que lo hace de forma organizada y estructurada. Los
diccionarios, guías, enciclopedias, etc., son colecciones de datos que serían inútiles
si no estuvieran organizadas de acuerdo con unas determinadas reglas. Además,
tener estructurada la información supone ventajas adicionales, al facilitar el acceso
y el manejo de los datos. Por ello parece razonable desarrollar la idea de la
agrupación de datos, que tengan un cierto tipo de estructura y organización interna.
Como tendremos ocasión de ver, la selección de una estructura de datos frente a
otra, a la hora de programar es una decisión importante, ya que ello influye
decisivamente en el algoritmo que vaya a usarse para resolver un determinado
problema. El objetivo de este capítulo no es sólo la descripción de las distintas
estructuras, sino también la comparación de las mismas en términos de utilidad
para la programación. De hecho, se trata de dar una idea, acerca de los pros y
contras de cada una de ellas con el propósito final de justificar la ya citada
ecuación de:
PROGRAMACION = ESTRUCTURAS DE DATOS + ALGORITMOS
7030" GN"EQPEGRVQ"FG"FCVQU"GUVTWEVWTCFQU0
Empecemos recordando que un dato de tipo simple, no esta compuesto de
otras estructuras, que no sean los bits, y que por tanto su representación sobre el
ordenador es directa, sin embargo existen unas operaciones propias de cada tipo,
que en cierta manera los caracterizan. Una estructura de datos es, a grandes
rasgos, una colección de datos (normalmente de tipo simple) que se caracterizan
por su organización y las operaciones que se definen en ellos. Por tanto, una
estructura de datos vendrá caracterizada tanto por unas ciertas relaciones entre los
datos que la constituyen (p.e., el orden de las componentes de un vector de
números reales), como por las operaciones posibles en ella. Esto supone que
podamos expresar formalmente, mediante un conjunto de reglas, las relaciones y
operaciones posibles (tales como insertar nuevos elementos o como eliminar los ya
171
172
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
existentes). Por el momento y a falta de otros, pensemos en un vector de números,
como el mejor ejemplo de una estructura de datos.
Llamaremos dato de tipo estructurado a una entidad, con un solo identificador,
constituida por datos de otro tipo, de acuerdo con las reglas que definen cada una
de las estructuras de datos. Por ejemplo: una cadena esta formada por una
sucesión de caracteres, una matriz por datos simples organizados en forma de filas
y columnas y un archivo, está constituido por registros, éstos por campos, que se
componen, a su vez, de datos de tipo simple. Por un abuso de lenguaje, se tiende a
hacer sinónimos, el dato estructurado con su estructura correspondiente. Aunque
ello evidentemente no es así, a un primer nivel, en este libro, asumiremos esta
identificación.
Para muchos propósitos es conveniente tratar una estructura de datos como si fuera
un objeto individual y afortunadamente, muchos lenguajes de programación
permiten manipular estructuras completas como si se trataran de datos individuales,
de forma que los datos estructurados y simples se consideran a menudo por el
programador de la misma manera. Así a partir de ahora un dato puede ser tanto un
entero como una matriz, por nombrar dos ejemplos.
Las estructuras de datos son necesarias tanto en la memoria principal como en la
secundaria, de forma que en este capítulo nos centraremos en las correspondientes
a la memoria principal, dejando para el capítulo siguiente las estructuras más
adecuadas para el almacenamiento masivo de datos.
7040" VKRQU"FG"FCVQU"GUVTWEVWTCFQU
Los datos de tipo simple tienen una representación conocida en términos
de espacio de memoria. Sin embargo, cuando nos referimos a datos estructurados
esta correspondencia puede no ser tan directa; por ello vamos a hacer una primera
clasificación de los datos estructurados en: contiguos y enlazados. Las estructuras
contiguas o físicas son aquellas que al representarse en el hardware del ordenador,
lo hacen situando sus datos en áreas adyacentes de memoria; un dato en una
estructura contigua se localiza directamente calculando su posición relativa al
principio del área de memoria que contiene la estructura. Los datos se relacionan
por su vecindad o por su posición relativa dentro de la estructura. Las estructuras
enlazadas son estructuras cuyos datos no tienen por qué situarse de forma contigua
en la memoria; en las estructuras enlazadas los datos se relacionan unos con otros
mediante punteros (un tipo de dato que sirve para ‘apuntar’ hacia otro dato y por
tanto para determinar cuál es el siguiente datos de la estructura). La localización de
un dato no es inmediata sino que se produce a través de los punteros que relacionan
unos datos con otros.
ESTRUCTURAS DE DATOS
173
Los datos estructurados se pueden clasificar, también, según la variabilidad de su
tamaño durante la ejecución del programa en: estáticos y dinámicos. Las
estructuras estáticas son aquellas en las que el tamaño ocupado en memoria, se
define con anterioridad a la ejecución del programa que los usa, de forma que su
dimensión no puede modificarse durante la misma (p.e., una matriz) aunque no
necesariamente se tenga que utilizar toda la memoria reservada al inicio (en todos
los lenguajes de programación las estructuras estáticas se representan en memoria
de forma contigua). Por el contrario, ciertas estructuras de datos pueden crecer o
decrecer en tamaño, durante la ejecución, dependiendo de las necesidades de la
aplicación, sin que el programador pueda o deba determinarlo previamente: son las
llamadas estructuras dinámicas. Las estructuras dinámicas no tienen teóricamente
limitaciones en su tamaño, salvo la única restricción de la memoria disponible en el
computador.
Estas dos clasificaciones nos ayudarán a exponer los distintos tipos de datos
estructurados, incidiendo en las ventajas e inconvenientes para su almacenamiento
y tratamiento, en términos de la eficacia de una determinada aplicación ya sea de
economía espacial (no emplear más memoria de la necesaria) o temporal (emplear
el menor tiempo posible en las operaciones).
7050" GUVTWEVWTCU"FG"FCVQU"EQPVKIWCU
Vamos a estudiar una serie de agrupaciones de datos que son utilizadas en
todos los lenguajes de programación, y que tienen en común la ubicación de sus
datos en zonas de memoria adyacentes.
70503" Ecfgpcu
La cadena es quizás la estructura más simple y se define como una
secuencia de caracteres que se interpretan como un dato único. Su longitud puede
ser fija o variable por lo que, además de saber que están constituidas por caracteres
alfanuméricos, hemos de conocer su longitud. En una variable tipo cadena se puede
almacenar una palabra, una frase, una matricula de coche, una temperatura, etc. La
longitud de una cadena se puede determinar bien indicando al principio de la
misma el número de caracteres que contiene, bien situando un carácter especial
denominado fin-de-cadena. Los siguientes ejemplos muestran los dos métodos de
representar la cadena “Capital 94” :
174
10
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
C
a
p
Long.
i
t
a
l
9
4
C
a
p
Cadena (long. = 10)
i
t
a
l
9
4
#
Fin de
cadena
Cadena (long. = 10)
en el segundo caso el carácter elegido como fin-de-cadena ha sido el #. La cadena
que no contiene ningún carácter se denomina cadena vacía y su longitud es 0, que
no tiene que ser confundida por una cadena formada sólo por blancos (o espacios),
cuya longitud es igual al número de blancos que contiene. De esta manera, una
variable de tipo cadena de tamaño 10 puede guardar cadenas de 10 caracteres, pero
también de menos si indicamos dónde terminan los caracteres de la cadena. Por
ejemplo la cadena “Jaca 99”:
7
Long.
J
a
c
a
9
Cadena (long. = 7)
9
J
Libre
a
c
a
9
Cadena (long. = 7)
9
#
Fin de
cadena
Libre
Sobre datos de tipo cadena se pueden realizar las siguientes operaciones:
Asignación: Guardar una cadena en una variable tipo cadena. Como en toda
asignación a una variable, la cadena que se guarda puede ser una constante, una
variable tipo cadena o una expresión que produzca un dato tipo cadena. Por
ejemplo:
nombre ← “Pepe”
nombre ← mi-nombre-de-pila
Concatenación: Formar una cadena a partir de dos ya existentes, yuxtaponiendo
los caracteres de ambas. Si se denota por // al operador “concatenación”, el
resultado de:
“ab” // “cd” es “abcd”
Nótese que las constantes de tipo cadena se escriben entre comillas, para no
confundirlos con nombres de variables u otros identificadores del programa.
Extracción de subcadena: Permite formar una cadena (subcadena) a partir de otra
ya existente. La subcadena se forma tomando un tramo consecutivo de la cadena
inicial. Si NOMBRE es una variable de tipo cadena que contiene “JUAN PEDRO
ORTEGA” y denotamos por (n:m) la extracción de m caracteres tomados a partir
del lugar n, entonces NOMBRE(6:5) es una subcadena que contiene “PEDRO”.
ESTRUCTURAS DE DATOS
175
Un caso particular de extracción que se utiliza a menudo es el de extraer un único
caracter. Por ello se suele proporcionar un método directo: el nombre seguido por
el lugar que ocupa dentro de la cadena. Así, en el ejemplo anterior, NOMBRE(6) =
“P” = NOMBRE(6:1)
Obtención de longitud: La longitud de una cadena es un dato de tipo entero, cuyo
valor es el número de caracteres que contiene ésta. En el primero de los dos
métodos anteriores de representación de cadenas, la longitud se obtiene
consultando el número de la primera casilla; en el segundo método la longitud es el
número de orden que ocupa el caracter de fin-de-cadena, menos uno.
Comparación de cadenas: Consiste en comparar las cadenas carácter a carácter
comenzando por el primero de la izquierda, igual que se consulta un diccionario. El
orden de comparación viene dado por el código de E/S del ordenador (ASCII
habitualmente). Así la expresión booleana: “Jose” < “Julio”, se evaluara como
verdadera. Nótese que en los códigos de E/S, las mayúsculas y las minúsculas son
diferentes, dando lugar a resultados paradójicos en la comparación, así pues, si el
código de E/S es ASCII, donde las mayúsculas tienen códigos inferiores a las
minúsculas, se cumpliría que “Z” < “a”.
70504" Cttc{u3
Es un conjunto de datos del mismo tipo almacenados en la memoria del
ordenador en posiciones adyacentes. Sus componentes individuales se llaman
elementos y se distinguen entre ellos por el nombre del array seguido de uno o
varios índices o subíndices. Estos elementos se pueden procesar, bien
individualmente, determinando su posición dentro del array, bien como array
completo. El número de elementos del array se específica cuando se crea éste, en la
fase declarativa del programa, definiendo el número de dimensiones o número de
índices del mismo y los límites máximo y mínimo que cada uno de ellos puede
tomar, que llamaremos rango. Según sea este número, distinguiremos los
siguientes tipos de arrays:
- unidimensionales (vectores)
- bidimensionales (matrices)
- multidimensionales
Por ello hablaremos de arrays de dimensión 1, 2 ó n, cuyo producto por el rango (o
rangos) especifica el número de elementos que lo constituyen. Este dato lo utiliza
el compilador para reservar el espacio necesario para almacenar en memoria todos
1
Utilizaremos el término array, ya que su traducción castellana, “arreglo, colección, etc” es poco significativa y la
imensa mayoría de veces se usa en el argot informático el anglicismo array. Sin embargo, sí usaremos vector y
matriz para referirnos a determinados tipos de array.
176
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
sus elementos ocupando un área contigua. Cada elemento ocupa el mismo número
de palabras, que será el que corresponda al tipo de éstos. No debemos olvidar que,
al nivel físico, la memoria es lineal; por ello los elementos se colocan en la
memoria linealmente según un orden prefijado de los índices.
En el ejemplo de la figura el número de dimensiones es 2, su rango (3;5) y el
número total de elementos es 15.
elemento
(2,4)
1
2
3
1
2
3
4
5
Fig. 5.1.
Representación de un array bidimensional.
5.3.2.1" Vectores
Por motivos de simplicidad y mayor frecuencia de uso, a la hora de revisar las
operaciones con arrays nos centraremos en los vectores, que además presentan la
ventaja de ser estructuras ordenadas (sólo existe orden total cuando tenemos
estructuras de una dimensión o lineales). Las notaciones algorítmicas que
utilizaremos son:
nombre_vector =
vector [inf . . sup] de tipo
nombre_vector
inf .. sup
nombre válido del vector
límites inferior y superior del rango
(valor entero que puede tomar el índice)
tipo de los elementos del vector
{entero, real, carácter}
tipo
La declaración de un vector supone una mera reserva de espacio, pudiéndose
asumir que, hasta que asignemos valores por cualquier mecanismo a sus distintos
elementos, estamos ante una estructura vacía.
NUMEROS = vector [1..10] de real
significa que NUMEROS es un vector, que podrá contener como elementos, al
menos 10 números de tipo real, cuyos índices varían desde el 1 hasta el 10.
FORTRAN
BASIC
ESTRUCTURAS DE DATOS
REAL X(10)
DIM X(10) AS SINGLE
RCUECN
x: array[1..10] of real
C
float x[10]
177
Es importante señalar que podemos implementar arrays cuyos elementos sean a su
vez cadenas o elementos de otro tipo, así podemos pensar en situaciones como la
siguiente, durante la fase declarativa
tipo: palabra = cadena[16]
COCHES = vector [1..9] de palabra
lo que nos permitirá manipular en un solo vector hasta 9 cadenas conteniendo
como máximo 16 caracteres cada una. Con lo cual COCHES puede contener una
información tal como:
1
2
3
4
5
6
7
8
9
Alfa Romeo
Fiat
Ford
Lancia
Renault
Seat
Ya hemos dicho que las operaciones sobre arrays se pueden realizar con elementos
individuales o sobre la estructura completa mediante las correspondientes
instrucciones y estructuras de control del lenguaje. Las operaciones sobre
elementos del vector son:
Asignación: Tiene el mismo significado que la asignación de un valor a una
variable no dimensionada, ya que un vector con su índice representa la misma
entidad que una variable no dimensionada.
A[20] ← 5 asigna el valor 5 al elemento 20 del vector A
A[17] ← B asigna el valor de la variable B al elemento 17 del vector A
Acceso secuencial o recorrido del vector: Consiste en acceder a los elementos de
un vector para someterlos a un determinado proceso, tal como introducir datos
(escribir) en él, visualizar su contenido (leer), etc.. A la operación de efectuar una
acción general sobre todos los elementos de un vector se la denomina recorrido y
para ello utilizaremos estructuras repetitivas, cuyas variables de control se utilizan
178
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
como subíndices del vector, de forma que el incremento del contador del bucle
producirá el tratamiento sucesivo de los elementos del vector.
Ejemplo 1:
Escribir un algoritmo para recorrer secuencialmente un vector H de 10 elementos
(haciendo la lectura y escritura de cada elemento) primero con un bucle desde y
luego con un bucle mientras.
El pseudocódigo correspondiente será el siguiente:
desde i ← 1 hasta 10 hacer
leer (H[i])
escribir (H[i])
fin_desde
i←1
mientras i <= 10 hacer
leer (H[i])
escribir (H[i])
i ← i+1
fin-mientras
Ejemplo 2:
Supongamos que queremos procesar los primeros elementos de un vector
PUNTOS, previamente declarado, realizando las siguientes operaciones desde 1
hasta LIMITE (donde este valor debe necesariamente ser menor que el límite
superior del rango): a) lectura del array; b) cálculo de la suma de los valores del
array; c) cálculo de la media de los valores. Escribir el algoritmo correspondiente.
inicio
escribir ‘número de datos’
leer numero
suma ← 0
escribir ‘datos del array’
desde i=1 hasta numero hacer
leer PUNTOS[i]
suma ← suma + PUNTOS[i]
fin_desde
media ← suma/numero
escribir ‘la media es’, media
fin
BÚSQUEDA EN UN VECTOR: Esta operación, relacionada con la recuperación
de información, consiste en encontrar un determinado valor dentro del vector,
obteniendo su posición en el mismo en caso que éste exista o declarar la búsqueda
ESTRUCTURAS DE DATOS
179
como fallida en caso de no encontrarlo. La experiencia a la hora de buscar un dato
entre una colección de ellos nos dice que este proceso varía sensiblemente según
que éstos estén o no ordenados; por esta razón presentaremos dos métodos básicos,
según que el vector esté desordenado u ordenado.
Búsqueda secuencial: Consiste en recorrer el vector, con sus datos no
necesariamente ordenados, del principio hacia el final. Si se encuentra el valor
buscado se da por finalizada la búsqueda; en caso contrario, tras haber recorrido
todo el vector se indica que el elemento en cuestión no se encuentra almacenado en
el vector. Supongamos que deseamos localizar un determinado valor, que,
obviamente, supondremos es del mismo tipo que los elementos del vector de rango
n. El algoritmo es el siguiente:
algoritmo búsqueda_secuencial
A: vector donde se busca (contiene n elementos)
t: valor buscado
inicio
encontrado ← Falso
i←1
mientras (i <= n) y (encontrado = Falso) hacer
si t = A[i]
entonces
escribir ‘Se encontró el elemento buscado en la posición’, i
encontrado ← Verdadero
si_no
i←i+1
fin_si
fin_mientras
si i = n+1 {también puede utilizarse si encontrado = Falso}
entonces
escribir ‘No se encuentra el elemento’
si_no
escribir ‘El elemento se encuentra en la posición’, i
fin_si
fin
Una manera más eficaz de realizar una búsqueda secuencial consiste en modificar
el algoritmo utilizando un elemento centinela. Este elemento se agrega al vector al
final del mismo. El valor del elemento centinela es el del argumento. El propósito
de este elemento centinela, A[n+1], es significar que la búsqueda siempre tendrá
éxito. El elemento A[n+1] sirve como centinela y se le asigna el valor de t antes de
iniciar la búsqueda. En cada paso se evita la comparación de i con n y por
180
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
consiguiente este algoritmo será preferible al método anterior. Si el índice
alcanzase el valor n+1, supondrá que el argumento no pertenece al vector original y
en consecuencia la búsqueda no tiene éxito.
algoritmo búsqueda_centinela
A: vector donde se busca (contiene n elementos); t: valor buscado
inicio
encontrado ← Falso
i←1
A[n+1] ← t
mientras A(i) <> t hacer
i←i+1
fin_mientras
si i = n+1
entonces
escribir ‘No se encuentra el elemento’
si_no
entonces
escribir ‘El elemento se encuentra en la posición’, i
fin_si
fin
Notemos que, a pesar de esta mejora, el número de comparaciones que hemos de
efectuar es del orden de la magnitud del vector y si ésta es muy grande el tiempo
necesario para la búsqueda puede ser alto. Por ello, puede valer la pena tener
ordenado el vector pues, como veremos ahora, las búsquedas sobre vectores
ordenados son sensiblemente más rápidas.
Búsqueda binaria: Se aplica a vectores cuyos datos han sido previamente
ordenados y es un ejemplo del uso del ‘divide y vencerás’ para localizar el valor
deseado. Más adelante, trataremos los algoritmos (y su coste) para ordenar un
vector; sin embargo ahora supondremos que esta ordenación ya ha tenido lugar. El
algoritmo de búsqueda binaria se basa en los siguientes pasos:
1) Examinar el elemento central del vector; si éste es el elemento buscado,
entonces la búsqueda ha terminado
2) En caso contrario, se determina si el elemento buscado está en la
primera o en la segunda mitad del vector (de aquí el nombre de binario) y a
continuación se repite este proceso, utilizando el elemento central del subvector
correspondiente.
Ejemplo 3:
ESTRUCTURAS DE DATOS
181
Considerar el siguiente vector ordenado de nueve elementos enteros, donde
queremos buscar el valor 2983
1
2473
2
2545
3
2834
4
2892
5
2898
central
6
2983
7
3005
8
3446
9
3685
Para buscar el elemento 2983, se examina el número central 2898, situado en la
quinta posición, que resulta ser distinto. Al ser 2983 mayor que 2898, se desprecia
la primera mitad del vector, quedándonos con la segunda:
6
2983
7
3005
central
8
3446
9
3685
Se examina ahora el número central 3005, situado en la posición 7, que resulta ser
distinto. Al ser 2983 menor que 3005, nos quedamos con la primera mitad del
vector:
6
2983
central
Finalmente encontramos que el valor buscado coincide con el central. Nótese que si
el valor buscado hubiera sido, por ejemplo, el 2900, la búsqueda habría finalizado
con fracaso al no quedar mitades donde buscar.
Vamos a dar el algoritmo de búsqueda binaria para encontrar un elemento K, en un
vector de elementos X(1), X(2),..., X(n), previamente clasificados en orden
ascendente (ordenado en orden creciente si los datos son numéricos, o
alfabéticamente si son caracteres). El proceso de búsqueda debe terminar
normalmente conociendo si la búsqueda ha tenido éxito (se ha encontrado el
elemento) o bien no ha tenido éxito (no se ha encontrado el elemento), y
normalmente se deberá devolver la posición del elemento buscado dentro del
vector. Las variables enteras BAJO, CENTRAL, ALTO, indican los límites
inferior, central y superior del intervalo de búsqueda, en cada subvector que
sucesivamente se esta considerando, durante la búsqueda binaria.
algoritmo búsqueda_binaria
X: vector de N elementos
K: valor buscado
inicio
BAJO ← 1
182
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
ALTO ← N
CENTRAL ← ent((BAJO + ALTO) / 2)
mientras BAJO < ALTO y X[CENTRAL] <> K hacer
si K < X[CENTRAL]
entonces
ALTO ← CENTRAL - 1
si_no
BAJO ← CENTRAL + 1
fin_si
CENTRAL ← ent ((BAJO + ALTO) / 2)
fin_mientras
si K = X(CENTRAL)
entonces escribir ‘valor encontrado en’, CENTRAL
si_no escribir ‘valor no encontrado’
fin_si
fin
La función ent, entenderemos que obtiene un entero redondeándolo por defecto.
El funcionamiento del algoritmo de búsqueda binaria, en un vector de
enteros, se ilustra en la Figura 5.2 para dos búsquedas: los enteros 8 y 11 que
finalizan respectivamente con éxito (localizado el elemento) y sin éxito (no
encontrado el elemento)
Aunque dejamos para un capítulo posterior el análisis de la complejidad
algorítmica, con el único objeto de ilustrar la diferencia entre los dos tipos de
búsqueda, digamos que para un vector de 1000 elementos, la búsqueda secuencial
supone efectuar un promedio de unas 500 comparaciones, mientras que la binaria,
resuelve el problema con sólo 10 en el peor de los casos. Otra cuestión, es el
esfuerzo que nos suponga ordenar el vector, pero esto lo veremos más adelante.
ESTRUCTURAS DE DATOS
Fig. 5.2.
183
Ejemplo de búsqueda binaria: (a), con éxito; (b), sin éxito.
Insertar datos en un vector
La operación insertar consiste en colocar un nuevo elemento, en una
determinada posición del vector; ello supone no perder la información, que
pudiera hallarse anteriormente, en la posición que va a ocupar, el valor a insertar.
Es condición necesaria para que esta operación pueda tener lugar, la comprobación
184
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
de espacio de memoria suficiente en el vector, para el nuevo valor; dicho de otro
modo, que el vector no tenga todos sus elemento ocupados por datos. Cada vez que
insertamos un dato en una determinada posición hemos de correr todos los
elementos posteriores del vector, hacia abajo, poniendo especial cuidado en que no
se pierda ninguno de estos datos.
Ejemplo 4:
Consideremos el ya visto vector COCHES de 9 elementos que contiene 7 marcas
de automóviles, en orden alfabético, en el que se desea insertar dos nuevas marcas
OPEL y CITRÖEN manteniendo el orden alfabético del vector. Como Opel está
comprendido entre Lancia y Renault, se deberán desplazar hacia abajo los
elementos 5 y 6, que pasarán a ocupar la posición relativa 6 y 7. Posteriormente
debe realizarse la misma operación con Citröen que ocupará la posición 2. El
algoritmo que realiza esta operación para un vector de n elementos es el siguiente,
suponiendo que hay espacio suficiente en el vector, y que conocemos la posición,
que designaremos por P, que debe ocupar el elemento a insertar. Por ejemplo, la
primera inserción, supone que Opel debe ocupar la posición P = 5.
i ← n {Indicar el número de posiciones del vector que ya están ocupadas}
mientras i> = P hacer
{mover el elemento actual i-ésimo hacia abajo, a la posición i+1}
COCHES[i+1] ← COCHES[i]
{decrementar contador}
i ← i-1
fin_mientras
{insertar el elemento en la posición P}
COCHES[P] ← “Opel”
{actualizar el contador de elementos del vector}
n ← n + 1 {el vector acaba con un elemento más ocupado por datos}
fin
1.
2.
3.
4.
5.
6.
Los contenidos sucesivos del vector COCHES son los siguientes:
1
Alfa Romeo
1
Alfa Romeo
1
Alfa Romeo
2
Fiat
2
Fiat
2
Citröen
3
Ford
3
Ford
3
Fiat
4
Lancia
4
Lancia
4
Ford
5
Renault
5
Opel
5
Lancia
ESTRUCTURAS DE DATOS
6
Seat
6
Renault
6
Opel
7
7
Seat
7
Renault
8
8
8
Seat
9
9
9
185
Eliminar datos de un vector
La operación de borrar es distinta, según el elemento a eliminar se
encuentre al final del vector (no presenta ningún problema) o se borre un elemento
del interior de mismo vector. En este último la eliminación provocara el
movimiento hacia arriba de los elementos posteriores a él para reorganizar el
vector. El algoritmo de borrado del dato almacenado en el elemento j-ésimo del
vector COCHES es el siguiente:
algoritmo borrado {borrar el elemento j-ésimo}
inicio
desde i = j hasta N - 1
{llevar elemento i + 1 hacia arriba}
COCHES[i] ← COCHES[i+1]
fin-desde
{actualizar contador de elementos}
{ahora COCHES tendrá ocupado por datos un elementos menos, n - 1}
N←N-1
fin
5.3.2.2" Matrices
Llamaremos matriz o tabla a un array bidimensional, esto es, un conjunto
de elementos del mismo tipo en el que sus componentes vienen definidos por dos
subíndices, el primero referido a la fila y el segundo a la columna. Además de las
matrices, que utilizamos en álgebra lineal, un ejemplo típico de esta estructura es el
tablero de ajedrez, que se representa por un array T[8,8]. Se puede representar la
posición o casilla (recuadro) de cada tablero del siguiente modo:
T[i,j] = 0 si no existe ninguna pieza en la fila i-esima y columna j-esima
T[i,j] = 1 si la casilla contiene un peón blanco
= 2 para un caballo blanco
= 3 para alfil blanco
186
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
= 4 para una torre blanca
= 5 para una reina blanca
= 6 para un rey blanco
con los correspondientes números negativos para las piezas negras.
Puesto que la memoria del ordenador no está organizada en forma rectangular sino
en forma de una enorme fila para almacenar una matriz hemos de recurrir a guardar
las filas una a continuación de otra. Así, si en una matriz con un número de
columnas C, que es el número de elementos que tiene cada fila, para localizar el
elemento de fila i y columna j, tendríamos que movernos, desde la posición de
inicio de la matriz, hasta la posición: C*(i-1) + j. Afortunadamente el propio
software del sistema se encarga de convertir los términos en forma de filas y
columnas, en localizaciones concretas dentro de la memoria, de forma que
podemos pensar conceptualmente en forma de tabla, aunque se almacenen en forma
de fila, dentro de la máquina2.
5.3.2.3" Arrays multidimensionales
Dependiendo del tipo de lenguaje, pueden existir arrays de tres o más
dimensiones (por ejemplo FORTRAN 77 admite hasta siete dimensiones). Para el
caso de tres dimensiones, la estructura puede visualizarse como un cubo, y para
mayor número de dimensiones ésta visualización no es posible.
El tratamiento de estos arrays es similar al de las matrices, cada conjunto de índices
individualiza un elemento de la estructura, que se almacena en memoria de forma
secuencial.
70505" Tgikuvtqu
Hasta ahora nos hemos referido a estructuras formadas por datos simples
del mismo tipo; sin embargo, es interesante poder manejar una especie de arrays
heterogéneos en los que sus elementos puedan ser de tipos diferentes. Llamaremos
registro a una estructura de datos, formada por yuxtaposición de elementos que
contienen información relativa a un mismo ente. A los elementos que componen el
registro los llamamos campos, cada uno de los cuales es de un determinado tipo,
simple o estructurado. Los campos dentro del registro aparecen en un orden
determinado y se identifican por un nombre. Para definir el registro es necesario
2
La forma de almacenar ls matrices expuesta se conoce como “orden principal de la fila”, pero no es la única. Así
el FORTRAN utiliza el “orden principal de la columna” consistente en almacenar los elementos de una columna
consecutivamente y pasar a la columna siguiente.
ESTRUCTURAS DE DATOS
187
especificar el nombre y tipo de cada campo. Por ejemplo consideremos un registro,
referido a Empleado, que está constituido por tres campos: Nombre (cadena), Edad
(entero) y Porcentaje de impuestos (real).
Nombre
Edad
Porcentaje de impuestos
Las operaciones básicas que se ejecutan con los registros son: asignación del
registro completo a una variable de tipo registro, (definida con sus mismos campos)
y selección de un campo, que se realiza especificando el nombre del campo. Puesto
que esta estructura, esta especialmente ligada a las transferencias con los
periféricos de almacenamiento, volveremos sobre ella cuando nos refiramos a los
archivos.
7060" GUVTWEVWTCU"FKPıOKECU"["RWPVGTQU
Hasta este momento hemos venido trabajando con variables,
dimensionadas o no, que son direcciones simbólicas de posiciones de memoria, de
forma que existe una relación bien determinada entre nombres de variables y
posiciones de memoria durante toda la ejecución del programa. Aunque el
contenido de una posición de memoria asociada con una variable puede cambiar
durante la ejecución, es decir el valor asignado a la variable puede variar, las
variables por si mismas no pueden crecer ni disminuir, durante la ejecución. Sin
embargo, en muchas ocasiones es conveniente poder disponer de un método por el
cual, podamos adquirir posiciones de memoria adicionales, a medida que las
vayamos necesitando durante la ejecución y al contrario liberarlas cuando no se
necesiten.
Las variables y estructuras de datos que reúnen estas condiciones se llaman
dinámicas3 y se representan con la ayuda de un nuevo tipo de dato, llamado
puntero, que se define como un dato que indica la posición de memoria ocupada
por otro dato. Puede concebirse como una flecha, que “apunta”, al dato en cuestión
(Ver Figura 5.3).
3
El concepto de estructura dinámica se refiere a la utilización de punteros que permiten que la estructura tenga las
propiedades expuestas. Sin embargo, como veremos más adelante, éste es un concepto ligado a la implementación
que se haga de la estructura y no de la estructura en sí. Así hay estructuras que pueden implementarse estática o
dinámicamente (p.e. colas o pilas).
188
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Fig. 5.3 Representación de un puntero
Los punteros proporcionan los enlaces de unión entre los elementos, permitiendo
que, durante la ejecución del programa, las estructuras dinámicas puedan cambiar
sus tamaños. En las estructuras dinámicas estos elementos, llamados nodos, son
normalmente registros de al menos dos campos, donde por lo menos uno de ellos,
es un puntero (es decir contiene información que permite localizar al siguiente siguientes- nodo de la estructura). Ver Figura 5.4.
DATOS
Fig. 5.4.
PUNTERO
Representación de un nodo
La utilización de punteros permite que sea relativamente fácil añadir
indeterminadamente nuevos datos, insertar nuevos nodos en otros ya existentes y
en general modificar estas estructuras. Dependiendo de las relaciones entre los
nodos de la estructura hablaremos de estructuras lineales y no lineales: si partiendo
del nodo inicial es posible dirigirse sucesivamente a todos los nodos visitando cada
uno una única vez diremos que es una estructura lineal; en caso de no ser posible
el recorrido en estas condiciones se habla de estructura no lineal.
7070" GUVTWEVWTCU"NKPGCNGU
Una lista en su sentido amplio, es un conjunto de datos del mismo tipo
(simple o estructurado), cada elemento de la cual tiene un único predecesor
(excepto el primero) y un único sucesor (excepto el último) y cuyo numero de
elementos es variable. Se distinguen dos tipos de listas: contiguas y lineales. La
lista contigua es una estructura intermedia entre las estáticas y las dinámicas, ya
que sus datos se almacenan en la memoria del ordenador en posiciones sucesivas y
se procesan como vectores. Con esta disposición secuencial, el acceso a cualquier
elemento de la lista y la adición por los extremos de nuevos elementos es fácil,
siempre que haya espacio para ello. Para que una lista contigua pueda variar de
tamaño y por tanto, dar la impresión de que se comporta como una estructura
dinámica, hay que definir un vector dimensionado con tamaño suficiente para que
pueda contener todos los posibles elementos de la lista. Como se observará, una
lista contigua es un vector que tiene posiciones libres por delante y detrás y el
ESTRUCTURAS DE DATOS
189
índice del mismo hace de puntero. Es un caso relativamente banal de estructura
dinámica, al cual no prestaremos mayor atención.
70703" NKUVCU"GPNC\CFCU
Estas listas están formadas por un conjunto de nodos, en los que cada
elemento contiene un puntero con la posición o dirección del siguiente elemento de
la lista, es decir su enlace. Se dice entonces, que los elementos de una lista están
enlazados por medio de los campos enlaces. Cada nodo está constituido por dos
partes: información o campos de datos (uno o varios) y un puntero (con la
dirección del nodo siguiente). Al campo o campos de datos del nodo lo
designaremos como INFORMACIÓN del nodo y al puntero por SIGUIENTE del
nodo. Con esta organización de los datos, es evidente que no es necesario que los
elementos de la lista estén almacenados en posiciones físicas adyacentes para estar
relacionados entre sí, ya que el puntero indica unívocamente la posición del dato
siguiente en la lista.
Una forma alternativa de ver las listas enlazadas, es considerarlas como una
estructura que contienen un dato dado como la cabeza, y el resto como la cola. La
notación usual es la siguiente:(A | B), donde la lista tiene el elemento A en la
cabeza y el elemento B como cola. Recursivamente, (A| (B |(C D ) ) ) es la lista con
el elemento A en la cabeza, mientras que la cola está forma por una lista con el
elemento B en la cabeza y una lista que contiene los elementos C y D en la cola,
etc.
Nótese que para tener definida una lista enlazada, además de la estructura de cada
uno de sus nodos, necesitamos una variable externa a la propia lista, con un puntero
que marque la posición de la cabeza (inicio, primero) de la lista. Esta variable es
quien normalmente da nombre a la lista, pues nos dice donde localizarla, sea cual
sea su tamaño. Para detectar el último elemento de la lista se emplea un puntero
nulo, que por convenio, se suele representar de diversas formas: por un enlace con
la palabra reservada nil (NULO), por una barra inclinada (/) (Ver Figura 5.5) o por
un signo especial, tomado de la toma de tierra en electricidad. Una lista enlazada
sin ningún elemento se llama lista vacía y las distinguiremos asignando a su
puntero de cabecera el valor nil.
190
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
A
C
D
D
C
puntero o enlace al nodo 2
KPKEKQ
RTKOGTQ
A
B
informacion del nodo 1
B
C
nil
KPKEKQ
RTKOGTQ
Fig. 5.5.
Ejemplos de listas enlazadas
5.5.1.1" Creación de una lista
La implementación de una lista enlazada, depende del lenguaje de
programación, ya que no todos soportan el puntero como tipo de datos;
afortunadamente los más modernos como C, Pascal, etc., si lo hacen, por lo que en
lo que sigue vamos a asumir el uso de punteros para su manejo. La alternativa, al
uso de punteros, es recurrir a vectores paralelos en los que se almacenan los datos
correspondientes a INFORMACION y SIGUIENTE, con una variable que apunte
al índice que contiene la cabeza de la lista, de forma que nos podemos imaginar el
siguiente esquema de equivalencia, entre ambas estructuras físicas:
KPH
RTKOGTQ
8
1
UKI
KPH
UKI
KPH
UKI
KPH
UKI
2
3
4
5
6
7
8
9
10
11
12
Una vez definida la estructura de sus nodos, cosa que dejamos aparte, pues
dependerá de cada lenguaje de programación, crear una lista consiste en llenar un
primer nodo con la información correspondiente a un elemento y cuyo campo de
enlace sea NULO. Además hay que definir la variable con el puntero externo que
debe contener la dirección de este nodo inicial. Fijarse que ello supone que el
lenguaje de programación que utilicemos debe tener una función que nos de la
posición de memoria en la que se ha almacenado este nodo. A partir de este nodo
ESTRUCTURAS DE DATOS
191
inicial la lista empieza a modificarse, creciendo y disminuyendo, insertando y
borrando nodos.
5.5.1.2" Procesamiento de listas enlazadas
El objetivo de lo que sigue, no es tanto la descripción de las operaciones de
procesamiento del ejemplo más significativo de estructura dinámica, como la
comparación de éstas con las estáticas, en términos de utilidad para la
programación. Se trata por tanto solamente de dar una idea, acerca de los pros y
contras de utilizar vectores o listas enlazadas como estructuras lineales.
En esta línea, vamos ahora a ver como efectuamos, con listas enlazadas, las mismas
cuatro operaciones (recorrido, búsqueda, inserción y eliminación) que ya hemos
llevado a cabo utilizando vectores, como estructura de datos.
Vamos a utilizar las notaciones algorítmicas siguientes:
PRIMERO
P
NODO(P)
INFO(P)
SIG(P)
es un puntero externo al primer nodo de una lista enlazada;
es un puntero a un nodo cualquiera de la lista;
el nodo apuntado por P.
campo de datos del nodo apuntado por P;
campo puntero del nodo apuntado por P
(apunta al nodo siguiente).
Recorrido de una lista
Recorrer un vector fue fácil con una estructura repetitiva, al poder utilizar
su índice para poder ir del principio al final de la estructura. Sin embargo, en el
caso de las listas, al carecer de índice, puede pensarse que no es tan fácil acceder
directa o aleatoriamente a sus nodos, ya que para ello es necesario acceder al
primer nodo mediante el puntero externo, al segundo, después de acceder al
primero, etc. Afortunadamente, esto se resuelve, usando una variable puntero,
auxiliar X, que apunte en cada momento al nodo procesado, de forma que. con solo
hacer la asignación: X ← SIG(X), esto es guardar en X el campo puntero del nodo
(Ver Figura 5.6) se tiene el efecto de avanzar hacia el siguiente nodo de la lista.
192
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Fig. 5.6 Asignación X ← SIG(X)
Basándonos en lo anterior , el recorrido de una lista, es posible utilizando el
puntero temporal P. Así el siguiente algoritmo, nos permite leer la lista completa.
1.
2.
3.
4.
5.
6.
7.
inicio
P ← PRIMERO
mientras P <> nil hacer
escribir INFO(P)
P ← SIG(P)
fin_mientras
fin
El puntero P contiene el valor del primer elemento de la lista. El bucle recorre toda
la lista hasta que encuentra un nodo cuyo siguiente sea NULO, en cuyo caso se
efectuaría: (P ← NULO), que corresponde al ultimo de la lista. La línea 4 escribe
el valor de cada elemento y la línea 5 avanza el puntero P, dándole el valor del
campo SIG del nodo actual.
Ejemplo 5:
Escribir un algoritmo que recorra una lista enlazada para calcular el número de
elementos que la componen (que en principio es indeterminado):
inicio
N←0
P ← PRIMERO
mientras P <> nil hacer
N←N+1
P ← SIG(P)
fin_mientras
fin
{contador de elementos}
Búsqueda en una lista
En el caso de trabajar con un vector, la búsqueda variaba sensiblemente
según que éste estuviera o no ordenado. En el caso de una lista enlazada, la
búsqueda debe hacerse mediante un recorrido de la misma, elemento a elemento,
hasta o bien encontrar el elemento deseado o bien detectar el final de la lista,
aunque en el caso de que la lista este ordenada podemos dar por terminada la
búsqueda sin éxito, cuando en este recorrido, nos encontremos con un nodo, cuya
información es posterior al valor buscado. Veamos estos dos casos, con listas
desordenadas y ordenadas.
ESTRUCTURAS DE DATOS
193
Dada una lista enlazada cualquiera cuyo primer nodo está apuntado por PRIMERO,
el siguiente procedimiento busca un elemento t obteniendo un puntero POS que lo
apunta (si no se encuentra el elemento POS debe ser NULO).
procedimiento BusquedaDesordenada(PRIMERO, t, REF POS)
{Elemento buscado: t}
{puntero al lugar que ocupa: POS}
inicio
P ← PRIMERO
POS ← NULO
mientras P <> NULO hacer
si t= INFO [P]
entonces
POS ← P
P ← NULO
sino
P ← SIG [P]
fin-si
fin-mientras
si POS = NULO entonces escribir ´busqueda sin exito¨ {esto es opcional}
fin
En caso de que la lista está ordenada en orden ascendente, el algoritmo de
búsqueda en las condiciones arriba indicadas es el siguiente.
procedimiento BusquedaOrdenada (PRIMERO, t,REF POS)
inicio
{se supone la lista ordenada}
P ← PRIMERO
POS ← NULO
mientras P <> nulo hacer
si INFO[P] < t
entonces
P ← SIG[P]
si_no si t = INFO [P]
entonces
POS ← P
P ← NULO
fin-si
fin-si
fin-mientras
si POS = NULO entonces escribir ´búsqueda sin exito¨
fin
194
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Como podemos observar, la búsqueda en listas sin ordenar resulta muy parecida a
la que se da en el caso de vectores. Sin embargo para listas enlazadas ordenadas, al
no poder conocer el tamaño que tiene la estructura en cada momento, no podemos
explotar todas las posibilidades que nos proporcionaban los vectores ordenados con
la búsqueda binaria.
Inserción de un elemento
Insertar, al igual que borrar, consiste básicamente en modificar los
punteros de la lista. Vamos a hacer el siguiente planteamiento general: Sea una lista
enlazada en la que se desea insertar un nuevo nodo, cosa que puede hacerse bien al
principio de la lista, bien a continuación de un nodo específico. La inserción al
principio de la lista es directa (Ver Figura 5.7)
En cualquier inserción necesitamos disponer de un nodo vacío, donde depositar la
información que queremos añadir, previamente al propio proceso de inserción.
Llamaremos DISPO a una lista de nodos disponibles, para guardar el nodo antes de
ser insertado en la lista.
Veamos como se efectúa la inserción de un nodo, con la información ELEMENTO,
al principio de la lista.
Fig. 5.7.
Inserción en el primer nodo
algoritmo inserción
NUEVO ← DISPO {obtiene un nuevo nodo si es posible; si no, da NULO}
si NUEVO = NULO
{comprobación de desbordamiento}
entonces
escribir “desbordamiento”
sino
INFO(NUEVO) ← ELEMENTO
{Colocamos en el campo INFORMACIÓN del nuevo nodo los
datos}
SIG(NUEVO) ← PRIMERO
ESTRUCTURAS DE DATOS
195
{El puntero del nuevo nodo apunta a la cabeza de la lista original}
PRIMERO ← NUEVO
{El nuevo nodo es ahora la nueva cabeza de la lista}
fin_si
fin
La inserción de un nuevo nodo (cuya información llamaremos NOMBRE) a
continuación de un nodo dado apuntado por P, exige la utilización de un puntero
auxiliar Q, aparte de los ya utilizados P y NUEVO. Veamos su algoritmo (Ver
Figura 5.8) asumiendo que habrá disponibilidad de nodo (no hay desbordamiento)
con la misma nomenclatura que en la Figura 5.7.:
1.
2.
3.
4.
5.
NUEVO ← DISPO
INFO(NUEVO) ← NOMBRE
Q ← SIG(P)
SIG(P) ← NUEVO
SIG(NUEVO) ← Q
Después de los pasos 1 y 2, tendremos la estructura mostrada en la Figura 5.8 (a).
Fig. 5.8 (a)
Tras los pasos 3 y 4, se tiene la estructura mostrada en la Figura 5.8 (b)
196
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Fig. 5.8 (b)
Finalmente tras la ejecución de la última instrucción, la situación será la mostrada
en la Figura 5.8 (c)
Fig. 5.8 (c)
Nótese que el puntero Q puede evitarse ya que los pasos 3, 4 y 5 son reemplazables
por:
SIG (NUEVO) ← SIG (P)
SIG (P) ← NUEVO
Sin embargo, recurrir a Q nos será útil durante el posible proceso de búsqueda del
nodo a partir del cual insertar.
Eliminación de un elemento de una lista enlazada
Esta operación consiste en hacer que el nodo anterior, al nodo que quiere
eliminarse, se enlace con el posterior a éste, con lo cual el nodo que nos interesa
quedará fuera de la lista. Consideremos la lista enlazada de la Figura 5.9(a). El
algoritmo que sigue elimina de la lista enlazada el elemento siguiente al apuntado
por P, utilizando un puntero auxiliar Q:
ESTRUCTURAS DE DATOS
197
Fig. 5.9 (a) Lista donde se desea eliminar el elemento apuntado por SIG(P)
1.
2.
3.
Q ← SIG(P)
SIG(P) ← SIG(Q)
LIBERARNODO(Q)
Tras cada uno de estos tres pasos, la lista sufre los siguientes pasos:
Fig. 5.9 (b) Situación tras el paso 1
Fig. 5.9 (c) Situación tras el paso 2
Fig. 5.9 (d) Situación tras el paso 3
Notemos que a su vez, el proceso de borrado dará lugar a la existencia de
nodos libres o disponibles, al liberar el nodo que se elimina; este espacio de
memoria podrá ser utilizado al invocar DISPO.
70704" XGEVQTGU"xu"NKUVCU"GPNC\CFCU
El uso de estructuras lineales en programación, es constante, por lo que la
decisión entre la utilización de vectores o listas enlazadas, en el caso de que el
lenguaje de programación que utilicemos las soporte, es una constante disyuntiva.
No podemos dar ninguna regla al respecto, ya que será cada aplicación la que
198
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
aconsejará una u otra opción. Solamente podemos hacer algunas consideraciones a
la luz de lo que hemos aprendido hasta ahora, en este capítulo.
Comparando los procesos de inserción y borrado en listas enlazadas con los
correspondientes a los que vimos en vectores, resulta bastante evidente que el
número de operaciones necesarias es mucho menor en las listas. Por tanto, para
aquellas aplicaciones en las que la inserción y el borrado juegan un papel
significativo, hay que considerar seriamente la utilización de listas enlazadas, al
objeto de mejorar la eficiencia y rapidez del procedimiento. Esta situación, como
vimos, no se repite si consideramos el proceso de búsqueda, en cuyo caso los
algoritmos para vectores ordenados son mucho más eficaces. Evidentemente, si
necesitamos hacer frecuentemente estas tres operaciones, la solución acabará
siendo un compromiso, entre las dos opciones. Más adelante propondremos una
nueva estructura, no lineal, que será razonablemente aceptable, cuando las tres
operaciones búsqueda, inserción y borrado sean igualmente frecuentes.
70705" RKNCU
Para introducir esta estructura, recordemos la forma en que se apilan los
platos en los restaurantes: una pila de platos se soporta sobre un muelle, cuando se
retira un plato, los demás suben. Vamos a trasladar esta idea a la informática. Una
pila (stack) es una estructura lineal a cuyos datos sólo se puede acceder por un
solo extremo, denominado tope o cima (top). En esta estructura sólo se pueden
efectuar dos operaciones: añadir y eliminar un elemento, acciones que se conocen
por meter (push), y sacar (pop). Si se meten varios elementos en la pila y después
se sacan de ésta, el último elemento en entrar será el primero en salir. Por esta
razón se dice que la pila es una estructura en la que el último en entrar es el
primero en salir, en inglés, LIFO (last in first out).
Cuando se almacena una pila en la memoria de un ordenador, los elementos
realmente no se mueven arriba y abajo, a medida que se meten o sacan de la pila.
Simplemente es la posición del tope de la pila la que varía. Un puntero,
denominado, puntero de pila, indica la posición del tope o, lo que es lo mismo, el
primer elemento disponible en la cima. Otro puntero se emplea para determinar la
base de la pila que mantiene el mismo valor mientras existe la pila. La Figura 5.10
muestra el uso del puntero de la pila y la base de ésta. Si se realiza la secuencia de
operaciones: sacar, sacar y meter 5.9, el estado resultante de la pila aparece en la
Figura 5.11. Para representar una pila vacía, el puntero de la pila tiene el mismo
valor que la base de la pila.
ESTRUCTURAS DE DATOS
Fig. 5.10
Pila
199
Fig. 5.11. Estado de la pila de la
Fig. 5.10 tras las operaciones:
sacar, sacar, meter 5.9
La pila es una de las estructuras más importantes en computación, se usa para
calcular expresiones, para pasar de un lenguaje de ordenador a otro y para transferir
el control de una parte de un programa a otra. Como ejemplo de uso de la pila,
considérese un programa que llama a la función raíz cuadrada de un número. El
subprograma recibe el argumento cuya raíz ha de calcularse y retorna la raíz ya
calculada. Este argumento se saca de la pila para utilizarlo y una vez calculada la
raíz, cuando la función termina, mete el resultado en la pila. El último dato entrado,
argumento, es el primer dato sacado e igual ocurre con el resultado de la función
que es el primer dato utilizado, cuando el control retorna al programa.
5.5.3.1" Procesamiento de una pila
Para trabajar con pilas, hay que contar con procedimientos para meter y sacar
elementos y para comprobar si la pila está vacía (puede utilizarse una variable o
función booleana VACIA, de modo que cuando su valor sea verdadero la pila está
vacía, y falso en caso contrario).
Las pilas pueden implementarse utilizando memoria estática (por medio de
vectores) o dinámica (utilizando punteros). Vamos a estudiar la implementación de
una pila utilizando un vector S, de tamaño LONGMAX, dejando al lector la
implementación dinámico de una pila como caso particular de lista enlazada.
Utilizaremos las siguientes notaciones:
p = CIMA
LONGMAX
S(i)
X
VACIA
puntero de la pila
longitud máxima de la pila
elemento i-ésimo de la pila S
elemento a añadir/quitar de la pila
función booleana “pila vacía”
200
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
PUSH
POP
subprograma para añadir o meter elementos
subprograma para eliminar o sacar elementos
Veamos cuál es el algoritmo de los procedimientos PUSH, POP y de la función
booleana VACIA
Meter el dato x en la pila (push):
inicio
si p = LONGMAX
entonces
escribir ‘pila llena’
sino
p←p+1
S(p) ← x
fin_si
fin
Sacar un dato de la pila (pop) y ponerlo en x:
inicio
{este subprograma pone el valor de x en la cima de la pila}
si p = 0
entonces
escribir ‘pila vacía’
sino
x ← S(p)
p←p-1
fin_si
fin
Función Pila vacía (vacía)
inicio
si p = 0
entonces
VACIA ← cierto
sino
VACIA ← falso
fin_si
fin
ESTRUCTURAS DE DATOS
201
70706" EQNCU
A pesar de los orígenes no europeos de muchas de las ideas asociadas con los
ordenadores, esa importante institución británica, la cola, ha encontrado su lugar en
las ciencias de la computación. Todo el mundo sabe como funciona una cola, los
recién llegados se sitúan al final, mientras que la desaparición se hace por el
principio, sin que esté permitido “colarse”. Vamos a definir cola, como una
estructura lineal, en la que los datos entran por la parte de atrás y salen por la de
delante. Una cola es una estructura en la que el primer dato en entrar es el primer
dato en salir, es decir, una estructura FIFO (first in, first out).
Hay varias formas de implementar una cola en la memoria de un ordenador, bien
con vectores, bien en listas enlazadas. En cualquier caso se necesitan dos variables
que representan a los punteros FRENTE (f = front) y FINAL (r = rear). El estado
de COLA VACIA se manifiesta cuando f y r son ambas nulos en la
implementación dinámica o cuando coinciden en el caso estático.
100
264
119
frente
[1]
final
(a)
[3]
[4]
100 264 119
48
frente
48
[2]
final
(b)
Fig.5.12
Ejemplos de Implementación de una cola:
a) con una lista enlazada. b) con un vector
Las colas se utilizan algo menos que las pilas, por lo que no insistiremos en las
operaciones que facilitan su procesamiento. Sin embargo digamos que facilitan la
interconexión y el almacenamiento de datos en tránsito tanto en redes de
ordenadores, como entre un procesador y un periférico (así por ejemplo, en los
trabajos para imprimir, decimos que están en cola de impresión, por orden de
llegada).
202
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Como se puede observar, la cola puede considerarse en la implementación
dinámica como un caso particular de lista enlazada. Se deja al lector la escritura de
los algoritmos de inserción y borrado de un elemento y la comprobación de cola
vacía, tanto en el caso estático como en el dinámico.
7080" GUVTWEVWTCU"PQ"NKPGCNGU"*ıTDQNGU+
Existen en Informática varias estructuras no lineales, en las que un elemento puede
estar relacionado con más de uno sea por delante o detrás de él (por ejemplo, los
grafos); no obstante, dentro del carácter introductorio de este curso, nosotros nos
restringiremos a la más sencilla de ellas, la de árbol.
A todos nos son familiares expresiones como “árbol genealógico” o “recorrer un
árbol”. En este sentido, un árbol es una estructura que implica una jerarquía, en la
que cada elemento está unido a otros por debajo de él. Comparada con las
estructuras lineales anteriores, el árbol tiene la particularidad de que cada elemento
puede tener más de un “siguiente”, aunque un solo antecedente o padre.
Definiremos árbol, de forma recursiva, como un conjunto finito de uno o más
nodos, de tal manera, que exista un nodo especial denominado raíz y los nodos
restantes están divididos en conjuntos denominados subárboles, que también
responden a la estructura de un árbol. Por extensión a la idea de árbol genealógico
se habla de nodos padres y nodos hijo y un nodo, en la parte inferior del que no
cuelgue ningún subárbol (no tiene ningún hijo) se denomina nodo terminal u hoja
(véase Figura 5.13).
raíz
nodo
nodo
nodo
nodo
nodo terminal
hoja
nodo
nodo
subárbol
Fig. 5.13.
Conceptos relacionados con los árboles
ESTRUCTURAS DE DATOS
203
70803" ıTDQNGU"DKPCTKQU
Hay un tipo especial de árbol muy usado en computación, denominado árbol
binario, en el que de cada nodo pueden colgar, a lo más, dos subárboles. Estos se
denominan subárbol derecho y subárbol izquierdo, y también son árboles
binarios. La Figura 5.14 representa un árbol binario.
nodo
nodo
nodo
nodo
nodo
nodo
nodo
Fig. 5.14.
Un árbol binario
La forma usual de representar los árboles supone el uso de punteros, aunque
también se puede hacer con vectores. En un árbol binario cada nodo está
constituido por una parte de datos (INFORMACION) y dos punteros que indican la
posición de sus hijos. Uno o ambos de los punteros pueden tener un valor nulo si
del nodo no cuelgan subárboles. Cada nodo de un árbol será un registro que
contiene al menos tres campos:
- un campo INFORMACION de datos de un cierto tipo.
- un puntero al nodo del subárbol izquierdo (que puede ser nulo).
- un puntero al nodo del subárbol derecho (que puede ser nulo).
La Figura 5.15 ilustra el uso de los punteros para construir el mismo árbol
representado en la Figura 5.14. Nótese cómo los punteros de los nodos terminales
son punteros nulos.
204
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
dato
puntero izdo.
puntero dcho.
dato
puntero izdo.
puntero dcho.
dato
puntero izdo.
puntero dcho.
dato
puntero izdo.
puntero dcho.
dato
puntero izdo.
puntero dcho.
dato
puntero izdo.
puntero dcho.
dato
puntero izdo.
puntero dcho.
Fig. 5.15.
Punteros empleados para construir un árbol binario
5.6.1.1" Recorrido de un árbol binario
Recorrer un árbol supone acceder a sus elementos de forma sistemática lo que
supone llevar a cabo tres actividades:
1.
2.
3.
Visitar el nodo raíz
Recorrer el subárbol izquierdo
Recorrer el subárbol derecho
Estas tres acciones repartidas en diferentes órdenes proporcionan diferentes
recorridos del árbol, llamados: pre-orden, post-orden, in-orden. Su nombre
refleja el momento en que se visita el nodo raíz. En el “in-orden” el raíz está en el
medio del recorrido, en el “pre-orden”, el raíz está el primero y en el “post-orden”,
el raíz está el último:
Recorrido pre-orden
1.
2.
3.
Visitar el raíz
Recorrer el subárbol izquierdo en pre-orden
Recorrer el subárbol derecho en pre-orden
Recorrido in-orden
1.
2.
3.
Recorrer el subárbol izquierdo en in-orden
Visitar el raíz
Recorrer el subárbol derecho en in-orden
ESTRUCTURAS DE DATOS
205
Recorrido post-orden
1.
2.
3.
Recorrer el subárbol izquierdo en post-orden
Recorrer el subárbol derecho en post-orden
Visitar el raíz
Obsérvese que todas estas definiciones de recorrido tienen naturaleza
recursiva.
Ejemplo 6:
Determinar cual sería el resultado de los tres posibles recorridos para cada uno de
los tres árboles mostrados en la Figura 5.16
Fig. 5.16
Recorrido de árboles binarios
Árbol 1
Pre-orden
In-orden
Post-orden
+ * cde
c*d+e
cd * e +
Árbol 2
Pre-orden
In-orden
Post-orden
/ + * + ab / cd ↑ efg
a + b * c/d + e ↑ f/g
ab + cd/*ef ↑ + g
Árbol 3
Pre-orden
In-orden
Post-orden
mebadlpnvtz
abdelmnptvz
adblentzvpm
La característica esencial de los árboles es que cada uno de sus nodos puede estar
conectado a subárboles, que a su vez tiene estructura arbórea. En otras palabras,
siempre que se está en un árbol, la estructura inferior tiene carácter de árbol. En
206
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
este sentido un árbol es una estructura de datos recursiva, que puede manipularse
mediante programas recursivos. Esta propiedad de los árboles es la que los hace
más interesantes desde un punto de vista informático y por ello se utilizan
ampliamente, como por ejemplo: los módulos de muchos programas se enlazan
como si de árboles se tratara, la estructura que emplean muchos sistemas operativos
para manejar los ficheros son árboles, algunos ordenadores se refieren a su
memoria como si ésta estuviera fragmentada en forma de árbol; asimismo
acabamos de ver cómo los árboles se usan para representar operaciones aritméticas.
70804" ıTDQN"DKPCTKQ"FG"DðUSWGFC
Ya hemos hecho notar que una de las aplicaciones que se dan más frecuentemente
en informática, es la de manejar una colección de datos sobre los cuales se efectúan
de forma constante operaciones de búsqueda inserción y borrado (pensemos por
ejemplo en el trabajo habitual de un servicio de reserva en una agencia de viajes).
A lo largo de este capítulo hemos visto que cada una de estas tres operaciones
elementales se resuelven de forma distinta, según la estructura elegida para
organizar esta colección de datos sea un vector o una lista enlazada. Sabemos que
la inserción y el borrado se mejoran sensiblemente, si elegimos una lista en vez de
un vector, por el contrario, para la búsqueda parece claramente preferible trabajar
con un vector ordenado. Para superar esta situación, vamos a describir una variante
del árbol binario con la que podemos localizar, insertar y borrar con mayor
eficacia. Ello nos dará una nueva posibilidad a la hora de programar, al poder
seleccionar nuevas estructuras, que nos permitan utilizar nuevos y mejores
algoritmos.
Llamaremos árbol binario de búsqueda a un árbol binario construido de acuerdo
con el procedimiento siguiente:
1.
2.
3.
El primer elemento se utiliza para crear el nodo raíz.
Los valores del árbol deben ser tales que pueda existir un orden (entero, real,
lógico o carácter e incluso definido por el usuario si se tiene un orden total
con él).
En cualquier nodo, todos los valores del subárbol izquierdo del nodo son
menores o iguales que el valor del nodo. De modo similar todos los valores
del subárbol derecho deben ser mayores que los valores del nodo.
Para este tipo de árbol, es sencillo probar que su recorrido “in-orden” obtiene los
valores debidamente ordenados, lo que nos será de gran utilidad. Así, por ejemplo,
en la Figura 5.17 se muestra un árbol binario de búsqueda.
ESTRUCTURAS DE DATOS
Fig. 5.17
207
Árbol binario de búsqueda
El recorrido in-orden del árbol de la figura 5.17 es: B F G H P R S T W Y
Z. Ello nos permitirá almacenar y procesar un conjunto ordenado, con bastante
facilidad, sin que tengamos que proceder a largas operaciones de readaptación. El
paso de un conjunto cualquiera a un árbol binario de búsqueda es afortunadamente
fácil, como muestra el ejemplo siguiente:
Ejemplo 7:
Supongamos que se dispone de un vector que contiene los siguiente caracteres:
D F E B A C G
para expresarlo mediante un árbol binario de búsqueda, vamos a seguir el
algoritmo:
1.
Nodo raíz del árbol: D.
2.
El siguiente elemento se convierte en el descendente derecho, dado que F
alfabéticamente es mayor que D.
3.
A continuación, se compara E con el raíz. Dado que E es mayor que D, pasará
a ser un hijo de F y como E < F será el hijo izquierdo.
4.
El siguiente elemento B se compara con el raíz D y como B<D y es el primer
elemento que cumple esta condición, B será el hijo izquierdo de D.
5.
Se repiten los pasos hasta el último elemento.
El árbol binario de búsqueda resultante sería:
208
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Nótese que en caso de que el vector estuviese previamente ordenado (ascendente o
descendentemente) el árbol de búsqueda que obtendríamos sería en realidad una
lista.
Una vez definida esta nueva estructura tratemos de constatar su utilidad, cuando
nos enfrentamos a esta hipotética aplicación, en la que las tres operaciones de
búsqueda, inserción y borrado son muy frecuentes. Por motivos de espacio, no
vamos a bajar hasta la especificación completa de los algoritmos correspondientes
a cada una de estas tres operaciones, sólo presentaremos un esbozo del diseño
correspondiente.
Búsqueda de un elemento
La búsqueda en un árbol binario ordenado es dicotómica, ya que a cada
examen de un nodo, se elimina aquel de los subárboles que no contiene el valor
buscado (valores todos inferiores o todos superiores).
El algoritmo de búsqueda del elemento -llamado clave - se realiza comparándolo
con la raíz del árbol. Si no es el mismo, se pasa el subárbol izquierdo o derecho
según sea el resultado de la comparación y se repite la búsqueda en ese subárbol,
de forma recursiva.
La terminación del procedimiento se producirá cuando:
- se encuentra la clave
- no se encuentra la clave; y se llega a encontrar un subárbol vacío.
Así por ejemplo, si buscamos “W” en el árbol de la figura 5.17, se visitarán los
nodos “P”, “S”, “W”. Si, en el mismo árbol, buscamos “X”, se visitarán los nodos
“P”, “S”, “W”, “Z”, “Y” y se alcanza un subárbol vacío bajo la “Y” sin encontrar la
clave.
Insertar un elemento
ESTRUCTURAS DE DATOS
209
Para insertar un elemento en un árbol hay que comprobar en primer lugar
que áquel no se encuentre ya en el árbol, dado que en este caso no precisa ser
insertado (de hecho ésta es una comprobación que también deberíamos hacer
trabajando con vectores o listas enlazadas, lo que supone que cada inserción se
acompaña, en cierta manera, de un proceso de búsqueda). Si el elemento no existe,
la inserción se realiza en un nodo en el que al menos uno de los dos punteros IZQ o
DER tenga valor nil, con lo cual el nuevo elemento de inserta como una nueva hoja
del árbol, sea cual sea su valor (Ver Figura 5.18).
La inserción no varía mucho del propio proceso de búsqueda, pues realmente
vamos a insertar el nodo en la posición que ésta ocuparía, si ya se encontrara en el
árbol. Para ello, se desciende en el árbol a partir del nodo raíz, dirigiéndose de
izquierda a derecha de un nodo, según que el valor a insertar sea inferior o superior
al valor del campo INFO de este nodo. Cuando se alcanza un nodo del árbol en que
no se puede continuar, el nuevo elemento se engancha a la izquierda o derecha de
este nodo, en función de que su valor sea inferior o superior al del nodo alcanzado.
Fig. 5.18 Ejemplo de Inserciones en un árbol de búsqueda binaria: (a), insertar
100; (b), insertar (o); (c), insertar 22 y 12.
Eliminación de un elemento
La eliminación de un elemento debe hacerse conservando el orden de los
elementos del árbol. Se consideran diferentes casos según la posición del elemento
o nodo en el árbol a eliminar:
- si el elemento es una hoja, se suprime simplemente;
210
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
- si el elemento no tiene más que un descendiente, se sustituye entonces por ese
descendiente (ver Figura 5.19);
- si el elemento tiene dos descendientes, la situación es un poco más complicada
ya que la simple sustitución de un nodo por uno de sus hijos conllevaría la
pérdida de estructura de árbol binario. En este caso el nodo a eliminar se debe
sustituir por un descendiente más a la derecha o a la izquierda, de modo que
siga conservando la ordenación (ver Figura 5.20).
Fig. 5.19
Ejemplo de Eliminación de un nodo (49) con un solo subárbol
a) antes de la eliminación b) después de la eliminación
Para poder realizar estas acciones, será preciso conocer la siguiente información
del nodo a eliminar:
- Su posición en el árbol;
- La dirección de su padre;
- La dirección relativa a su ascendencia, es decir si el nodo a eliminar es
un hijo derecho o izquierdo.
ESTRUCTURAS DE DATOS
211
Fig. 5.20:Ejemplo de eliminación de un nodo (27) con dos subárboles no nulos. Se
ha sustituido por el elemento 42 que es un nodo sucesor siguiente en orden ascendente.
Los algoritmos correspondientes no son difíciles aunque su detalle cae fuera de la
óptica de este capítulo y se dejan como ejercicio para el lector.
5.1. EL CONCEPTO DE DATOS ESTRUCTURADOS. ................................171
5.2. TIPOS DE DATOS ESTRUCTURADOS ..................................................172
5.3. ESTRUCTURAS DE DATOS CONTIGUAS............................................173
5.3.1 CADENAS ......................................................................................................173
5.3.2 ARRAYS ........................................................................................................175
5.3.3 REGISTROS ...................................................................................................186
5.4. ESTRUCTURAS DINÁMICAS Y PUNTEROS .......................................187
5.5. ESTRUCTURAS LINEALES .....................................................................188
5.5.1 LISTAS ENLAZADAS ...............................................................................189
5.5.2 VECTORES VS LISTAS ENLAZADAS.....................................................197
5.5.3 PILAS...........................................................................................................198
5.5.4 COLAS.........................................................................................................201
5.6. ESTRUCTURAS NO LINEALES (ÁRBOLES) .......................................202
5.6.1 ÁRBOLES BINARIOS................................................................................203
5.6.2 ÁRBOL BINARIO DE BÚSQUEDA..........................................................206
CAPÍTULO 6
ARCHIVOS Y BASES DE DATOS
Como ya sabemos, para que una computadora sea realmente útil, necesita
procedimientos y dispositivos que permitan almacenar los datos que no está
procesando en un momento dado, pero que puede necesitar con posterioridad. Igual
consideración merecen los programas, ya que los vamos a utilizar multitud de
veces; el hecho de que una secuencia de instrucciones pueda ser almacenada de
forma permanente y utilizada con posterioridad es la base de la existencia de la
industria del software.
En el capítulo anterior discutimos varias formas de organizar los datos dentro de un
programa y cómo estas estructuras se estructuran dentro de la memoria principal.
Ahora nos centraremos en las formas de organización que utilizan los sistemas
operativos para el almacenamiento de datos y programas en los dispositivos de
memoria masiva, así como la forma como podemos acceder a ellos por medio de
un lenguaje de programación. A lo largo de este capítulo haremos abstracción de
las características físicas de los dispositivos de almacenamiento secundario, cuya
descripción dejamos para el correspondiente capítulo dedicado al soporte físico del
computador.
8030" CTEJKXQU<"FGHKPKEKQPGU"["EQPEGRVQU
El concepto de archivo, aparece no sólo como forma de utilización de
información presente en un medio de almacenamiento permanente, sino además,
éstos permiten superar las limitaciones impuestas por el tamaño de la memoria
principal a la hora de manipular grandes volúmenes de datos. Dada la ingente
cantidad de datos que puede manejar un computador en la actualidad, el uso de los
dispositivos de almacenamiento como memoria secundaria permite que la cantidad
de datos que puede tratar un programa no esté limitada por el tamaño de la
memoria principal. La propia aparición de la memoria virtual (capacidad de un
procesador de acceder a un medio de almacenamiento masivo, tal como un disco
duro, y manejarlo como si fuera memoria principal) deriva de esta misma idea, en
el sentido de que una parte del dispositivo de almacenamiento es usado como una
ampliación de la memoria principal.
213
214
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Los datos que se encuentran en memoria masiva suelen organizarse en archivos, y
por tanto entenderemos como archivo o fichero a un conjunto de informaciones
sobre un mismo tema tratado como una unidad de almacenamiento y organizado
de forma estructurada para la búsqueda de un dato individual. Como ya hemos
dicho, los archivos pueden contener instrucciones de programas o información
creada o usada por un programa.
Como tal, un archivo no es más que una agrupación de datos, cuya estructura
interna es la que el usuario, el programador o el sistema operativo, le haya
conferido implícitamente (la organización del fichero no es intrínseca a la
existencia del mismo). En este punto debe aclararse que los archivos son
independientes de los programas y de hecho, un mismo archivo creado por un
programa puede ser usado por otros. El único requisito para obtener información de
un archivo cualquiera es conocer como se han organizado los datos en el mismo,
pues de lo contrario el resultado es una colección de bytes aparentemente sin
sentido. Lo anterior pone de manifiesto que el fichero no contiene información
explícita sobre su organización y por tanto esto tiene que ser tenido en cuenta al
procesarlos.
Las estructuras con que se organizan los archivos no son inmanentes a los mismos
ni son propias del sistema operativo, por lo que debe ser el software el responsable
del mantenimiento de dichas estructuras. En ocasiones tendremos a nuestra
disposición programas específicos llamados sistemas de gestión de archivos que
permiten diseñar archivos con determinadas estructuras y realizar recuperaciones y
actualizaciones eficazmente para dichas estructuras. Los programas que los utilicen
pueden abstraerse del mantenimiento de las estructuras, delegando esta labor en el
sistema de gestión de archivos.
Sin embargo una simple colección de ficheros no organiza óptimamente la
totalidad de informaciones que pretendemos gestionar, ya que existen relaciones
entre los distintos datos presentes en los diversos ficheros, que además deben estar
disponibles para distintas aplicaciones. Por ello a toda colección de ficheros a las
que pueda accederse por un conjunto de programas y que contienen todos ellos
datos relacionados entre sí la llamaremos base de datos.
Acabamos de indicar cómo se pueden organizar los conjuntos de archivos, veamos
ahora como se organiza un archivo internamente. La concepción clásica por la cual
un fichero es un conjunto de informaciones estructuradas en unidades que en el
capítulo anterior denominamos registros viene heredada de los sistemas manuales
de tratamiento de la información y por tanto muchas de las ideas y de los términos
que se usan en este campo derivan de la terminología empleada con los ficheros
manuales. Según aquellos, tanto si los ficheros se almacenan en un archivador, en
un disco magnético o en otro medio de almacenamiento, un fichero o archivo es
una colección ordenada de datos, cuya unidad elemental que lo compone es el
ARCHIVOS Y BASES DE DATOS
215
registro. Un registro se corresponde con una ficha, o con una hoja de papel en un
fichero manual, siendo una colección de información, normalmente relativa a una
entidad particular, (p.e. información acerca de un estudiante) puede contener varios
datos y cada registro de un mismo fichero tiene, en general, la misma estructura
que los demás. Los datos individuales ocupan campos dentro de los registros. Un
campo puede tener una longitud fija o variable, normalmente representa un ítem o
elemento de datos elementales (Ver Figura 6.1). Los registros que componen un
archivo pueden tener longitud fija o variable; en los segundos, debe existir alguna
manera de indicar la longitud del registro, bien mediante un campo que lo indique,
bien mediante un carácter especial que indique el final de un registro. El término
longitud del campo hace referencia al tamaño máximo de dicho campo. Los
campos pueden ser de diferente tipo: numérico, cadena, moneda, fecha o código,
etc., ...
Campo1
Campo2
Campo3
Campo4
Campo5
Campo6
Campo7
Campo8
nombre
pasajero
NOMBRE
NUMERO DE VUELO
FECHA DE VUELO
NUMERO DE ASIENTO
FUMADOR
CIUDAD ORIGEN
CIUDAD DESTINO
PRECIO
número
vuelo
fecha
vuelo
Fig. 6.1.
número
asiento
tipo cadena (alfanumérico)
tipo cadena (alfanumérico)
tipo cadena (alfanumérico)
tipo entero
tipo lógico
tipo cadena (alfanumérico)
tipo cadena (alfanumérico)
tipo real
fumador
ciudad
origen
ciudad
destino
precio
Ejemplo de campos de un registro
La forma más común de identificar un registro es eligiendo un campo dentro del
registro que llamaremos clave del registro. La localización de un registro se hace a
través de los valores que tiene el campo clave, siendo a veces necesario utilizar
varias claves bien por existir valores iguales de la clave en distintos registros, bien
por estar interesados en buscar los registros por distintos campos (p.e. por nombre
y por número de asiento en el ejemplo de la figura 6.1). Por esta razón se permite
utilizar más de un campo como clave de un registro. En este caso los campos se
denominan clave primaria, clave secundaria, etc.
Aclaremos que esta concepción de archivo no engloba todos los tipos de archivos
existentes. No obstante esta concepción es útil, como estructura de datos, para
organizar grandes volúmenes de datos en memoria masiva, donde los datos deben
disponerse de un modo sistemático que facilite las operaciones más comunes sobre
216
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
los ficheros, en particular la de búsqueda. Los conceptos de carácter, campo,
registro, archivo y base de datos son conceptos lógicos que se refieren a la forma
como el usuario ve los datos y su organización
8040" UQRQTVG"["CEEGUQ"C"NQU"CTEJKXQU
Un archivo, dependiendo principalmente del uso o capacidad que vaya a
tener, puede estructurarse en un soporte (disco o cinta) de distintas formas. De
hecho al hablar de archivos hay que retener que conviven dos visiones de los
mismos, por un lado existe un sistema físico, más o menos complejo, donde
realmente se almacenan los datos y por otro una visión lógica adecuada al usuario,
que trabaja, sin preocuparse excesivamente sobre las características físicas de este
almacenamiento. El sistema operativo permite que el usuario pueda utilizar
solamente ésta última, haciendo de interfaz entre ambas (ver figura 6.2).
PROGRAMA
buffer
solicitud
SISTEMA
OPERATIVO
nivel lógico
nivel físico
datos
DISCO
(soporte)
Fig. 6.2.
solicitud
Acceso a los archivos
En efecto, desde el punto de vista hardware, para almacenar datos o programas en
la memoria masiva sólo existen direcciones físicas. Por ejemplo, en un disco toda
información se graba o lee en forma de bloques (sectores) referenciados por
(número de unidad)/(superficie)/(pista)/(sector). El sistema operativo posibilita que
el usuario no tenga que utilizar direcciones físicas, realizando la transformación de
la dirección lógica de un dato en el archivo (posición relativa de un dato dentro del
mismo) a la dirección física (en qué punto concreto del soporte se encuentra el
dato) y efectuando los accesos necesarios al dispositivo donde se encuentra el
archivo para transferir la información del archivo al programa o a la inversa.
El tiempo que se tarda en acceder a una determinada información almacenada en
memoria masiva (y por tanto contenida en un soporte magnético) es variable,
ARCHIVOS Y BASES DE DATOS
217
dependiendo, entre otras cosas, del lugar previo donde se ha accedido a la última
información. Cuando el acceso a las informaciones de un archivo se produce en un
orden determinado y fijo se conoce como acceso secuencial; el acceso a los
bloques de datos se hace de forma sucesiva, uno tras otro., tal como se reproducen
las canciones grabadas en una cinta. Cuando el acceso a determinada información
contenida en el archivo puede hacerse sin acceder a las informaciones anteriores o
posteriores se dice que se trata de un acceso directo, como ocurre al querer
acceder a una determinada canción grabada en un disco.
Los soportes de memoria secundaria se clasifican según el modo de acceso que
permiten en soportes secuenciales y soportes direccionables. Un soporte
secuencial (o no direccionable) únicamente permite el acceso secuencial, es decir,
el acceso a un bloque concreto del mismo requiere leer o pasar los bloques
anteriores a aquél; es el caso de las cintas magnéticas. Los soportes direccionables
o aleatorios permiten tanto el acceso directo como el secuencial: se puede acceder a
un bloque físico sin más que dar su posición, sin necesidad de recorrer o leer otros
bloques, aunque también puede hacerse de esa manera. Los discos magnéticos son
ejemplo de soportes direccionables.
En los primeros tiempos de la informática la estructura de los ficheros estaba
determinada en gran medida por los medios de almacenamiento disponibles. Hoy
día la situación se ha invertido. La naturaleza de la aplicaciones determina la
estructura de los ficheros, que es la que define los medios de almacenamiento que
hay que utilizar. Obviamente los soportes secuenciales presentan limitaciones
respecto a los direccionables, pero también su coste es mucho menor que el de
éstos, aunque esta es una estimación que quizás tenga que revisarse en un futuro no
muy lejano. La elección de uno u otro soporte dependerá del uso que se vaya a dar
a la información que deban contener. No obstante, la tendencia actual presenta un
uso ampliamente mayoritario de los soportes direccionables como dispositivos de
memoria secundaria, mientras los soportes secuenciales quedan como medio de
almacenamiento para copias de seguridad.
En el resto del capítulo trataremos los archivos desde el punto de vista lógico del
programador y de su uso como memoria secundaria, ciñéndonos a estructuras
típicamente asociadas a los soportes direccionables (los discos), obviando, por
tanto, los detalles físicos subyacentes.
8050" GN"UKUVGOC"QRGTCVKXQ"["NC"IGUVKłP"FG"CTEJKXQU
Sobre la estructura de periféricos de almacenamiento disponibles en el
ordenador, el sistema operativo construye dos abstracciones. La primera es la
creación de archivos, ello aislará al usuario de los problemas físicos de
almacenamiento. Así, cuando deseemos referirnos a un conjunto de información
del mismo tipo, como una unidad de almacenamiento única, bastará con crear un
218
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
archivo dándole el nombre que considere oportuno. La segunda abstracción es lo
que se denomina directorio. Los directorios son conjuntos de archivos agrupados
de acuerdo con un libre criterio (teniendo en cuenta los usuarios que lo han creado,
o el contenido de los archivos, etc.). El sistema operativo crea y mantiene por cada
directorio un índice con los nombres de los archivos que éste contiene, así como
información sobre cada uno de ellos, tal como espacio que ocupa, tipo, fecha y
hora en que por última vez se ha escrito sobre él, dirección física donde se
encuentra, etc. De este modo la estructura global del sistema de archivos es un
árbol en el que los nodos internos (los que constituyen la raíz de un subárbol) son
directorios y los nodos hoja son archivos.
Sobre estas estructuras de datos, el sistema operativo permite al usuario realizar,
entre otras, las siguientes funciones:
- creación de archivo o directorio.
- borrado de archivo o directorio.
- listar el índice de un directorio.
- copiar de archivo o directorio.
Al ser estas funciones propias del sistema operativo y en general los lenguajes de
programación han sido diseñados para que los programas no tengan que realizar
directamente ninguna de estas operaciones, ya que basta con invocar al sistema
operativo para que las lleve a cabo cuando sean necesarias.
8060" QTICPK\CEKłP"FG"CTEJKXQU
Hay diferentes formas de estructurar u organizar los registros que
componen un archivo sobre un soporte de información. La eficiencia en la
utilización del archivo depende de la organización del mismo; por ello se debe
optar por una u otra organización atendiendo a la forma en que se va a usar el
archivo. Las principales organizaciones de archivos son:
Secuencial. Los registros se encuentran en cierto orden, yuxtapuestos
consecutivamente y por tanto han de ser leídos, necesariamente, según este orden.
En la organización secuencial los registros carecen de un orden especial, estando
situados según el orden temporal de su inclusión en el archivo; si se desea que
estén ordenados según otro criterio, el campo clave por ejemplo, debe hacerse
programándolo adecuadamente. Por lo general, en un archivo secuencial al final
del archivo físico, se graba la marca de final de fichero (end-of-file, EOF), que en
la mayoría de lenguajes se asocia a una función lógica, eof, verdadera cuando se
alcanza el final de fichero y falsa en caso contrario. Si un archivo está vacío, sólo
contiene la marca final de archivo.
ARCHIVOS Y BASES DE DATOS
219
Los archivos secuenciales son los que ocupan menos memoria y son útiles cuando
se desconoce a priori la cantidad de datos a almacenar (además se pueden utilizar
para manejar registros de longitud variable). En general, son muy empleados para
el almacenamiento de información, cuyos contenidos sufran pocas modificaciones
en el transcurso de su vida útil. Un caso especial de los archivos secuenciales son
los archivos de texto donde cada registro es simplemente un carácter o código de
control. Es decir, un archivo de texto es simplemente una secuencia de caracteres
que incluyen ciertos caracteres especiales o de control (p.e. el carácter
fin_de_línea). Una de las aplicaciones más comunes de este tipo de archivos es la
de contener documentos creados por programas como los procesadores de texto y
los editores. El código de los programas también se almacena en archivos de texto,
aunque la estructura del código sea desconocida para el sistema de archivos.
Secuencial Indexada.- En esta organización se dispone de una tabla de índices
adicional; entenderemos como índice, una referencia que permite obtener de forma
automática la ubicación de la zona del archivo físico donde se encuentra el registro
buscado. Este permite localizar un registro por medio de su clave sin recorrer
previamente todos los que le preceden. Un diccionario sería un ejemplo de archivo
secuencial indexado, ya que en cada página tenemos dos niveles, el superior que
nos dice cual es la letra inicial de la palabra y el inferior la cabecera de cada
página, de forma que en un ordenador, guardaríamos en la tabla de índices las
letras y las cabeceras, que nos dicen en que pagina ir a buscar la palabra deseada.
La organización secuencial indexada implica un mantenimiento de las tablas de
índices y una previsión inicial de la cantidad máxima de registros que va a
contener.
En general, al igual que un diccionario, cada archivo secuencial indexado consta de
dos archivos el de índices y el de datos, el primero es secuencial y contiene las
claves del último registro de cada bloque físico del archivo y la dirección de acceso
al primer registro del bloque y en el segundo, los registros de datos, clasificados en
orden ascendente por el campo clave.
Directa.- En está organización, la ubicación del registro en el soporte físico, se
obtiene directamente a partir de funciones que la obtienen a partir del valor de la
clave, mediante un algoritmo de transformación (hashing) de ésta. Un archivo para
que pueda estar dotado de una organización directa tiene que cumplir dos
condiciones: a) que sus registros sean de longitud fija y b) su propio tamaño tiene
que estar prefijado, lo que determina la distribución de la información, al tiempo
que limita la cantidad de registros que podrá contener. Conviene saber que las
funciones hash de conversión de clave a dirección, son numerosas y están basadas
en diferentes métodos, aunque su estudio supera el ámbito de este texto.
Digamos finalmente, que la organización más sencilla y más comúnmente
empleada es la secuencial , aunque no sea la más eficiente. Todos los lenguajes de
220
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
programación permiten tratar con archivos secuenciales, mientras que el
tratamiento de archivos indexados y archivos de organización directa no está
previsto en todos los lenguajes.
8070" QRGTCEKQPGU"UQDTG"CTEJKXQU
Desde el punto de vista del programador, los archivos interesan porque los
programas típicamente operan sobre ellos, para leer ó escribir en los mismos. Sin
embargo, ya hemos dicho que no debe preocuparse de los detalles del hardware
dado que la manipulación directa del archivo corresponden al sistema operativo.
Los programadores deben emplear determinados procedimientos o funciones para
comunicarle al S.O. la operación a realizar y obtener una respuesta de éste.
El sistema operativo debe mantener ciertas informaciones sobre cada fichero que
esté manipulando, tales como el soporte en que se encuentra el archivo, el tipo de
organización del mismo, el lugar donde éste empieza o la posición actual dentro de
un archivo (que indica dónde se va a producir el próximo acceso al archivo, si se
trabaja con acceso secuencial). Todo ello esta contenido en un descriptor de
fichero asociado a cada archivo que se esté utilizado en un momento determinado.
Vamos a ver los procedimientos básicos, que con la ayuda del sistema operativo,
los programas pueden llevar a cabo sobre los distintos tipos de ficheros.
80703" CRGTVWTC"["EKGTTG"FG"WP"CTEJKXQ
Para que un programa pueda operar directamente sobre un archivo, la
primera operación que debe realizar es la apertura del mismo. En la misma, el
programa emplea una subrutina identificando el archivo con el que quiere trabajar
(mediante un nombre y, según el caso, el soporte donde se encuentra) y el modo en
que va a emplearlo (este segundo aspecto varía según el lenguaje con que se
trabaje). El sistema operativo construye a partir de estas informaciones un
descriptor de fichero, de manera que el programa ya no se referirá al archivo por su
nombre (que es un identificador externo al programa), sino por un número o
variable asociado a este descriptor, que a partir de ahora será un identificador
interno del programa. Hacemos notar que el modo de apertura determina las
operaciones que se podrán realizar sobre el mismo: por ejemplo no se puede
escribir en un archivo si su descriptor de fichero ‘sabe’ que ha sido abierto para
‘sólo lectura’. Además, cuando se abre un fichero, la posición actual dentro del
archivo es el comienzo del mismo.
Cuando un programa no vaya a acceder más a un archivo, es necesario indicar al
sistema operativo esta circunstancia. Con ello el sistema operativo libera el
descriptor de fichero y se asegura que el archivo queda debidamente almacenado
en la memoria secundaria. Para cerrar un archivo simplemente se utiliza la
ARCHIVOS Y BASES DE DATOS
221
subrutina de cierre indicando el archivo por medio de su identificador interno
(número o variable).
Evidentemente, para poder utilizar un archivo, éste tiene que existir. Por ello el
fichero deberá haber sido creado en algún momento, y recordemos que la creación
de un fichero es una tarea propia del sistema operativo. Asimismo, al abrir un
fichero para su lectura, las informaciones de este archivo tienen que haber sido
almacenadas sobre un soporte y ser utilizables; un intento de lectura en un fichero
inexistente produce indefectiblemente un error.
La situación de escritura es diferente: si en la apertura damos el nombre de un
fichero para escribir datos en él y no existe ningún fichero con ese nombre, en
muchos lenguajes ello significará que el sistema operativo lo creará de modo
automático (en caso contrario lo habrá hecho el programador previamente). Si ya
existiera un fichero con el mismo nombre, sus contenidos serían borrados y
empezaría a escribiese desde un principio. La forma de evitar el borrado de
contenidos si se desea añadir datos nuevos a los ya existentes en un archivo es
abrirlo en modo ‘añadir’: los datos nuevos se escribirán en el archivo sin borrar los
anteriores, en el bien entendido que haya espacio disponible para ello.
En los casos en que la apertura requiere la creación de un nuevo archivo por parte
del sistema operativo, éste necesita saber:
-
nombre dispositivo: indica el soporte donde se situará el archivo;
nombre del archivo: que lo identifica entre los restantes en el mismo soporte;
tamaño del archivo: indica el espacio necesario para la creación del archivo;
organización del archivo: tipo de organización del archivo;
tamaño del bloque o registro físico: cantidad de datos que se leen o escriben
en cada operación de entrada/salida (E/S).
además de algunas indicaciones acerca del directorio al que se va a incorporar.
Algunos de estos datos tienen valores por defecto, esto es, valores que tomarán si
no se indica nada distinto. El proceso de creación puede no ser posible por generar
una serie de errores entre los que se pueden señalar:
-
Otro archivo con el mismo nombre ya existía en el soporte.
El dispositivo no tiene espacio disponible para crear otro nuevo archivo.
El dispositivo no está operativo.
Existe un problema de hardware que hace abortar el proceso.
Uno o más de los parámetros de entrada en la instrucción son erróneos.
222
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
80704" NGEVWTC"["GUETKVWTC"GP"WP"CTEJKXQ
Básicamente, la lectura de un archivo consiste en transferir información del
archivo a la memoria principal, mientras que la escritura en un archivo es la
transferencia de información de la memoria principal a un archivo. Para ello,
invocaremos la subrutina de lectura o escritura respectiva indicando a que archivo
queremos acceder (mediante su identificador interno del programa) y la
información que queremos transferir. En general, para una lectura debemos indicar
el lugar de la memoria principal (indicado bien por el nombre de una variable, bien
por un puntero) donde se desea situar los datos procedentes del archivo. En el caso
de escritura indicamos igualmente qué datos de la memoria principal deseamos
transferir al archivo (determinados asimismo, por la variable que los contiene o por
el puntero que indica su posición en la memoria). Esta descripción genérica de las
operaciones debe particularizarse para cada tipo de organización de archivo
posible.
En los archivos secuenciales, la lectura o escritura se realizan en el archivo a partir
de la posición actual en el mismo (contenida en el descriptor de fichero) que es en
principio la posición siguiente a la del último acceso al archivo que se hubiera
producido. En caso de que el soporte lo permita (soporte direccionable) y
conociendo la posición de un dato determinado dentro del archivo podremos
cambiar la posición actual dentro del mismo llamando a la subrutina de
posicionamiento y efectuar el siguiente acceso a partir de la nueva posición. Es
especialmente importante en la lectura de estos archivos, detectar cuando se ha
alcanzado el final del fichero y no hay más datos que leer. En algunos lenguajes, la
propia subrutina de lectura indica cuando se encuentra la marca de final de fichero.
En otros se dispone de una subrutina de detección de fin de fichero que conviene
consultar antes de realizar una lectura.
En los archivos secuenciales indexados los accesos no utilizan la posición actual,
sino que deben indicar el valor del campo clave para buscar el registro, de modo
que si no se encuentra un registro con dicha clave, hay que tener en cuenta esta
circunstancia. Igualmente la escritura se realiza indicando el valor de la clave y el
registro se sitúa en el archivo en la posición adecuada, actualizando las tablas de
índices si fuera necesario.
En los archivos de organización directa, que según indicamos eran de tamaño
prefijado y registros de longitud fija, usando la función hash que utilice el archivo,
a partir de cada clave se obtiene la posición del archivo donde debe encontrarse el
registro. El problema específico de esta organización (genérico de toda función
hash) es que la relación no es biunívoca, esto es, claves distintas pueden dar lugar a
la misma posición, lo que en la organización directa suscita el problema de las
colisiones, que son resueltas usando técnicas especiales.
ARCHIVOS Y BASES DE DATOS
223
Para la escritura indicamos el registro con su campo clave lo cual determina la
posición en el archivo. Sin embargo, si un campo con clave distinta ya ocupara
dicha posición (a consecuencia de tener el mismo resultado de la función hash) se
produce una colisión. La solución parcial a las colisiones es la existencia de una
zona de rebose donde emplazar el registro que ha colisionado. Para la lectura
indicaremos el campo clave, lo que permite calcular la posición donde debe
encontrarse el registro, comprobándose que efectivamente la clave del registro
encontrado sea la solicitada. Si no fuera así, se busca el registro en la zona de
rebose. Si tampoco se encuentra allí, se indicará el error correspondiente.
8080" RTQEGUCOKGPVQ"FG"CTEJKXQU
La vida de todo archivo comienza cuando se crea y acaba cuando se borra.
Durante su existencia es objeto de constante procesamiento, que con mucha
frecuencia incluye acciones de consulta o búsqueda y de actualización. En el caso
de la estructura archivos, entenderemos como actualización, además de las
operaciones, vistas para vectores y listas enlazadas en el capitulo anterior, de
introducir nuevos datos (altas) o de eliminar alguno existente (bajas), la
modificación de datos ya existentes, (operación muy común con datos
almacenados). En esencia, es la puesta al día de los datos del archivo.
Una operación de alta en un archivo consiste en la adición de un nuevo registro.
En un archivo de empleados, un alta consistirá en introducir los datos de un nuevo
empleado. Para situar correctamente un alta, se deberá conocer la posición donde
se desea almacenar el registro correspondiente: al principio, en el interior o al final
de un archivo. El algoritmo de ALTAS debe contemplar la comprobación de que el
registro a dar de alta no existe previamente.
Una baja es la acción de eliminar un registro de un archivo. La baja de un registro
puede ser lógica o física. Una baja lógica supone el no borrado del registro en el
archivo. Esta baja lógica se manifiesta en un determinado campo del registro con
una bandera, indicador o “flag” -carácter *. $, etc.,-, o bien con la escritura o
rellenado de espacios en blanco en el registro dado de baja.
Una modificación en un archivo consiste en la operación de cambiar total o
parcialmente el contenido de uno de sus registros. Esta fase es típica cuando
cambia el contenido de un determinado campo de un archivo; por ejemplo, la
dirección de un empleado. El proceso consiste en la lectura del registro procedente
del archivo, modificación de su contenido y reescritura, total o parcial del mismo
en el archivo.
Estas acciones las realizan los programas actuando a nivel de registro a partir de las
operaciones básicas descritas en el apartado anterior. La mayor parte de estas
224
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
acciones de procesamiento implican la localización de un registro concreto, para
luego actuar sobre él (leerlo, escribir o cambiar parte de él, borrarlo, etc.). La
facilidad de ejecución de cada una de ellas y su eficiencia en término de coste
temporal depende de la organización del fichero, como veremos a continuación.
80803" RTQEGUCOKGPVQ"FG"CTEJKXQU"UGEWGPEKCNGU
En archivo secuencial los registros se insertan en el archivo en orden
cronológico de llegada al soporte, es decir, un registro se almacena inmediatamente
a continuación del registro anterior. Puesto que los archivos secuenciales terminan
con una marca final de archivo, cuando se tengan que añadir registros a un archivo
secuencial, éstos se añadirán en las marcas fin de archivos.
6.6.1.1" PROCESO PARA LA ESCRITURA DE REGISTROS
Este proceso es secuencial, y para ello tendremos que ejecutar un programa
que permite la entrada de datos del archivo desde el terminal. El sistema usual es el
interactivo en el que el programa solicita los datos al usuario que los introduce por
teclado, hasta que se introduce una marca final de archivo EOF o FF) que supone el
final físico del archivo. Esta operación tiene dos variantes:
- utilizar por primera vez el archivo.
- añadir datos al archivo ya creado, después del último registro del mismo.
La primera supone que el archivo tiene que ser creado durante el proceso, mientras
que la segunda, asume que se trabaja con un registro que ya contiene datos y que
por tanto ya existe. Dejando aparte la cuestión de la creación del archivo, el
proceso que nos interesa requerirá los siguientes pasos:
* abrir el archivo;
* leer datos del registro.
* grabar registro.
* cerrar archivo.
El algoritmo de creación con inclusión del menú de opciones es el siguiente:
algoritmo creación
inicio
{menú de opciones}
escribir `1 creación archivo nuevo´.
escribir `2 añadir datos al archivo`.
leer opción
si opción = 1
entonces
ARCHIVOS Y BASES DE DATOS
225
abrir archivo nuevo para creación
sino
abrir archivo para añadir datos
fin_si
{introducción de datos en el archivo}
mientras no se alcance el fin de archivo (EOF) hacer
leer datos de un registro
escribir (grabar) registro en el archivo
fin_mientras
cerrar archivo
fin
6.6.1.2" CONSULTA
El proceso de búsqueda o consulta de una información en este tipo de
archivo, se debe efectuar obligatoriamente en modo secuencial. Por ejemplo, si se
desea consultar la información contenida en el registro 50, se deberán leer
previamente los 49 primeros registros que le preceden en orden secuencial. En el
caso de un archivo de personal si desean buscar un registro determinado
correspondiente a un determinado estudiante, será necesario recorrer, -leer- todo el
archivo desde el principio hasta encontrar el registro que se busca o la marca final
de archivos, si el registro correspondiente al estudiante buscado, no se encuentra en
el archivo.
Así, para el caso de un archivo de n registros, el número de lecturas de registros
efectuadas son:
- mínimo 1, si el registro buscado es el primero del archivo;
- máximo n, si el registro buscado es el último o no existe dentro del archivo.
Por término medio, el número de lecturas necesarias para encontrar un determinado
registro es: (n+1)/2
El tiempo de acceso al periférico será influyente en las operaciones de
lectura/escritura. Así, mientras en el caso de una lista o vector de n elementos
almacenados en memoria central puede suponer tiempos de microsegundos o
nanosegundos, en el caso de un archivo de n registros en un disco los tiempos de
acceso son de milisegundos o fracciones/múltiplos de milisegundos. Esto supone
un tiempo de acceso de 1.000 a 100.000 veces más grande una búsqueda de
información en un soporte externo que en memoria central.
Para obtener un algoritmo de consulta en un archivo secuencial, se requerirá un
diseño previo de la presentación de la estructura de los registros correspondientes
en el dispositivo de salida, de acuerdo con el número y longitud de los campos que
226
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
lo integran. En el algoritmo siguiente hay que distinguir la lectura desde una
terminal del registro buscado, de las lecturas de registros, pertenecientes al archivo,
que se efectúan secuencialmente.
algoritmo consulta
inicio
leer registro buscado (campo x) {registro buscado con un campo clave x}
encontrado ← falso
abrir archivo para lectura
leer registro
N←1
mientras registro < > FF hacer {FF, fin de fichero}
si registro (campo x) = registro buscado (campo x)
entonces
escribir ”el registro buscado existe”
encontrado ← verdadero
registro = FF
sino
leer registro
N←N+1
fin-si
fin_mientras
si encontrado ← falso
entonces
escribir ‘registro no encontrado, después de consultar’ N-1 ’registros’
fin-si
cerrar archivo
fin
6.6.1.3" ALTAS
La operación de dar de alta un determinado registro es similar a la
operación ya descrita anteriormente de añadir datos a un archivo. Es importante
remarcar que en un archivo secuencial sólo permite añadir datos al final del mismo.
En otro caso, si se quiere insertar un registro en medio de los ya presentes en el
archivo, sería necesaria la creación nueva del archivo.
El algoritmo para dar de alta un registro al final del fichero es como sigue:
algoritmo altas
leer registro de alta
inicio
ARCHIVOS Y BASES DE DATOS
227
abrir archivo para añadir
mientras haya mas registros hacer {algunos lenguajes ahorran este bucle}
leer datos del registro
fin_mientras
escribir (grabar) registro de alta en el archivo
cerrar archivo
fin
6.6.1.4" BAJAS
Existen dos métodos para dar de baja a un registro en un archivo
secuencial, donde no es fácil eliminar un registro situado en el interior de una
secuencia: Para ello podemos seguir dos métodos:
1) Utilizar y por tanto crear un segundo archivo auxiliar transitorio,
también secuencial, copia del que se trata de actualizar. Se lee el archivo completo
registro a registro y en función de su lectura se decide si el registro se debe dar de
baja o no. En caso afirmativo, se omite la escritura en el archivo auxiliar. Si el
registro no se va a dar de baja, este registro se reescribe en el archivo auxiliar (Ver
Figura 6.3).
Tras terminar la lectura del archivo original, se tendrán dos archivos: original ( o
maestro) y auxiliar. El proceso de bajas del archivo concluye borrando el archivo
original y cambiando el nombre del archivo auxiliar por el del inicial.
Archivo
original
Actualizacion
Fig. 6.3.
Archivo
auxiliar
Borrado y Modificación
2) Guardar o señalar los registros que se desean dar de baja con un
indicador o bandera que se guarda en un array; de esta forma los registros no son
borrados físicamente, sino que son considerados como inexistentes.
Inevitablemente, cada cierto tiempo, habrá que crear un nuevo archivo secuencial
con el mismo nombre, en el que los registros marcados no se grabarán.
6.6.1.5" MODIFICACIONES
228
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
El proceso de modificación de un registro consiste en localizar este
registro, efectuar dicha modificación y a continuación reescribir el nuevo registro
en el archivo. El método que se utiliza es el mismo que el visto para bajas.
Vamos a suponer que recorremos el archivo, que llamaremos maestro y que
preguntamos al operador si desea modificar cada uno de sus registros. No habría
ninguna dificultad, en el caso de que la modificación se quisiera hacer en un solo
registro, para que éste se localizara individualmente (como hicimos durante la
consulta) utilizando el correspondiente campo clave. El algoritmo correspondiente
seria:
algoritmo modificación
inicio
abrir archivo maestro para lectura
abrir archivo auxiliar para creación
leer registro del maestro
mientras registro del maestro <> EOF hacer
escribir “Modificar (S/N)”
leer respuesta
si respuesta = “S” entonces
llamar_a subprograma de modificación
fin_si
escribir registro en el archivo auxiliar
fin _mientras
cerrar archivo maestro
cerrar archivo auxiliar
borrar archivo maestro
cambiar nombre del archivo auxiliar por nombre del archivo maestro
fin
El subprograma de modificación de un registro consta de unas pocas instrucciones
en las que se debe introducir por teclado el registro completo con indicación de
todos sus campos o, por el contrario, el campo o campos que se desea modificar. El
subprograma en cuestión podría ser:
subprograma modificar
inicio
escribir ”Escribir R, para modificar el Registro completo”
escribir” Escribir C, si solo se quiere modificar algunos Campos individuales”
leer opción
{validar opción válida}
según_la opción hacer
R:
visualizar campos
introducir todos los campos del registro
ARCHIVOS Y BASES DE DATOS
229
C:
solicitar campos a modificar
elegir campos
introducir campos
fin_según
fin
80804" RTQEGUCOKGPVQ"FG"HKEJGTQU"UGEWGPEKCNGU"KPFGZCFQU
Debido a que esta organización de archivos no está soportada por todos los
lenguajes de programación, no vamos a tratar en detalle su correspondiente
procesamiento. Recordemos que estos archivos constan de un área de datos que
agrupa los registros y un área de índices. Una de las ventajas de la utilización de
índices en un fichero secuencial reside en que la búsqueda de registros puede
hacerse de forma mucho mas rápida que la que hemos visto hasta ahora. El
almacenamiento del área de índices en memoria principal, mientras el programa se
ejecuta, permite ejecutar la búsqueda binaria, con las ventajas que sabemos que
ésta conlleva.
Las operaciones que se pueden llevar a cabo con un archivo secuencial indexado,
son las habituales, solo que en su programación hay que tener en cuenta que se
tiene que construir y manejar la tabla de índices (claves-direcciones) y que los
registros se graban en el orden de las claves.
80805" RTQEGUCOKGPVQ"FG"HKEJGTQU"FG"QTICPK\CEKłP"FKTGEVC
Las operaciones con archivos de acceso directo son las usuales, ya vistas
anteriormente, aunque teniendo en cuenta que para cualquier acceso a un registro
inicialmente hay que buscar en la tabla de índices una clave igual a la
correspondiente al elemento que se desea (para obtener la dirección de la clave y
poder acceder el registro correspondiente) y que desde el punto de vista del
programador, solo existen los registros alcanzables a través de los índices que
existen en cada momento.
En un soporte direccionable -normalmente un disco-, cada posición se localiza por
su dirección absoluta-número de pistas y número de sector en el disco-. Los
archivos de acceso directo manipulan direcciones relativas en lugar de absolutas, lo
que hace al programa independiente de la posición absoluta del archivo en el
soporte. La función de conversión transformará las claves en direcciones relativas.
Suponiendo que existen N posiciones disponibles para el archivo, la conversión de
clave producirá una dirección relativa en el rango 1 a N. En el caso en que dos
230
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
registros distintos produzcan la misma dirección, se dice que se produce una
colisión que por otro lado son inevitables y que se controlan mediante dos métodos
básicos (sobre los que no insistiremos mas):
Buscar una nueva dirección libre en el mismo espacio del archivo.
Asignar el registro a la primera posición libre de la zona de excedentes.6.6.3.1" PROCESO DE ESCRITURA DE REGISTROS
El proceso de introducción de datos en un archivo directo o aleatorio, que
en un abuso de lenguaje llamaremos creación, consiste en ir introduciendo los
sucesivos registros en el soporte que los va a contener y en la detección obtenida
resultante del algoritmo de conversión. Si al introducir un registro se encuentra
ocupada la dirección, el nuevo registro deberá ir a la zona de sinónimos o de
excedentes, sobre cuyos detalles ya hemos dicho que no entraríamos. Bastará con
saber que estos archivos necesitan dos zonas de almacenamiento, la principal
constituida por registros de longitud constante y la de sinónimos donde
secuencialmente se almacenan aquellos registros cuyas claves coinciden o son
direcciones sinónimas de registros grabados en la zona principal.
Veamos un algoritmo que desarrolla este proceso de escritura:
algoritmo escri-reg
inicio
abrir archivo
leer registro
mientras < > FF hacer
calcular dirección mediante algoritmos de conversión
escribir ”dirección libre S/N”
leer respuesta
si respuesta = “S”
entonces
grabar registros
sino
buscar espacio en área de sinónimos
grabar registro
fin_si
leer registro
fin_mientras
fin
ARCHIVOS Y BASES DE DATOS
231
6.6.3.2" CONSULTA.A partir de la entrada del número o números de registros a consultar. Las
operaciones a realizar son:
-
definir clave del registro buscado.
aplicar algoritmo de conversión clave a dirección.
lectura del registro ubicado en la dirección obtenida.
comparación de las claves de los registros leído y buscado.
exploración secuencial del área de excedentes, si no se encuentra el registro
en este área es que no existe.
Veamos un esquema que facilita el proceso de consulta:
mientras < > EOF hacer
leer registro R
ir a subprograma de obtención de la dirección
leer registro S
si R=S
entonces
llamar_a subprograma consulta
sino
leer área de sinónimos
si FF en área de sinónimos ¨{no hay ningún sinónimo}
entonces
escribir “registro no existe”
sino llamar_a subprograma consulta
fin_si
fin_si
fin_mientras
6.6.3.3" ALTAS
Para dar de alta a un registro, se debe introducir su número de orden y contenido.
La inserción de un registro en el archivo, supone utilizar un campo adicional,
alta/baja del registro, SW (interruptor) que tome el valor 1 ó 0, según que el
registro esté dado de alta o de baja, ya que como veremos a continuación, la baja es
solo de caracter lógico y es posible que demos de alta un registro que ya existe,
pero que fue dado de baja anteriormente.
El algoritmo para llevar a cabo el procedimiento de dar de alta es:
232
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
algoritmo altas
inicio
SW = 0
repetir
leer” número de registro a dar de alta”. NR
si 1<NR<ALTO {ALTO es el número máximo de registros permitidos}
entonces
leer registro NR
si SW = 1
entonces
escribir “registro ya existe”
sino
SW=1
leer datos del registro
escribir SW y datos en el registro NR
fin_si
sino
escribir “el numero de registro no es correcto.“
fin_si
hasta_que no se deseen más altas
fin
6.6.3.4" BAJAS
Para realizar una baja, basta con indicarlo en el campo SW del registro
correspondiente, indicando, en el caso de que el registro exista en el archivo, que
su valor pase de 1 a 0. Este tipo de baja es solo lógica, lo que significa que, pese a
usar un registro dado de baja, éste sigue ocupando el mismo espacio que si
estuviera dado de alta.
El algoritmo para llevar a cabo el procedimiento de dar de baja es:
algoritmo baja
repetir
{ número de registro}
leer NR
si 1 ≤ NR ≤ TOTAL
entonces
leer registro NR
si SW=0
entonces
escribir” el registro no existe”
sino
escribir registro
ARCHIVOS Y BASES DE DATOS
233
si la opción de baja es correcta
entonces
SW = 0
escribir SW en el registro NR
fin_si
fin_si
sino
escribir “número de registro no correcto”.
fin_si
hasta-que no mas bajas
fin
6.6.3.5" MODIFICACIONES.En un archivo aleatorio para modificar un determinado registro hay que
localizarlo, para lo que hay que introducir el correspondiente número de registro,
modificar el contenido y reescribirlo. Veamos su algoritmo correspondiente:
algoritmo modificación
inicio
repetir
leer “número de registro”, NR
si 1 ≤ NR ≤ TOTAL
entonces
leer registro NR
si SW= 0
entonces
escribir “registro no existe”
sino
escribir registro
leer modificaciones
escribir nuevo registro
fin_si
sino
escribir “número de registro no correcto”
fin_si
hasta_que no haya más modificaciones.
fin
8090" VKRQU"FG"CTEJKXQU
234
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
En una aplicación informática se pueden utilizar archivos para realizar
funciones diversas. Conocer la función que va a desempeñar un archivo concreto es
fundamental a la hora de decidir cómo se debe organizar éste. En una primera
aproximación podemos clasificar los archivos en la forma que se indica en la Tabla
6.1.
Un archivo permanente contiene información relevante para una aplicación, es
decir, los datos necesarios para el funcionamiento de la misma. Su vida es larga al
menos comparable a la de la aplicación para la que ha sido creado) y generalmente
no puede generarse de una forma inmediata a partir de otros archivos.
Tabla 6.1.- Clasificación de los archivos según el uso que se hace de ellos.
-ARCHIVOS PERMANENTES
Archivos maestros
Archivos constantes
Archivos históricos
-ARCHIVOS TEMPORALES
Archivos intermedios
Archivos de maniobras
Archivos de resultados
Un archivo temporal contiene información relevante para un determinado proceso
o programa, pero no para el conjunto de la aplicación. Se genera a partir de los
datos de archivos permanentes o para actualizar éstos, y su vida es generalmente
muy corta.
Los archivos permanentes se pueden clasificar en:
Archivos maestros.- Un archivo maestro, tal como lo hemos venido viendo,
contiene el estado actual de los datos susceptibles de ser modificados durante la
aplicación informática que se programa. Es el núcleo central de la aplicación.
Todos los procesos están, en general, orientados a actualizar el archivo maestro o a
obtener resultados de él. Un ejemplo de este tipo de archivo es el archivo de
clientes de un banco, en el que los registros contienen información de
identificación de clientes, su saldo en cuenta, etc.
Archivos constantes.- Un archivo constante es aquel que contiene datos fijos para
la aplicación. En él las modificaciones son infrecuentes, normalmente se accede a
él sólo para consultar. Serán archivos constantes lo que contengan los intereses
para distintos tipos de cuentas bancarias, la ubicación de estantes en una biblioteca,
la capacidad de las aulas de un centro, una tabla de números primos, etc.
ARCHIVOS Y BASES DE DATOS
235
Archivos históricos.- Un archivo histórico es aquel que contiene datos que fueron
actuales en tiempos anteriores. Se conservan para poder reconstruir la situación
actual o situaciones anteriores. En algunos casos puede estar formado simplemente
por los registros borrados del archivo maestro. Un archivo histórico puede
contener, por ejemplo, los clientes que se han dado de baja en una entidad bancaria.
Los archivos temporales se pueden clasificar en:
Archivos intermedios.- Se utilizan para almacenar resultados de un programa que
han de ser utilizados por otro, dentro de una misma tarea.
Archivos de maniobras.- Se utilizan para almacenar datos propios de un programa
que éste no puede conservar en memoria principal, por falta de espacio en ésta. Se
encuentran normalmente en programas de cálculo numérico, compiladores y
editores. Su vida es siempre menor que es el tiempo de ejecución del programa.
Archivos de resultados.- Se utilizan para almacenar datos elaborados que van a
ser transferidos a un dispositivo de salida. Por ejemplo, un archivo de impresión,
que contiene datos que van a ser transferidos a una impresora.
Veamos un ejemplo próximo a una aplicación real, para ver el papel que juega cada
uno de los tipos de archivo.
Ejemplo 1:
Supongamos que se desea almacenar y procesar los datos relativos a ocupación y
cobros de un hotel. Será necesario, en primer lugar, almacenar una serie de datos
fijos, como son las características de cada habitación, la tarifa de precios, etc. Esta
información estará contenida en archivos, que por su naturaleza serán
permanentes y constantes. Los registros de estos archivos pueden tener la
siguiente estructura:
FDES: Archivo de descripción de habitaciones
-Número de habitación.
-Número de camas.
-Categoría
-Exterior/interior.
FPRE: Archivo de precios
-Categoría de la habitación.
-Número de camas.
-Precio por día en temporada alta.
236
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
-Precio por día en temporada baja.
Además, se deberán crear otros archivos que contendrán datos variables.
Concretamente, debe existir un archivo con información sobre el estado actual de
ocupación del hotel, que será un archivo permanente, éste será el archivo maestro
de la aplicación. Este archivo podrá tener la siguiente estructura:
HOTEL: Archivo de ocupación del hotel
-Número de habitación
-Inservible (si/no)
-Ocupada (sí/no).
-Número de personas.
-DNI del inquilino.
-Apellidos y nombre del cliente
-Fecha prevista para la partida.
-Fecha de ocupación.
Cada vez que un cliente abandona el hotel se creará un archivo de resultados
conteniendo la factura que se debe cobrar a dicho cliente. Este archivo será
transferido posteriormente a impresora, después de lo cual se borrará. Se trata, por
tanto, de un archivo temporal. Los datos de ocupación de habitaciones del archivo
HOTEL pasarán, una vez dejada la habitación por el cliente, a un archivo
histórico.
80:0" DCUGU"FG"FCVQU
En una aplicación convencional con archivos, éstos se diseñan siguiendo
las instrucciones de los correspondientes programas. Esto es, una vez planteado se
decide si debe haber ó no archivos, cuántos deben ser, qué organización contendrá
cada uno, qué programas actuarán sobre ellos y cómo lo harán. Esto tiene la
ventaja, en principio, de que los programas son bastante eficientes, ya que la
estructura de un archivo era pensada “para el programa” que lo va a usar. Sin
embargo, esta forma de actuar está plagada de graves inconvenientes. Por un lado,
los programas que se realizan con posterioridad a la creación de un archivo pueden
ser muy lentos, al tener que usar una organización pensada y creada “a la medida”
de otro programa previo, que realiza procesos diferentes. Por otra parte, si se toma
la decisión de crear nuevos archivos para los programas que se han de realizar, se
puede entrar en un proceso de degeneración de la aplicación, ya que:
-
gran parte de la información aparecerá duplicada en más de un archivo (se
denomina redundancias) ocupando la aplicación más espacio del
necesario;
ARCHIVOS Y BASES DE DATOS
-
237
al existir la misma información en varios archivos, los procesos de
actualización se complican de forma innecesaria, dando lugar a una
propagación de errores;
se corre el riesgo de tener datos incongruentes entre los distintos archivos.
Por ejemplo, tener dos domicilios diferentes de un mismo individuo en dos
archivos distintos (por estar uno actualizado y el otro no).
Ejemplo 2:
La dirección de una empresa se plantea la necesidad de contar con
información de sus empleados a efectos de envío de circulares y de selección de
personal para determinadas tareas. Una solución aceptable para esta aplicación,
puede ser crear un archivo con los siguientes campos: DNI, Nombre, Dirección,
Puesto ocupado, Fecha ingreso, Fecha nacimiento. Teléfono, a partir de los cuales
se puede obtener la información deseada. Si posteriormente la misma empresa
decide informatizar su nómina tendrá que optar por una de las siguientes
posibilidades:
-
-
Crear una aplicación completamente independiente de la anterior, que
dispondrá de nuevos archivos de datos: En este caso habrá datos
duplicados y con una alta posibilidad de que en algunos casos sean
incoherentes, pues los procesos de modificación serán independientes.
Modificar los archivos existentes. Esto implica reescribir o, al menos,
modificar los programas de aplicación anteriores.
Crear archivos que contengan la información de la nueva aplicación no
usada el la anterior. En estos archivos deberá haber al menos un campo de
enlace con el archivo anterior, por ejemplo el DNI. Nos encontramos aquí
en una situación intermedia, hay redundancias, no es necesario reescribir
todos los programas, pero los nuevos programas serán más lentos.
Es una aplicación convencional con archivos aparecen, pues, los siguientes
problemas:
Dificultad de mantenimiento. Si hay archivos con información parcialmente
duplicada, realizar las actualizaciones necesarias en un problema complejo y
costoso. Normalmente es necesario actualizar varios archivos con diferentes
organizaciones. Si la actualización no se realiza correctamente se tendrán
informaciones incoherentes.
Redundancia. Se dice que hay redundancia cuando hay datos que no aportan
realmente información real. Es decir, su valor se puede deducir del de otros datos.
238
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Supóngase que en el archivo de selección del ejemplo anterior se hubiese
incluido un campo con la antigüedad del empleado. Este campo sería redundante,
pues su valor se puede obtener del valor del campo Fecha de ingreso y de la fecha
actual. Un caso trivial de redundancia se da cuando se incluye más de una vez el
mismo dato. Esto no es normal que ocurra en un archivo, pero es frecuente en un
sistema de archivos.
Rigidez de búsqueda. El archivo se concibe para acceder a los datos de un
determinado modo. Sin embargo, en la mayoría de los casos es necesario ( o al
menos deseable) combinar acceso secuencial y directo por varias claves.
En el caso de archivo de dirección la organización más apropiada sería
directa o indexada, utilizando como clave el DNI del empleado. Esto permite la
consulta y la modificación de un empleado concreto, operaciones que serán
frecuentes. Sin embargo, estas organizaciones no permiten:
-
localizar a un empleado por su nombre,
obtener una relación de empleados por orden alfabético,
obtener empleados con fecha de ingreso anterior a una dada,
...........
Todas estas búsquedas implican procesar el archivo secuencialmente,
creando un archivo intermedio, que en algunos casos habrá que ordenar
posteriormente.
Dependencia de los programas. En un archivo las relaciones existentes entre
campos y registros no están plasmadas en modo alguno. Es el programa , que
trabaja con el archivo, el que determina en cada caso dichas relaciones. El
programa recibe cada vez que lee una cadena de caracteres. Por tanto, la
información de dónde comienza y dónde acaba cada campo, su tipo, etc., es
inherente al programa. Esto implica que cualquier modificación de la estructura de
un archivo obliga a modificar todos los programas que lo estén usando. Esto ocurre
aún en el caso de que la alteración sea ajena al programa. Así, si se aumenta la
longitud de un campo, habrá que modificar incluso los programas que no lo usan.
Confidencialidad y seguridad. Uno de los mayores problemas de cualquier
sistema de información es mantener la reserva necesaria sobre los datos que
contiene. Esto es, por un lado, impedir el acceso de determinados usuarios a
determinados datos (confidencialidad) y por otro, impedir modificaciones
provocadas por usuarios no autorizados (seguridad). Si se está trabajando con
archivos, el control deberá realizarlo el propio programa, por lo que no se podrá
impedir que alguien construya un programa para modificar o ver el contenido del
archivo, siempre que el sistema operativo le permita el acceso.
ARCHIVOS Y BASES DE DATOS
239
80:03" EQPEGRVQ"FG"DCUG"FG"FCVQU
Las bases de datos surgen como alternativa a los sistemas de archivos,
intentando eliminar o al menos reducir sus inconvenientes. Podemos definir una
base de datos así:
Una base de datos es un sistema formado por un conjunto de datos y un paquete
software para la gestión del mismo, de tal modo que se controla el
almacenamiento de datos redundantes, los datos resultan independientes de los
programas que lo usan, se almacenan las relaciones entre los datos junto con éstos
y se puede acceder a los datos de diversas formas.
En una base de datos se almacenan las relaciones entre datos junto a los datos.
Esto, y el utilizar como unidad de almacenamiento el campo además del registro, es
el fundamento de la independencia con los programas de datos.
Normalmente la definición del concepto de base de datos se realiza en forma de
requisitos u objetivos que está debe cumplir. Aunque la definición anterior es
suficientemente precisa, vamos a exponer algunos requisitos que debe cumplir un
buen sistema de base de datos:
Acceso múltiple. Diversos usuarios pueden acceder a la base de datos, sin que
se produzcan conflictos ni visiones incoherentes.
Utilización múltiple Cada usuario podrá tener una imagen o visión particular
de la estructura de la base de datos.
Flexibilidad. Se podrán usar distintos métodos de acceso, con tiempos de
respuesta razonablemente pequeños.
Confidencialidad y seguridad. Se controlará el acceso a los datos ( incluso a
nivel de campo), impidiéndoselo a los usuarios no autorizados.
Protección contra fallos.
Deben existir mecanismos concretos de
recuperación en caso de fallo de la computadora.
Independencia física. Se puede cambiar el soporte físico de la base de datos
(modelo de discos, por ejemplo), sin que esto repercuta en la base de datos ni
en los programas que la usan.
Independencia lógica. Capacidad para que se puedan modificar los datos
contenidos en la base, las relaciones existentes entre ellos o incluir nuevos
datos, sin afectar a los programas que lo usan.
Redundancia controlada. Los datos se almacenan una sola vez.
240
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Interfaz de alto nivel. Existe una forma sencilla y cómoda de utilizar la base,
al menos se cuenta con un lenguaje de programación de alto nivel, que facilita
la tarea.
Interrogación directa (“query”). Existan facilidades para que se pueda tener
acceso a los datos de forma conversacional.
80:04" GUVTWEVWTC"IGPGTCN"FG"WPC"DCUG"FG"FCVQU
En una base de datos se almacena información de una serie de objetos o
elementos. Estos objetos reciben el nombre de entidades. Entidad es cualquier ente
sobre el que se almacena información. Así, en una base de datos académicos podrá
haber información de las siguientes entidades: alumno, profesor, asignatura, centro,
plan de estudios, curso, etc. En una base de datos comerciales de una empresa
podrán aparecer las siguientes entidades: cliente, producto, vendedor, etc. De cada
entidad se almacenan una serie de datos que se denominan atributos de la entidad.
Puede ser atributo de una entidad, cualquier característica o propiedad de ésta que
se considere relevante para la aplicación. Así son atributos de la entidad alumno,
para una aplicación administrativa: DNI, apellido y nombre, sexo, fecha de
nacimiento, nacionalidad, etc., sin que debieran figurar características como el
pensamiento político o la inclinación sexual, que siendo importantes no tienen nada
que ver con los requisitos de una aplicación administrativa.
Entidades y atributos son conceptos abstractos. En una base de datos, aunque la
tecnología evoluciona constantemente, la información de cada entidad se almacena
en registros, y cada atributo en campos de dicho registro, de forma análoga al
almacenamiento en archivos. Sin embargo, cada entidad necesita registros con una
estructura específica, mientras que en un archivo, todos los registros tienen la
misma estructura. Esto es, en una base de datos hay diferentes tipos de registros,
uno por entidad. Normalmente se reserva el nombre “registro” para especificar un
“tipo de registro”, usándose otras denominaciones para especificar cada una de las
apariciones de ese registro en la base de datos, ocurrencia de registro. Con esta
terminología se puede decir que, en la base de datos de uso para una empresa, antes
mencionada, hay un registro de vendedor y tantas “ocurrencias” de dicho registro
como vendedores tenga la empresa.
Normalmente no es necesario conocer los valores de todos los atributos de una
entidad para determinar si dos elementos son iguales. Por lo general, es suficiente
con conocer el valor de uno o varios atributos para identificar un elemento. Pues
bien, diremos que un conjunto de atributos de una entidad es un identificador de
dicha entidad si el valor de dichos atributos determina de forma unívoca cada uno
de los elementos de dicha entidad y no existe ningún subconjunto de él que sea
ARCHIVOS Y BASES DE DATOS
241
identificador de la entidad. Por ejemplo, en la entidad alumno, el atributo DNI es
un identificador de esa entidad.
Frecuentemente es necesario buscar una ocurrencia de un registro en una base de
datos, conociendo el valor de uno o varios campos. Para que esta operación sea
rápida, estos campos deben estar definidos en la base de datos como clave o llave
de búsqueda de dicho registro. En general, podemos decir que una clave es un
campo o conjunto de campos, cuyos valores permiten localizar de forma rápida
ocurrencias de un registro. La clave puede corresponderse con un identificador de
la entidad. Si esto no ocurre, podrá haber varias ocurrencias de registro con el
mismo valor de clave. Se dice entonces que la clave admite duplicados.
En una base de datos se almacenan, además de la entidades, las relaciones
existentes entre ellas. Así, por ejemplo, en la base de datos académicos antes citada
hay relaciones entre las siguientes entidades: cursos y alumnos, alumnos y
profesores, profesores y asignaturas.
80:05" VKRQU"FG"DCUGU"FG"FCVQU
Las bases de datos se clasifican tradicionalmente en tres grupos:
jerárquicas, en red y relacionales. Las dos primeras se diferencian en los tipos de
relaciones que permiten. Puede decirse que la estructura jerárquica es un caso
particular de la estructura de la red. Cualquier esquema que se cree para una base
de datos jerárquica se puede utilizar para una base de red. Las bases de datos
relacionales son conceptualmente distintas. En éstas, las relaciones se almacenan y
manipulan de forma completamente distinta, como se verá más adelante.
Bases de datos jerárquicas.En una base de datos jerárquica sólo se pueden crear estructuras jerárquicas
(esto es, en árbol). No es, pues, posible definir relaciones muchos a muchos. Para
poder dar una caracterización más precisa de este tipo de base de datos se introduce
un nuevo concepto: el de conjunto. Un conjunto es una estructura formada por dos
registros ligados por una relación uno a muchos. Los registros que forman el
conjunto reciben, en éste, los nombres de propietario y miembro, siendo la relación
de un propietario a muchos miembros y no acepta estructuras en las que un mismo
registro sea miembro de dos conjuntos distintos. Físicamente, una estructura de este
tipo se almacena usando punteros como enlace entre los distintos registros de cada
conjunto.
242
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Bases de datos en red.En una base de datos de red no hay ninguna restricción ni en el tipo de
relaciones que se pueden usar, ni en los registros que pueden intervenir en ellas. No
obstante se distinguen entre bases de datos en red simple y bases de datos en red
compleja, según permitan o no utilizar relaciones muchos a muchos. En una base
de datos en red simple este último tipo de relaciones no está permitido. Una base de
datos de red simple puede descomponer en conjuntos, al igual que una base
jerárquica.
Bases de datos relacionales.A principios de la década de los 70, F.F. Codd planteó una alternativa a las
bases de datos jerárquicas y en red, con la pretensión de obtener más flexibilidad
que con las bases anteriores y más rigor en el tratamiento de los datos.
Una base de datos relacional está formada por tablas (Ver Figura 6.4). como
sabemos, una tabla es una estructura bidimensional formada por una secuencia de
registros del mismo tipo.
Número de
vuelo
27
404
1024
114
Avión
Origen
Destino
DC-9
DC-10
B-727
B-727
DC-9
Granada
Madrid
Barcelona
Santiago
Madrid
Madrid
Oslo
París
Sevilla
Málaga
Hora de
salida
8:45
10:37
9:45
17:21
15:30
Fig. 6.4.
Ejemplo de representación de relaciones en forma de una tabla
Si se imponen ciertas condiciones a las tablas, se pueden tratar como
relaciones matemáticas. De ahí el nombre de este tipo de bases de datos y el hecho
de que a las tablas de una base de datos relacional se les denomine relaciones. Las
tablas deben cumplir las siguientes condiciones:
-
Todos los registros de una tabla son del mismo tipo. Para almacenar
registros se usan tablas distintas.
En ninguna tabla aparecen campos repetidos.
En ninguna tabla existen registros duplicados.
El orden de los registros en la tabla es indiferente. En cada momento se
pueden recuperar los registros en un orden particular.
En cada tabla hay una clave, formada por uno o varios campos.
Digamos que la mayor parte de bases de datos que están disponibles en la
actualidad para ordenadores personales y estaciones de trabajo son relacionales,
ARCHIVOS Y BASES DE DATOS
243
habiendo incorporado una serie de ventajas adicionales, aunque éste es un campo
de la informática que está en constante evolución.
80:06" UKUVGOC"FG"IGUVKłP"FG"NC"DCUG"FG"FCVQU
Se denomina sistema de gestión de la base de datos (SGDB o DBMS, del
inglés “Data Base Management System”) al conjunto de software destinado a la
creación, control y manipulación de la información de una base de datos.
Concretamente, Un DBMS debe permitir la realización de las siguientes tareas:
-
Acceso a los datos desde algún lenguaje de alto nivel.
Interrogación (o recuperación de la información) directa en modo
conversacional.
Definición del esquema de la base y de los distintos subesquemas.
Organización física de la base de datos y recuperación tras fallos del
sistema.
Un Sistema de Gestión de Base de Datos, al igual que el sistema operativo,
proporciona servicios tanto a los usuarios como a otros programas. A menudo,
cuando el usuario piensa que está utilizando directamente el Sistema de Gestión, lo
que realmente hace es usar un programa que le proporciona una interfaz de usuario
para trabajar con él.
244
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
6.1. ARCHIVOS: DEFINICIONES Y CONCEPTOS .....................................213
6.2. SOPORTE Y ACCESO A LOS ARCHIVOS ............................................216
6.3. EL SISTEMA OPERATIVO Y LA GESTIÓN DE ARCHIVOS ............217
6.4. ORGANIZACIÓN DE ARCHIVOS...........................................................218
6.5. OPERACIONES SOBRE ARCHIVOS......................................................220
6.5.1 APERTURA Y CIERRE DE UN ARCHIVO..............................................220
6.5.2 LECTURA Y ESCRITURA EN UN ARCHIVO ........................................222
6.6. PROCESAMIENTO DE ARCHIVOS .......................................................223
6.6.1 PROCESAMIENTO DE ARCHIVOS SECUENCIALES ..........................224
6.6.2 PROCESAMIENTO DE FICHEROS SECUENCIALES INDEXADOS ...229
6.6.3 PROCESAMIENTO DE FICHEROS DE ORGANIZACIÓN DIRECTA ..229
6.7. TIPOS DE ARCHIVOS ...............................................................................233
6.8. BASES DE DATOS ......................................................................................236
6.8.1 CONCEPTO DE BASE DE DATOS...........................................................239
6.8.2 ESTRUCTURA GENERAL DE UNA BASE DE DATOS.........................240
6.8.3 TIPOS DE BASES DE DATOS...................................................................241
6.8.4 SISTEMA DE GESTIÓN DE LA BASE DE DATOS ................................243
CAPÍTULO 7
ALGORITMOS Y SU COMPLEJIDAD
La tarea de programación está ligada al objetivo de obtener algoritmos que
resuelvan un problema con la mayor eficiencia posible; de hecho es sorprendente
comprobar las múltiples formas como podemos resolver un mismo problema y las
ventajas que conseguimos, en términos de eficiencia, al buscar soluciones
alternativas a las ya conocidas o consideradas como evidentes.
El objetivo de este capítulo es doble: presentar la variedad de algoritmos existentes
para resolver una serie, necesariamente reducida, de problemas habituales de
distinta naturaleza y, en paralelo, formalizar la idea de “mayor eficiencia”,
estableciendo el concepto de complejidad algorítmica que desde el punto de vista
computacional es básico. Esto nos permite introducir determinados conceptos
relacionados con los problemas que son potencialmente resolubles.
9030" OGFKFC"FG"NC"GHKEKGPEKC"["FG"NC
EQORNGLKFCF"CNIQTKVOKEC
Hasta ahora, el concepto de mayor eficiencia de un algoritmo frente a otro lo
hemos introducido de forma intuitiva, lo que no ha sido óbice para apostar por
algún método para obtener algoritmos más eficientes (p.e. divide y vencerás).
Para comparar y analizar la eficiencia de los algoritmos, éstos los consideraremos
escritos en un lenguaje de programación de alto nivel, pero aún empleando la
misma representación, establecer una medida precisa de la eficiencia de un
algoritmo no es fácil. En efecto, fijémonos en que una definición de eficiencia
podría ser el número de instrucciones que tiene el programa; sin embargo esto no
se correspondería, con el concepto intuitivo que tenemos de eficiencia (según el
cual, el algoritmo más eficiente sería aquel que tardase menos tiempo en resolver el
problema sobre una misma máquina), dado que todas las instrucciones no utilizan
el mismo tiempo de procesador aun realizando la misma función (Ver ejemplo de
la Figura 7.1).
desde i:=1 hasta 10000
desde i:=1 hasta 10000
245
246
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
x ← i^2
x ← i*i
fin-desde
fin-desde
Fig. 7.1. El primer algoritmo es más costoso que el segundo, a pesar de hacer la
misma función, a causa de que la potencia es mucho más lenta que el producto.
Es más, el número de instrucciones puede reducirse sin que por ello disminuya el
número de instrucciones que realmente deben procesarse; así por ejemplo, un bucle
lo podemos programar tanto con una estructura desde-hasta como con una
estructura mientras y aunque en este último caso se necesitan más instrucciones
(Ver Figura 7.2), realmente el tiempo de proceso es el mismo1.
desde i:=1 hasta 1000 i ← 1
acciones S
mientras i <= 1000
fin-desde
acciones S
i ← i+1
fin_mientras
Fig. 7.2. Los dos bucles implican los mismos cálculos, con independencia
del numero de instrucciones de sus estructuras.
Por otra parte, como ya hemos hecho notar en capítulos anteriores, el propio
concepto de tipo de dato se utiliza, entre otras cosas, para emplear los métodos más
adecuados para realizar las operaciones entre los datos. Así, para un mismo
procesador, efectuar el producto de dos números es mucho más lento si estos
números son de tipo Real que si son de tipo Entero, aun siendo los mismos
números; sin embargo ambos casos son similares desde el punto de vista
algorítmico.
Todo lo anterior, unido a la dificultad de dar una medida de tiempo relativo ligada
a la ejecución de cada instrucción (sobre todo en lo que al acceso a periféricos se
refiere) hace que una definición precisa que se corresponda con el concepto
intuitivo de eficiencia tenga poco sentido. Cuestiones como las comentadas
anteriormente, el bucle desde-hasta o el tipo de dato más adecuado, están ligadas a
cuestiones de implementación, más que al propio diseño del algoritmo, y pueden
optimizarse con suficiente práctica en la codificación de algoritmos. Sin embargo,
existen elementos ligados al propio diseño del algoritmo, que potencialmente son
mucho más impactantes sobre el tiempo de cálculo, que las consideraciones
anteriores, si el programador no considera adecuadamente la situación. Como
ejemplo analicemos
los algoritmos de la Figura 7.3, que en principio, calculan el
n
valor de x2 y veamos su comportamiento en función del valor de n.
m←x
1
m←1
Si bien es cierto que el bucle desde-hasta es ligeramente más rápido que el bucle mientras.
ALGORITMOS Y SU COMPLEJIDAD
247
desde j:=1 hasta 2n , hacer
desde j:=1 hasta n, hacer
m←m*x
m←m*m
fin-desde
fin-desde
n
Fig. 7.3. Ejemplo de dos algoritmos que calculan x2
En el primer algoritmo se necesitan realizar n multiplicaciones, mientras que en el
segundo se realizan 2n operaciones. Esto significa que para n=100 en un caso
realizamos 100 multiplicaciones y en el otro caso 2100 =1.26*1030 . Esto significa
que disponiendo de un computador que efectuara un millón de multiplicaciones por
segundo (lo cual implica que procesaría varios millones de instrucciones de
lenguaje máquina por segundo), para ejecutar el primer algoritmo empleará 0.0001
seg. (una diezmilésima de segundo) y para el otro 1,26*1024 seg
(¡aproximadamente 4*1016 años!), o sea que si hubiese empezado a calcular
centenas de miles de millones de años antes de que existiese el Universo, aún no
habría acabado). Este ejemplo nos da elementos para poder avanzar en el concepto
de complejidad de un algoritmo, ya que esta definición no debe necesariamente
discriminar entre la eficiencia de dos algoritmos cuyo tiempo de computación sea
del mismo “orden de magnitud”, pero que sí que lo debe hacer entre algoritmos
como los expuestos en la Figura 7.3.
n
En ambos algoritmos, que resuelven el mismo problema (calcular x2 ) podemos ver
que el número de operaciones a realizar dependerá del valor de n; se dice que n es
la talla o tamaño del problema. Si, por poner otro ejemplo, el caso fuera el de
buscar un valor en un vector, el tamaño del problema sería el número de elementos
del vector, ya que, sea cual sea el algoritmo, es obvio que el número de operaciones
dependerá del número de elementos del mismo. En general vemos que cada
problema tiene un tamaño (que determinaremos en cada caso) y que el coste del
algoritmo que resuelva el problema dependerá de dicho tamaño.
90303" QTFGP"FG"EQORNGLKFCF
La complejidad de un algoritmo deberá estar relacionada con el número de
operaciones elementales necesarias (asignaciones, comparaciones, sumas, restas,
multiplicaciones, divisiones, etc.) para resolver un problema dado. El número de
estas operaciones dependerá de los datos de entrada y éstos pueden dar lugar desde
una solución especialmente favorable hasta una especialmente costosa. Por ejemplo
en la búsqueda secuencial de un vector ordenado, si el valor buscado es el menor lo
obtendremos con muy pocas operaciones, sin embargo si buscamos el último, la
solución supondrá recorrer todo el vector. Por ello se habla del mejor, del peor caso
y del caso medio. Para el peor caso de un algoritmo, expresaremos la función que
mide el numero de operaciones según el tamaño del problema como f(n), que
tomaremos como medida aproximada de la eficiencia.
248
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Definición: Diremos que la complejidad del algoritmo es del orden de g(n) (lo
representaremos por O(g(n)) ) si existe un n0 tal que, para todo valor de n ≥ n0 ,
existe una constante C tal que |f(n)| ≤ C |g(n)|. Con esta definición, si f(n) es un
polinomio de grado k, el algoritmo correspondiente tendrá una complejidad O(nk),
independientemente de cuales sean los coeficientes y términos de menor grado del
polinomio. De esta forma se formaliza la idea de que dos algoritmos de distinta
eficiencia tengan la misma complejidad. En el caso de la figura 7.3, la complejidad
de los algoritmos es de O(n) y O(2n) respectivamente.
Si un algoritmo tiene una complejidad de O(nk), se dice que es polinomial2 (en el
caso de k=1 se le llama lineal, para k=2 cuadrático y para k=3 cúbico); el resto de
algoritmos se conocen como no-polinomiales. La siguiente tabla muestra el tiempo
que tardaría un computador en realizar f(n) operaciones, para distintas funciones f
y distintos valores de n, suponiendo que realizase un millón de operaciones por
segundo.
Tabla 7.1. Tiempo en segundos (salvo indicación contraria) que tardan en
realizarse f(n) operaciones, haciendo un millón por segundo
n
f(n)
n
n log(n)
n2
n3
n4
n5
Log(n)
n
2n
3n
n!
nn
10
20
30
40
50
70
100
0.00001 s 0.00002 s 0.00003 s 0.00004 s 0.00005 s 0.00007 s 0.0001 s
0.00003 s 0.00008 s 0.00014 s 0.00021 s 0.00028 s 0.00049 s 0.0006 s
0.0001 s 0.0004 s
0.0009 s
0.0016 s
0.0025 s 0.0049 s 0.01 s
0.001 s
0.008 s
0.027 s
0.064 s
0.125 s
0.343 s
1s
0.01 s
0.16 s
0.81 s
2.56 s
6.25 s
24 s
1.6 min
0.1 s
3.19 s
24.3 s
1.7 s
5.2 min
28 min 2.7 horas
0.002 s
4.1 s
17.7 s
5 min 35 s 1 h 4min 2.3 días 224 días
0.001 s
1.04 s
17 min
12 dias
35.6 a.
37 Ma 2.6 MEU
0.059 s
58 min
6.5 a.
385495 a. 22735 Ma 52000 Ma 1018 MEU
3.6 s
77054 a. 564 MEU 1.6 1018ME 6 1034 2.4 1070M
2
2.7 horas 219 EU 4.2 1014ME 2.4 1028ME 1.8 1067ME 3 10111 M 2 10182 M
s: segundos min: minutos h: horas
a: añosMa: millones de años
EU: edad del universo
MEU: millones de veces la edad del universo
Comparando las casillas inferiores de esta tabla (sombreadas) con el resto, se hace
evidente la importancia de estimar la complejidad de los algoritmos: aquellos cuya
complejidad del orden de las últimas filas de la tabla (no-polinomiales) no resultan
útiles más que para tamaños muy reducidos del problema a resolver, y por tanto
con muy reducida aplicación práctica.
2
También conocidos como Algoritmos de tiempo polinomial.
ALGORITMOS Y SU COMPLEJIDAD
249
90304" CPıNKUKU"FG"EQORNGLKFCF"FG"NQU"CNIQTKVOQU"FG
DðUSWGFC
Vamos ahora a comparar la complejidad de dos algoritmos, ya estudiados, que
resuelven un mismo problema: búsqueda secuencial y binaria. Para ponernos en
condiciones de partida semejantes, supongamos que trabajamos con un vector
ordenado de n elementos (única situación en la que es posible, aplicar la búsqueda
binaria).
En el caso de la búsqueda secuencial, el peor caso se dará cuando el elemento
buscado no exista en el vector o cuando éste esté situado en la ultima posición, por
lo que el numero de comparaciones, será igual al tamaño del vector (en este caso el
número de elementos del vector, n, es el tamaño del problema), por consiguiente,
O(n). (Obsérvese que el caso medio, supondrá aproximadamente (n+1)/2
comparaciones, con lo cual seguimos teniendo un problema de complejidad lineal).
Para analizar la búsqueda binaria usaremos también el número de comparaciones
que necesitamos, en el peor caso, que se dará cuando no encontremos el elemento
buscado o este se halle en uno de los extremos del vector. Para darnos una idea,
consideremos el siguiente vector: 1, 2, 3, 4, 5, 6, 7. Si buscamos el valor 7,
tendremos que efectuar 3 comparaciones. En realidad podemos redondear y
suponer que trabajamos con la potencia de dos más próxima por exceso a n, para
estimar el número máximo de subdivisiones que necesitamos en el peor caso. En
nuestro caso podemos suponer que el vector tuviera 8 elementos y observar como:
3 = log2 8, nos da el máximo numero de subdivisiones que tendríamos que llegar a
efectuar para localizar cualquier valor del vector. Sin mucha dificultad podemos
aceptar que este algoritmo presenta una complejidad de O(log2 n), cuya gran
eficiencia ni siquiera se ha representado en la tabla 7.1, ya que el número de
operaciones, para el caso algorítmico, es realmente muy baja y casi despreciable en
término de tiempo para un computador moderno. Así para un tamaño del vector de
100, solo serian necesarias 7 comparaciones y para el caso de n = 1000000, con 20
serían suficientes. Con ello concretamos la mayor eficiencia, ya adelantada, de un
algoritmo frente a otro en el caso de vectores ordenados.
9040" CNIQTKVOQU"FG"QTFGPCEKłP"["UW
EQORNGLKFCF
La ordenación o clasificación es el proceso de organizar los datos individuales
de un vector en algún orden o secuencia específica (creciente o decreciente para
datos numéricos o alfabéticamente para los datos tipo carácter). Durante la
descripción y análisis del proceso de búsqueda, hemos tenido ocasión de ver la
importancia que tiene el poder trabajar con datos ordenados; por ello no debe
250
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
extrañar que este problema ocupe un lugar especial en un curso de programación.
Nótese incluso que de esta operación viene el término “ordenador”.
Vamos a distinguir dos tipos de ordenación, la llamada ordenación interna que
exige que la colección completa de elementos a ordenar estén almacenados en
memoria principal (normalmente en forma de un vector) y la ordenación externa
en la que se trabaja con la restricción de que la mayoría de datos se encuentran
fuera de la memoria principal, esto es, almacenados en memoria secundaria (disco
o cinta). La razón para esta distinción reside en el hecho de que en un archivo es
muy frecuente que existan más registros a ordenar que los que caben
simultáneamente en la memoria principal; en consecuencia las hipótesis de partida
son radicalmente distintas. Afortunadamente la mayoría de sistemas operativos
actuales disponen de órdenes capaces de llevar a cabo la ordenación de un archivo
(p.e. la orden SORT en el DOS de Microsoft). A continuación vamos a estudiar
algunos algoritmos utilizados en ordenación interna de vectores.
90403" QTFGPCEKłP"RQT"KPUGTEKłP
Este algoritmo consiste en insertar un elemento en el vector, en una parte ya
ordenada del mismo y comenzar de nuevo con los elementos restantes; fijarse que
de hecho este método es el que utilizamos cuando ordenamos un mazo de naipes
por lo se le conoce también por método de la baraja.
Ejemplo 1:
Consideremos el siguiente vector, ya parcialmente ordenado en sus primeros siete
elementos y hagamos la inserción del octavo (45) en su lugar correspondiente:
5
14
24
39
43
65
84
45
Para insertar el elemento 45, que es el siguiente en la ordenación, habrá que
insertarlo entre 43 y 65, lo que supone desplazar a la derecha todos aquellas
números de valor superior a 45, es decir, saltar sobre 65 y 84. Como puede
observarse, el algoritmo se ejecutara en base a comparaciones y desplazamientos
sucesivos.
5
14
24
39
43
45
65
84
ALGORITMOS Y SU COMPLEJIDAD
251
El algoritmo de ordenación por inserción de un vector X de N elementos, se realiza
con un recorrido de todo el vector (desde el segundo al n-ésimo elemento, pues un
vector de un solo elemento, siempre está ordenado) y la inserción del elemento iesimo correspondiente en el lugar adecuado, suponiendo que en cada momento el
subvector X(1), X(i-1) esta ordenado En un primer esbozo del diseño, podemos
escribir:
desde i := 2 hasta N hacer
seleccionar el elemento más pequeño de X(i)...X(N) e intercambiarlo con X(i)
fin_desde
Esta acción -insertar- que se repite y constituye el cuerpo del bucle es una
operación que ya hemos tratado en vectores, pudiendo llevarse a cabo de diferentes
formas; Veamos el algoritmo correspondiente y observemos como se utiliza el
hecho, de que en cada paso (J) del bucle desde, al estar ordenado el subvector
correspondiente, X(1),......., X(J-1), el valor X(J-1) es el mayor de ellos. El objetivo
de cada pasada del bucle, es encontrar el valor que debe ocupar la posición j-ésima
en el vector ordenado.
algoritmo ord_inserción
inicio
desde J = 2 hasta N hacer
AUX ← X(J)
K←J-1
mientras AUX < X(K) hacer
X(K + 1) ← X(K)
K← K-1
fin_mientras
X(K + 1) ← AUX
fin_desde
fin
Para estimar la complejidad de este algoritmo, tomaremos como operaciones
elementales para calcular f(n), las comparaciones y asignaciones que se realizan
involucrando números a ordenar. El peor caso para obtener una ordenación
ascendente del vector, se produce cuando los números están inicialmente ordenados
de mayor a menor, es decir totalmente al revés. En este caso, el número de
comparaciones necesarias es, en función del contador j del algoritmo:
j=2
NºComparaciones: 1 +
Num. Asignaciones:
j=3
j=4 .
2 + 3 +
..
...
+
j=n-1
j=n
n-2 + n-1 = n(n-1)/2
252
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Bucle Desde :
Bucle Mientras:
Así, f(n) =
n
2
2
−
2
1
n
2
+
+
+ 2n − 2 +
complejidad O(n2).
2
2
n
2
2
−
+
+
n
2
2
3 +
...
...
2
= n +n−2
+
+
2 + 2 =2(n-1)
n-2 + n-1 = n(n-1)/2
y por tanto el algoritmo es de
Nótese que en el mejor caso (números inicialmente en el orden correcto), el
número de operaciones elementales es sensiblemente inferior (3n-3). En efecto:
j=2
j=3
j=4
j=n-1 j=n
Num. Comparaciones:
1
+
1
+
1 +
...
+
1
+
1 = n-1
Num. Asignaciones
Bucle Para :
Bucle Mientras:
2
0
+
+
2
0
+
+
2 +
0 +
...
...
+
+
2
0
+
+
2 =2(n-1)
0 =0
90404" QTFGPCEKłP"RQT"KPVGTECODKQ
El algoritmo de clasificación u ordenación por intercambio se basa en el
principio de comparar pares de elementos adyacentes y en caso de contravenir el
orden esperado, intercambiarlos, realizando este proceso las veces necesarias hasta
que estén todos ordenados.
Ejemplo 2:
Supongamos que se desea clasificar en orden descendente por el método de
intercambio el siguiente vector:
A(1)
50
A(2)
15
A(3)
56
A(4)
14
A(5)
35
A(6)
1
A(7)
12
A(8)
9
Los pasos a dar son:
1.- Comparar A(1) y A(2); si están en orden, se mantienen como están; en caso
contrario se intercambian entre sí. Al buscar un orden descendente, no efectuamos
ningún cambio pues 50 > 15 (orden descendente correcto).
2.- A continuación se comparan los elementos A(2) y A(3); de nuevo se
intercambian si es necesario. En este caso 15 > 56, luego debemos intercambiarlos.
3.- El proceso continúa hasta que cada elemento del vector ha sido comparado
con sus elementos adyacentes y se han realizado los intercambios necesarios.
ALGORITMOS Y SU COMPLEJIDAD
253
Los sucesivos contenidos del vector a lo largo de estos pasos, son los siguientes:
A(8)
A(7)
A(6)
A(5)
A(4)
A(3)
A(2)
A(1)
v.inicial 1ªcomp. 2ªcomp. 3ªcomp 4ªcomp 5ªcomp 6ªcomp 7ªcomp
9
9
9
9
9
9
9
1
12
12
12
12
12
12
1
9
1
1
1
1
1
1
12
12
35
35
35
35
14
14
14
14
14
14
14
14
35
35
35
35
56
56
15
15
15
15
15
15
15
15
56
56
56
56
56
56
50
50
50
50
50
50
50
50
Como se observa, al finalizar estos pasos, el elemento, cuyo valor sea menor, 1 en
nuestro ejemplo, acabará ocupando la última posición; utilizando un símil físico,
podemos decir que como elemento más ligero, sube hacia arriba, al igual que las
burbujas de aire en un depósito o botella de agua. Por esta razón este algoritmo se
conoce también como método de la burbuja.
Por tanto, en el caso de una ordenación descendente, a partir de un vector
cualquiera de N elementos, tras realizar un recorrido completo por todo el vector,
conseguimos que el menor de ellos, quede situado en la última posición, que es la
que le corresponderá, cuando el vector quede ordenado. En el segundo recorrido,
sólo será necesario abarcar a los N-1 elementos restantes, y en él el segundo valor
más pequeño llegará a la penúltima posición. Siguiendo de esta manera acabaremos
ordenando el vector, colocando en cada iteración, secuencialmente, un valor en su
posición definitiva.
Basándonos en la anterior, podemos proponer un algoritmo de ordenación basado
en dos etapas iterativas, una anidada dentro de la otra:
1ª etapa Dado un vector de N elementos Hacer el recorrido de la burbuja (ver
segunda etapa) primero para N elementos, luego para el subvector con los
N-1 primeros, luego para N-2, etc., hasta 2 elementos.
2ª etapa Recorrido de la burbuja: para los elementos a recorrer, comparar cada uno
con el siguiente e intercambiarlos si contravienen el orden requerido.
Mostrar la transformación del vector del ejemplo 2 de ordenación descendente, tras
dos ejecuciones del bucle interno (etapas o recorridos de la burbuja) del método de
intercambio3:
3
En el ejemplo podemos apreciar que tras dos iteraciones de la etapa externa el vector ya está ordenado y no haría
falta continuar con más recorridos, con el consiguiente ahorro de tiempo. La observación de este hecho permitiría
escribir un algoritmo de menor coste en el caso medio, aunque no en el peor caso..
254
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
estado
inicial
9
12
1
35
14
56
15
50
después de
1ª etapa
1
9
12
14
35
15
56
50
después de
2ª etapa
1
9
12
14
15
35
50
56
La etapa interna, en un primer diseño sería:
desde I=1 hasta R-1 hacer {siendo R el número de elementos a recorrer}
si A(I) < A(I+1) entonces intercambiar A(I) con A(I+1)
fin_desde
La acción intercambiar los valores de dos elementos A(I), A(I+1), es muy común y
al objeto de que no se pierda ningún valor, hay que reseñar que debe recurrirse a
una variable auxiliar, AUX, de forma que el procedimiento sería:
AUX← A(I)
A(I)← A(I+1)
A(I+1)← AUX
Estamos en condiciones de presentar el algoritmo completo, donde cada una de las
etapas viene representada por sendos bucles anidados. En esta ocasión, una vez
justificado el nombre de burbuja, vamos a ordenar de forma ascendente, esto es de
menor a mayor (la forma más habitual).
algoritmo burbuja
{ordenación ascendente}
inicio
desde I=1 hasta N hacer { lectura del vector}
leer X(I)
fin-desde
desde I=1 hasta N-1 hacer
desde J=1 hasta N-I hacer {no utilizamos los elementos ya ordenados}
si X(J) > X(J+1) entonces
{intercambiar}
AUX← X(J)
X(J) ←X(J+1)
La inclusión de la mejora correspondiente no se contempla en este texto y queda como un ejercicio para el lector
ALGORITMOS Y SU COMPLEJIDAD
255
X(J+1) ←AUX
fin-si
fin-desde
fin-desde
desde J = 1 hasta N hacer {imprimir vector ordenado}
escribir X(J)
fin-desde
fin
Para analizar la complejidad del algoritmo, vamos a considerar el número de
comparaciones que efectuamos. Como puede observarse el número de
comparaciones será el mismo para cualquier vector, sólo las asignaciones
cambiarán siendo en el peor caso tres por cada comparación, con lo que serán del
mismo orden de magnitud. Este método de ordenación, para un vector de n
elementos, precisa el siguiente numero de comparaciones (observando los valores
que toman los contadores I y J respectivamente):
(1 + 2 +
+ n-1) = (n -1) * (n/2)
Por tanto, estamos, de nuevo, con un algoritmo cuadrático, por lo que es interesante
que mejoremos su eficacia.
Ejemplo 3:
Describir los diferentes pasos para clasificar en orden ascendente el vector
siguiente por el método de la burbuja.
A(1)
72
A(2)
64
A(3)
50
A(4)
23
A(5)
84
A(6)
18
A(7)
37
A(8)
99
A(9)
45
A(10)
8
Las sucesivas operaciones en cada uno de los pasos necesarios hasta obtener la
clasificación final se muestra en la siguiente tabla, donde aparecen sombreados los
elementos que ya quedan ordenados y por tanto ya no se recorren:
A(1)
A(2)
A(3)
A(4)
A(5)
A(6)
vector 1 rec. 2 rec. 3 rec.
inicial i=1 i=2 i=3 i=4
72
64
50
23
23
64
50
23
50
18
50
23
64
18
37
23
72
18
37
50
84
18
37
64
45
18
37
72
45
8
i=5
18
23
37
49
8
50
i=6
18
23
37
8
41
50
i=7
18
23
8
37
41
50
Fin de
i=8 ordenación
18
8
8
18
23
23
37
37
41
41
50
50
256
A(7)
A(8)
A(9)
A(10)
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
37
99
45
8
84
45
8
99
45
8
84
99
8
72
84
99
64
72
84
99
64
72
84
99
64
72
84
99
64
72
84
99
64
72
84
99
64
72
84
99
90405" CNIQTKVOQ"FG"UJGNN
Tanto el método de inserción como de la burbuja son de orden cuadrático y en
consecuencia su tiempo de ejecución se dispara cuando el número de elementos a
ordenar es grande. Con el objetivo de mejorar ambas aproximaciones Donald Shell
propuso un nuevo método que lleva su nombre y que, sin mejorar la complejidad
en el peor caso, se comporta de forma sensiblemente más eficaz en la gran mayoría
de casos.
Shell cayó en la cuenta que en los métodos anteriores, el comparar cada elemento
con su contiguo supone, en promedio, ejecutar muchas comparaciones antes de
colocar los elementos extremos en su lugar definitivo. Su propuesta consiste en
modificar los saltos contiguos resultantes de las comparaciones, por saltos de
mayor tamaño y con ello conseguir una ordenación más rápida. El método se basa
en fijar el tamaño de los saltos constantes, pero de más de una posición.
Supongamos un vector de elementos
4
12
16
24
36
3
en el método de inserción directa, los saltos se hacen de una posición en una
posición y se necesitarán 5 comparaciones. En el método de Shell, si los saltos son
de dos posiciones, se realizarán tres comparaciones.
El método de Shell se basa en tomar como salto inicial el valor N/2 (siendo N el
número de elementos) y luego se va reduciendo a la mitad en cada repetición hasta
que el salto o distancia se reduce a 1. Por tanto habrá que manejar la variable salto,
de forma que los recorridos no serán los mismos en cada iteración.
Sea un vector: X(1), X(2), X(3),..., X(N). El primer salto a dar que tendrá un valor
de:
1+N
2
por lo que para redondear, se tomará la parte entera
1+N
2
ALGORITMOS Y SU COMPLEJIDAD
257
E = ent((1 + N)/2)
El algoritmo resultante será:
subalgoritmo Shell
inicio
E ← N+1
mientras E > 1
E ← ent(E/2)
repetir
ID ← verdadero
I←1
desde I = 1 hasta N-E
si X(I) > X(I+E) entonces
AUX ← X(I)
X(I) ← X(I+E)
X(I+E) ← AUX
ID ← falso
fin-si
fin-desde
hasta-que (ID = verdadero)
fin-mientras
fin
Ejemplo 4:
Deducir las secuencias parciales de clasificación por el método de Shell para
ordenar de modo ascendente el vector siguiente
6
1
5
2
3
4
0
Estas son:
Nº de Recorrido
vector inicial
1
2
3
4
5
Salto
3
3
3
1
1
vector resultante
6,1,5,2,3,4,0
2,1,4,0,3,5,6
0,1,4,2,3,5,6
0,1,4,2,3,5,6
0,1,2,3,4,5,6
0,1,2,3,4,5,6
intercambios
(6,2),(5,4),(6,0)
(2,0)
ninguno
(4,2),(4,3)
ninguno
258
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Aunque el análisis de la complejidad (que no haremos con detalle), nos
demostraría que para el peor caso, el algoritmo de Shell es cuadrático y no
mejoraría los algoritmos de ordenación anteriores (seguimos trabajando con dos
bucles anidados), como hemos dicho, en la práctica se puede comprobar que la
modificación propuesta por Shell supone una mejora importante para vectores no
especialmente desordenados.
90406" CNIQTKVOQ"FG"QTFGPCEKłP"TıRKFC"*›SWKEMUQTVfi+
Este nuevo método, de naturaleza recursiva, llamado ordenación rápida
(quicksort) propuesto por Hoare se basa en el hecho práctico de que es más rápido
y fácil de ordenar dos listas pequeñas que una lista grande. Se denomina de
ordenación rápida porque, en general, puede ordenar una lista de datos mucho más
rápidamente que cualquiera de los métodos de ordenación ya estudiados; de hecho,
se puede demostrar que su complejidad para el caso medio es O(n* log(n)).
El método es un ejemplo de la estrategia “divide y vencerás” de forma que el
vector inicial se divide en dos subvectores: uno con todos los valores, menores o
iguales a un cierto valor específico, llamado pivote, y otro con todos los valores
mayores que él. El valor elegido puede ser cualquier valor arbitrario dentro del
vector. El primer paso consiste en seleccionar el valor pivote y en dividir el vector
original V en dos partes:
• El subvector VI que sólo contiene valores inferiores o iguales al valor pivote
• El subvector VD que sólo contiene valores superior o iguales al valor pivote
Notemos que los subvectores VI y VD no estarán ordenados, excepto en el
caso de reducirse a un único elemento (obviamente ordenado), circunstancia ésta
que será especialmente útil.
Ejemplo 5:
Consideremos el siguiente vector y llevemos a cabo la anterior
descomposición de valores.
18
11
27
13
9
4
16
15
25
Se elige un valor pivote, por ejemplo 13. Se recorre la lista desde el extremo
izquierdo y se busca un elemento mayor que 13 (el primero es 18). A continuación,
se busca desde el extremo derecho un valor menor que 13 (se encuentra el 4). Se
intercambian estos dos valores y se obtiene:
ALGORITMOS Y SU COMPLEJIDAD
4
11
27
13
9
18
16
15
259
25
Se sigue recorriendo el vector por la izquierda y se localiza el 27, y a
continuación se busca por la derecha otro valor menor que el pivote, se encuentra a
la derecha (el 9); al intercambiar estos dos valores se obtiene:
4
11
9
13
27
18
16
15
25
Al intentar este proceso una vez más, nos encontramos con que la búsqueda
desde la izquierda de valores mayores que el pivote como la búsqueda desde la
derecha de valores menores que el pivote, acaban cruzándose, esto es, las
exploraciones desde los dos extremos acaban sin encontrar ningún valor que esté
“fuera de lugar”. Por tanto, lo que tenemos es que todos los valores a la derecha
son mayores que todos los valores a la izquierda del pivote. Por tanto, el objetivo
se ha alcanzado, ya que tenemos una partición del vector original en dos listas más
pequeñas:
4
11
9
[13]
27
18
16
15
25
Obsérvese que nadie nos garantiza que la situación anterior, donde el número de
valores por encima del pivote a su izquierda ha coincidido con el número de
valores menores que él a su derecha, se produzca para cualquier vector. Por ello el
algoritmo tiene que incluir algún mecanismo para que el propio pivote se sitúe en
su posición correcta.
Siguiendo con el ejemplo anterior, hemos conseguido que el elemento pivote tenga
valores menores delante y valores mayores detrás. Sin embargo, nos encontramos
con que ninguna de ambas listas a la izquierda y a la derecha están ordenadas; sin
embargo, basados en los resultados de la primera partición, se puede ordenar ahora
cada una de las dos partes de forma independiente. Esto es, debemos ordenar los
subvectores
4
27
11
18
9
16
15
25
para acabar con el vector totalmente ordenado.
Para un caso totalmente general, vamos a esbozar en primer lugar el método para
conseguir una partición del vector en VI -VD:
establecer como pivote X el valor de un elemento arbitrario de la lista
mientras la partición no se termina hacer
recorrer desde la izquierda y buscar un valor >= X
260
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
recorrer desde la derecha y buscar un valor <= X
si los valores están desordenados entonces intercambiar sus valores
fin-mientras
Si el vector es A, se deben considerar las sucesivas particiones que se van
generando, A(L),..., A(R), donde L y R representan los índices de los extremos
izquierdo y derecho del subvector que se está considerando. Para realizar el
recorrido de las sublistas se consideran las variables índices i y j. Normalmente se
supone que el valor pivote es conocido, sino es así, a falta de mejor criterio,
seleccionaremos como pivote el valor central del vector.
El siguiente algoritmo efectúa la partición de un vector A(L),...,A(R), basándose en
la elección de un pivote cuyo valor es X.
algoritmo partición
inicio
i←L
j←R
X← A((L+R)/2) {o cualquier otra elección de pivote}
mientras i <= j hacer
mientras A(i) < X hacer
i←i+1
fin-mientras
mientras A(j) > X hacer
j←j-1
fin-mientras
si i <= j
entonces
AUX ← A(i)
A(i) ← A(j)
A(j) ← AUX
i←i+1
j←j-1
fin-si
fin-mientras
fin
Obsérvese, que una vez ejecutado el algoritmo de partición, obtenemos dos
subvectores:
A(L) ... A(j) y
A(i) ... A(R)
que será preciso ordenar a continuación y por separado para ser unidos de nuevo en
un vector que contenga la totalidad de elementos ya ordenados.
ALGORITMOS Y SU COMPLEJIDAD
261
Ejemplo 6:
Utilizando el algoritmo de partición expuesto, dividir el siguiente vector de
enteros en dos subvectores.
50 30
20
80
90
70
95
85
10
15
75
25
Inicialmente i=L=1, j=R=12, X=70 (uno de los valores centrales)
50 30 20 80 90 70 95 85 10 15 75 25 i=1, j=12, X=70
se mueve i mientras A(i)<70, y se mueve j mientras A(j)>70
50 30
50 30
20
20
i=4
80 90
25 90
70
70
95
95
85
85
10
10
15
15
75
75
j=12
25 intercambio
80 i=5,j=11
como i<=j, vuelve a mover i mientras A(i)<70 y j mientras A(j)>70
50 30
50 30
20
20
25
25
i=5
90 70
15 70
95
95
85
85
10
10
j=10
15 75
90 75
80
80
intercambio
i=6,j=9
como aún i<=j, vuelve a mover i mientras A(i)<70 y j mientras A(j)>70
50 30
50 30
20
20
25
25
15
15
i=6
70 95
10 95
85
85
j=9
10 90
70 90
75
75
80
80
intercambio
i=7,j=8
como aún i<=j, luego vuelve a mover i mientras A(i)<70 y j mientras A(j)>70
y en esta ocasión el índice j pasa el 85, el 95 y se detiene en el 10 (i=6)
50 30
20
25
15
j=6 i=7
10 95 85
70
90
75
80
como no es cierto que sea i<=j entonces se acaban los bucles y hemos terminado
la partición, con dos subvectores que ordenar: el de L a j y el de i a R
[ 50 30
20
25
15
10 ] [ 95 85
70
90
75
80 ]
Nótese que el valor pivote no queda necesariamente en el centro ni en ningún sitio
específico.
262
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Como es fácil de prever, la generación sucesiva de subvectores, puede llegar a ser
un problema, así si en un paso se elige el subvector izquierdo y se deja el derecho
para más tarde, la particiones sucesivas nos complicarán la ordenación final. Un
medio para evitar esos problemas es utilizar una estructura de datos tipo pila, en la
que los datos se almacenan y recuperan por el mismo extremo.
El proceso comienza con un vector y se realiza la partición. Si el subvector derecho
tiene más de un elemento, éste se coloca en la pila y se prosigue con la partición
izquierda. Cuando se alcanza un punto en el que la partición izquierda tiene sólo un
elemento, tomamos una partición de la pila y se continúa como antes. Cuando no
existan particiones a sacar de la pila, la ordenación se ha terminado.
El algoritmo general será:
poner lista inicial en la pila
mientras haya particiones en la pila hacer
tomar partición de la cima de la pila {con forma de subvector: A(L) ... A(R)}
mientras exista más de un elemento en la partición hacer
partición
si existe más de un elemento en partición derecha
entonces poner partición derecha en la pila
fin-si
hacer partición izquierda de la lista
fin-mientras
fin-mientras
Aunque la naturaleza de este algoritmo es recursiva y hacia este objetivo nos
encaminamos, vamos a dar un algoritmo para su resolución iterativa utilizando una
pila implementada mediante un vector (en realidad se trata de dos pilas conjuntas)
que permite las siguientes acciones:
1.
{poner lista inicial en la pila}
P ← 1 {P, puntero de la pila}
SIzquierdo(P) ← 1
SDerecho(P) ← N
2.
{poner partición derecha en la pila}
P←P+1
SIzquierdo(P) ← i
SDerecho(P) ← R
ALGORITMOS Y SU COMPLEJIDAD
3.
{tomar una partición de la pila}
L ← SIzquierdo(P)
R ← SDerecho(P)
P←P-1
4.
{pila no vacía; hay particiones en la pila}
P>0
5.
{hacer partición izquierda de la lista}
R←j
6.
{hay más de un elemento en la partición}
L<R
El algoritmo rápido incluyendo partición y ordenación es el siguiente:
algoritmo OrdenacionRapida
inicio
P←1
SIzquierdo(1) ← 1
SDerecho(1) ← N
mientras P > 0 hacer
L ← SIzquierdo(P)
R ← SDerecho(P)
S←S-1
mientras L < R hacer
{partición de la lista}
i←L
j←R
X ← A((L + R)/2)
mientras i <= j hacer
mientras A(i) < X hacer
i←i+1
fin-mientras
mientras A(j) > X hacer
j←j-1
fin-mientras
si i <= j
entonces
AUX ← A(i)
A(i) ← A(j)
A(j) ← AUX
263
264
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
i←i+1
j←j-1
fin-si
fin-mientras
si i < R
entonces
P←P+1
SIzquierdo(P) ← i
SDerecho(P) ← R
fin-si
R←j
fin-mientras
fin-mientras
fin
Como puede verse el método de ordenación rápida por métodos iterativos es
enojoso y poco legible. La propia presentación que del algoritmo hemos hecho
(dividir sucesivamente un vector en dos mitades, hasta reducirlas a un solo
elemento) señala la utilización de la recursividad como método más apropiado. La
recursión se puede aplicar, ya que cada vez se aplica el mismo método de partición
o división a cada una de las subvectores. Se presentan dos problemas: 1) ¿Dónde se
detienen las particiones sucesivas? y 2) ¿Cómo se elige el pivote para cada
subvector? La primera respuesta, es cuando el subvector conste de un solo valor y
para la segunda vamos a recurrir a la idea , ya vista, de utilizar un término central
del vector como pivote.
Supongamos que contamos con un procedimiento OrdRápida (A, L, R), donde de
acuerdo con la notación seguida hasta ahora, A es un vector y L y R son
respectivamente el índice inferior y superior, del vector que se esta procesando en
cada momento. Para convencernos de las posibilidades de la recursividad ,
lancemos este procedimiento con el siguiente vector (L = 1 y R = 9):
9
22
32
16
20
18
12
14
26
Sublista izquierda
9
índices
i
14
12
...
16
Sublista derecha
18
20
j
i
32
22
...
26
n
ALGORITMOS Y SU COMPLEJIDAD
265
La ordenación de la parte izquierda implica el mismo procedimiento que en las
particiones. Por consiguiente, procesar el subvector izquierdo supone el mismo
procedimiento que antes, excepto que ahora: L = 1 y R = 5. La ordenación de la
parte derecha implica el mismo procedimiento que antes, excepto que L = 6 y R =
9. Los procedimientos de ordenación son:
OrdRapida (A, L, J)
OrdRapida (A, I, R)
El algoritmo resultante, se lista a continuación:
procedimiento OrdRapida(A: vector[1..n] de real, L y R:enteros)
var
i,j,Central,Aux: entero
inicio
i←L
j←R
Central ← A[(L + R) div 2] {división entera}
repetir
mientras A[i] < Central hacer
i ← i +1
fin-mientras
mientras A[j] > Central hacer
j←j-1
fin-mientras
si i <= j
entonces
Aux ← A[i]
A[i] ← A[j]
A[j] ← Aux
i←i+1
j←j-1
fin-si
hasta-que i > j
{proceso de subvector izquierdo}
si L < j entonces llamar_a OrdRapida (A, L, j)
{proceso de subvector derecho}
si i < R entonces llamar_a OrdRapida (A, i, R)
fin {procedimiento OrdenarRapido}
266
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
La utilización de este procedimiento desde un programa para ordenar un vector V
con n elementos se hará indicando que deseamos ordenar todo el vector, así
llamar_a OrdRapida(V, 1, n)
Aunque en el caso peor el algoritmo de ordenación rápida tiene orden de
complejidad cuadrático, su nombre se debe a que en el caso medio su
comportamiento es sensiblemente mejor que el de los métodos anteriores. Como
ejemplo, dada una colección arbitraria de vectores de 100 elementos, el numero
medio de comparaciones que utiliza el algoritmo de inserción es 2475, mientras
que por ordenación rápida esta cantidad es de alrededor de 700.
9050" GXCNWCEKłP"FG"WP"RQNKPQOKQ
El cálculo del valor que toma un polinomio en un punto es una tarea muy
frecuente, y que en muchas ocasiones debe hacerse de multitud de veces en un
mismo programa. Por ello es importante disponer de un algoritmo eficiente.
90503" GXCNWCEKłP"FKTGEVC
Supondremos que los coeficientes del polinomio P(x) =
n
∑a x
i =0
i
i
los tenemos
almacenados en el vector a(0),...a(n), y queremos calcular el valor del polinomio en
el punto dado x. El primer algoritmo para resolver el problema se basa en su
cálculo directo, calculando cada término en ai xi y sumándolos
algoritmo polinomio1
inicio
P←a(0)
desde j=1 hasta n hacer
pot←x
desde i = 2 hasta j
pot←pot * x
fin-desde
P←P+a(j)*pot
fin desde
fin
A pesar de su aparente simplicidad (es una implantación directa de la función
polinómica) este algoritmo presenta un coste elevado, ya que la presencia de dos
ALGORITMOS Y SU COMPLEJIDAD
267
bucles anidados, lo convierte en un algoritmo cuadrático, en función del numero de
coeficientes. Además, al tratarse de un problema númerico, no podemos despreciar
la generación de errores de redondeo que inevitablemente se producen, al efectuar
un numero elevado de operaciones aritméticas.
90504" CNIQTKVOQ"FG"JQTPGT
Afortunadamente, el calculo de la potencia en cada paso del bucle del
algoritmo anterior se puede evitar, si recordamos que la escritura de un polinomio
se puede hacer de la siguiente forma:
P(x) = a0 + a1x + a2x2 + ... + anxn = (...(((anx + an-1)x + an-2) x + an-3)... + a1)x + a0
Ejemplo 7:
Dado el polinomio: P(x) = 3x3+ 2x2 + 4x + 5 calcular su valor para x = 2, de la
manera expuesta.
Esto significa hacer las siguientes operaciones:
3
x 2)
P
3
2
6
8
4
16
20
5
40
45
De acuerdo con estos cálculos, P(3) = 45. Esta forma de evaluar el polinomio se
conoce como método de Horner, y su algoritmo correspondiente se reduce a un
solo bucle:
incio
P←a(n)
desde j=n-1 hasta 0 hacer
P←P*x+a(i)
fin-desde
fin
Este algoritmo es lineal ya que solo requiere n multiplicaciones, n sumas y n+1
asignaciones.
268
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
90505" OÖVQFQ"FGN"ıTDQN
Aunque puede demostrarse que el método de Horner es óptimo con respecto
al número de operaciones, al objeto de insistir en la variedad de métodos que
existen para resolver un mismo problema, vamos a presentar otra forma de resolver
el problema, basada en el “divide y vencerás” que si bien no es estrictamente mejor
que el método de Horner para obtener el valor de un polinomio, puede superarlo en
ciertos casos (p.e. cuando esta evaluación se tiene que hacer simultáneamente sobre
un conjunto de puntos). Este método se basa en que todo polinomio se puede
expresar separando los términos de potencia par e impar de la siguiente forma:
P(x) = a0 + a1x + a2x2 + ... + anxn = (a0 + a2x2 + a4x4 +...) + (a1x + a3x3 + a5x5 +...)=
donde w= x2
= Q(x2)+xR(x2) =Q(w)+xR(w),
De esta manera, el problema de evaluar un polinomio de grado n, se ha
transformado en evaluar dos polinomios de grado n/2, los polinomios Q y R. Si
suponemos, sin pérdida de generalidad, que el polinomio inicial tiene un número de
coeficientes que es potencia de dos4 (n=2k-1), el procedimiento anterior lo
podemos aplicar recursivamente k veces, hasta conseguir que los polinomios
generados en el último paso, sean de grado cero (o sea, queden reducidos a los
coeficientes del polinomio). Representando los sucesivos polinomios sólo por sus
coeficientes, este proceso lo podemos representar por un árbol binario, como se
muestra en el siguiente diagrama:
(a 0 , a1 , a 2 , a 3 , a 4 , a 5 , a 6 , a 7 , a8 , a 9 , a10 , a11 , a12 , a13 , a14 , a15 )
(a 0 , a 2 , a 4 , a 6 , a8 , a10 , a12 , a14 )
(a1 , a 3 , a5 , a 7 , a 9 , a11 , a13 , a15 )
Nivel 0
Nivel 1
(a 0 , a 4 , a8 , a12 ) (a 2 , a 6 , a10 , a14 ) (a1 , a5 , a 9 , a13 ) (a3 , a7 , a11 , a15 )
Nivel 2
(a0 , a8 ) (a4 , a12 ) (a2 , a10 ) (a6 , a14 ) (a1 , a9 ) (a5 , a13 ) (a3 , a11 ) (a7 , a15 )
Nivel 3
4
Si no es potencia de dos, pueden considerarse como cero los coeficientes que falten hasta la potencia de dos más
cercana, y se puede aplicar el método.
ALGORITMOS Y SU COMPLEJIDAD
a 0 a 8 a 4 a 12 a 2 a 10 a 6 a 14 a 1 a 9 a 5 a 1 a 3 a 11 a 7 a 15
269
Nivel 4
Para evaluar el valor de un polinomio en un punto, basta con que evaluemos cada
nodo del árbol, desde las hojas a la raíz (bottom-up), de la siguiente forma:
Valor(nodo)=Valor(hijo_izquierdo(nodo))+Z*Valor(hijo_derecho(nodo)),
donde Z=X2Nivel(nodo)
Obsérvese que en el ejemplo dado se han de evaluar 15 nodos, y cada evaluación
implica una asignación, una suma y una multiplicación. Por tanto este método es
comparable en complejidad computacional al de Horner, salvo en dos cosas: La
primera es que se necesitan tres multiplicaciones para generar x2, x4 y x8 y la
segunda y más importante, es que hay que disponer los coeficientes del polinomio
en el orden presentado en el Nivel 4.
Vamos a ilustrar con un ejemplo concreto la ventaja que puede suponer este
método respecto al de Horner
Ejemplo 8:
Calcular el valor que toma en el punto x=2 el polinomio utilizando el método del
árbol
P(X) = 1-2x+3x2-4x3+5x4-6x5+7x6-8x7+9x8-10x9+11x10-12x11+13x12-14x13-15x1416x15
1 9
5 13
3 11
7 15
-2 -10 -6 -14 -4 -12 -8 -16
2305
3333
2819
3847
-2562
55633
64371
-3590
-3076
-60002
313117
-68740
-334962
-356807
-4104 Z=256
Z=16
Z=4
Z=2
270
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Si quisiéramos calcular el valor del polinomio en el punto x= -2, sólo tenemos que
hacer:
P(-2)= 313117+2*334962= 983041
dado que el cuadrado de 2 y -2 coinciden. Si quisiéramos calcular el valor del
polinomio también en los puntos 2i y - 2i , sólo necesitamos hacer 4
multiplicaciones y 4 sumas:
55633
64371
-60002
-201851
-68740
Z=16
214958
Z= -4
P(2i)= -201851+214958i
P(-2i)= -201851-214958i
Z= 2i
Z= -2i
Sin embargo, para calcular P(-2), P(2i) y P(-2i) por el método de Horner,
tendríamos que haber empezado desde el principio. Por consiguiente, este método
puede ser más conveniente que el de Horner, si necesitamos evaluar el polinomio
en varios puntos y coinciden sus cuadrados, ó potencias cuartas, etc...
Queda pendiente el problema de distribuir los coeficientes según el orden que
figura en las hojas del árbol, pero esto es sencillo si observamos lo que ocurre en el
ejemplo visto, del polinomio de grado 16, donde el subíndice de los coeficientes
que en la siguiente figura están entre una caja y otra, es igual -en el mismo ordenque el de los subíndices de las cajas inferiores más dos elevado a la diferencia entre
N y el número de cajas exteriores (siendo N el grado del polinomio más uno):
a0
a8
a4
a12
a2
a10
a6
a14
a1
a9
a5 a13
a3 a11
a7 a15
Un algoritmo para generar un vector que contenga los subíndices en el orden
adecuado, es pues el siguiente:
P(0)←0
C←N
K←1
mientras k<>N hacer
ALGORITMOS Y SU COMPLEJIDAD
271
C←C/2
desde j=k hasta 2*k-1 hacer
P(j) ←P(j-k)+C
fin-desde
k←k*2
fin-mientras
Como podemos observar la variedad de algoritmos, para resolver un tema tan
aparentemente sencillo como éste, es realmente llamativa y esta es una
circunstancia que no puede ni debe ser ignorada durante el proceso de
programación.
9060" CNIQTKVOQU"RCTC"NC"DðUSWGFC"FG"ECFGPCU
FG"ECTCEVGTGU
Hemos abordado la búsqueda de una determinada información en un entorno
ordenado, estudiando diversos algoritmos y observando como todos ellos sacaban
provecho de este orden ya establecido para hacer una búsqueda eficiente. Sin
embargo, en ocasiones es necesario buscar en un entorno en el que no se ha
producido previamente una ordenación, y en el que además no se busca una
coincidencia exacta, sino que se busca que en qué posición aparece un determinado
patrón (o bien si aparece o no). Ejemplos de tales situaciones se producen en un
procesador de textos cuando buscamos una palabra o parte de ella, y en algunos
sistema operativos, que permiten buscar en qué ficheros aparece una determinada
secuencia de caracteres, sin olvidar su uso en programación cuando trabajamos con
variables de cadena. Esta es una tarea tan importante que en casi todos los casos
anteriores se suelen suministrar órdenes o instrucciones que la realizan. Vamos a
estudiar algoritmos para buscar una secuencia de caracteres en un cadena,
obteniendo el lugar a partir del cual aparece esta subcadena o bien un cero si no
existe tal secuencia.
90603" CNIQTKVOQ"FG"EQORCTCEKłP
El algoritmo más directo, y que de hecho se empleó durante tiempo hasta
obtener uno mejor, consiste en comparar el primer carácter de la cadena con el
primero de la secuencia; si coinciden se pasa analizar el segundo, si coinciden el
tercero y así sucesivamente hasta que o coincide el último de la secuencia
(momento en el cual acaba la búsqueda) o se encuentra un carácter distinto,
momento en el cual se pasa a comparar el segundo carácter de la cadena con el
primero de la secuencia; si hay coincidencia se comparan el tercero con el segundo,
y así sucesivamente.
272
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Ejemplo 9:
Veamos un ejemplo de este algoritmo para localizar “trigales” en un texto que
comienza por “tres tristes tigres comieron trigo en unos trigales...”:
TRES_TRISTES_TIGRES_COMIERON_TRIGO_EN_UNOS_TRIGALES ...
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
TRIGALES
En negrita se han puesto las comparaciones con resultado exitoso, y subrayadas las
que resultan fallidas. Como puede observarse, se han de hacer 53 comparaciones
para llegar a encontrar la solución y 8 más para comprobar que es ésta. En el peor
caso la complejidad del algoritmo es del orden del producto de las longitudes de las
cadenas, no obstante en la práctica este peor caso no se suele presentar, dado que
este implica buscar en una cadena del tipo “aaaaaaaaaaa...b” un patrón del tipo
“aaaaa...b”, lo que afortunadamente no es muy habitual. Esta complejidad lineal
con el tamaño de la cadena larga, resulta absolutamente ineficiente cuando se ha de
emplear para buscar entre cantidades de información cercanas o superiores al orden
de Mbytes. Por ello resulta fundamental obtener algoritmos más eficientes.
El algoritmo correspondiente, lo podemos representar como sigue:
función posición(cadena_corta, cadena_larga):número
N←longitud(cadena_corta)
ALGORITMOS Y SU COMPLEJIDAD
273
M←longitud(cadena_larga)
j←1
k←1
mientras (j ≤ N) y (k ≤ M) hacer
si cadena_corta(j)=cadena_larga(k)
entonces
j←j+1
k←k+1
si_no
k←k-j+2
j←1
fin-si
fin_mientras
si j=N+1
entonces
posición←k-j+1
si_no
posición←0
fin-si
fin-funcion.
90604" CNIQTKVOQ"FG"DQ[GT/OQQTG
Partamos de la idea de ir avanzando sobre la cadena larga, pero haciendo las
comparaciones con la secuencia en sentido inverso, esto es, desde su último
carácter al primero. Así, si la longitud de la secuencia es N, se compara el carácter
N-ésimo de la cadena larga, con el último de la secuencia, si coinciden se pasa a
analizar el anterior y así sucesivamente hasta que coincida la subcadena completa o
hasta que encontremos un carácter distinto. En este caso la secuencia no se
“desliza” un lugar sobre la cadena, sino que se desliza hasta el carácter de la
secuencia que coincide con el carácter distinto, antes encontrado. Caso de no existir
este carácter en la secuencia, ésta se deslizaría totalmente empezando el nuevo
proceso a partir de esta posición.
Ejemplo 10:
Aplicar el algoritmo de Boyer-Moore para el caso en que la cadena
cadena_larga=“campanarios” (M=11) y la secuencia, cadena_corta=“rios” (N = 4).
274
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
En primer lugar se compararía la cuarta letra de la secuencia larga, “p”, con la
última letra de la secuencia, “s”. Al ser distintas, y además la “p” no aparecer en la
secuencia, se intenta buscar la secuencia a continuación de la “p”. Para ello
consideraríamos la cuarta letra, a partir de la “p”, esto es la “r”, para compararla de
nuevo con la “s”, resultando también ser distintas. Sin embargo, ahora si la “r”
aparece en la secuencia, por lo que se pondría las dos “r” alineadas y a partir de
ellas, las comparaciones, letra a letra, resultarán ciertas. Veamos este algoritmo
aplicado al ejemplo anterior (M = 51 y N = 8):
TRES_TRISTES_TIGRES_COMIERON_TRIGO_EN_UNOS_TRIGALES...
TRIGALES (I ⇒ hace avanzar 5)
TRIGALES (_ ⇒ 8)
TRIGALES (C ⇒ 8)
TRIGALES (_ ⇒ 8)
TRIGALES(N ⇒ 8)
TRIGALES (R ⇒ 6)
TRIGALES
Como puede observarse en este caso sólo han sido necesarias 6
comparaciones para llegar a encontrar la solución y 8 más, para comprobar que es
ésta, por lo que la mejora de este algoritmo es más que notable. Con este método, si
la cadena tiene M caracteres y la secuencia N, en la práctica se han de hacer
alrededor de M/N comparaciones hasta encontrar la solución.
La formulación del algoritmo correspondiente exige que podamos definir la
cantidad de caracteres que se tiene que deslizar la secuencia para cada posible
carácter de la cadena. Esto es fácil de hacer utilizando un vector cuyos índices se
correspondan con dichos caracteres, como se muestra a continuación:
Algoritmo avanza(texto:cadena; var incr:vector);
inicio
N←longitud(texto)
desde letra='_' hasta 'z' hacer
incr[letra]←N
fin-desde
desde i=1 hasta N hacer
incr[texto[i]]←N-i
fin-desde
fin
Por motivos de simplicidad, en el algoritmo anterior estamos usando la posibilidad
de utilizar los caracteres como índices, cosa que no todos los lenguajes de
programación soportan, sin embargo siempre es posible convertir un carácter a un
numero y utilizarlo como índice (Recuérdese que en ASCII, los caracteres
especiales y alfanuméricos van desde el carácter blanco, de valor decimal 32, hasta
ALGORITMOS Y SU COMPLEJIDAD
275
z de valor decimal 122). Así el vector incr es del tipo array[alfabeto] de enteros,
siendo alfabeto = '_'.....'z'.
El algoritmo final de búsqueda de secuencias de Boyer- Moore es:
función busca(texto1,texto2:cadena):entero
inicio
M ← longitud(texto2)
N ← longitud(texto1)
i←N
j←N
avanza(texto1,incrementa);
mientras (i<=M) y (j>0) hacer
si texto1[j]=texto2[i]
entonces
i ← i-1
j ← j-1;
si_no
j←N
i ← i+incrementa[texto2[i]];
fin-si
fin_mientras
si j=0
entonces
busca ← i+1
si_no
busca ← 0
fin-si
fin-función.
9070" PQVCU"HKPCNGU"UQDTG"EQORNGLKFCF
90703" CNIQTKVOQU"PQ/FGVGTOKPKUVCU
El concepto de algoritmo que hemos manejado hasta el momento, implica que
el resultado de cualquiera de sus operaciones está definido de forma única, y por
tanto distintas ejecuciones del mismo producen el mismo resultado. Estos
algoritmos están perfectamente adaptados para su codificación en un lenguaje de
alto nivel y su ejecución en un computador. Sin embargo, podemos extender el
concepto de algoritmo para permitir que el resultado de un paso no esté
determinado de forma única, sino que tenga un conjunto calculable de posibles
276
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
elecciones. Estos algoritmos se conocen como no-deterministas, y los utilizamos
frecuentemente:
• Cuando vamos de un punto a otro de la ciudad, no siempre seguimos el mismo
camino, y esto es porque las distintas calles a seguir las elegimos de forma no
determinista.
• El método que utilizamos cada uno para jugar al ajedrez. Ante la imposibilidad
de analizar todas las posibles jugadas y quedarnos con la más ventajosa (lo que
daría un algoritmo determinista), nosotros elegimos algunas de las posibles para
analizar, de forma no determinista (de hecho ante una misma disposición de
piezas, podríamos dar respuestas distintas en distintas partidas).
Por tanto, un algoritmo no-determinista debe tener al menos un paso en el que se
genere una posible hipótesis de solución del problema, y debe contener algún
método que le permita comprobar si esta hipotética solución se confirma como tal
solución del problema (momento en el cual acaba con éxito el algoritmo) o si por el
contrario no lo es (acabando con un fallo, tras lo cual se podría volver a intentar
aplicar el algoritmo). Por ello, los algoritmos no-deterministas se consideran
basados en el paradigma de programación conocido como “generación y prueba”
(generate and test)5 y su complejidad tiene que ser analizada de diferente forma a
como lo hemos hecho en el caso determinista, ya que si intentamos aplicar la
misma definición nos encontramos con el problema de que el concepto de número
de operaciones elementales requeridas para alcanzar una solución no es
directamente trasladable a los algoritmos no-deterministas, puesto que no siempre
realizan el mismo numero de pasos con los mismos datos iniciales. La definición
de la función f(n) para estos algoritmos es la siguiente: dado un problema de
tamaño n, f(n) es el mínimo número de operaciones elementales requerido para
alcanzar la solución del problema, si existe la sucesión de elección de hipótesis que
llevan a ella.
90704" RTQDNGOCU"FG"ENCUG"R"["PR
Para muchos de los problemas prácticos, desgraciadamente, no se conoce un
algoritmo polinomial que los resuelva, es más hay muchos de ellos en los que el
mejor algoritmo (determinista) conocido, tiene una complejidad exponencial. Sin
embargo es posible encontrar un algoritmo no-determinista que tenga complejidad
polinomial, y que en muchos casos lo hace resoluble a efectos prácticos. Ello ha
llevado a definir dos clases de problemas: los de la clase “P” (para los que existe
un algoritmo determinista de complejidad Polinomial) y los de la clase “NP” (para
5
Pensemos sólo en algoritmos de decisión no-deterministas, que son aquellos que pueden dar una respuesta sí o no
(exito o fallo) a un determinado problema.
ALGORITMOS Y SU COMPLEJIDAD
277
los que existe un algoritmo No-determinista de complejidad Polinomial)6, o
abreviadamente también se habla de problemas P y problemas NP. Dado que si un
problema está en P, existe un algoritmo determinista de complejidad polinomial
que lo resuelve, a partir de este algoritmo se puede generar uno no-determinista que
también tenga complejidad polinomial, simplemente tomando como método de
generación de hipótesis el resultado de la aplicación del algoritmo determinista. Por
tanto podemos afirmar que la clase P está incluida en la clase NP.
A la luz de la tabla 7.1, queda claro que es de gran importancia para establecer la
computabilidad de un problema distinguir si está en P o es NP pero no está en P
(Dado que en el primer caso se puede resolver en un tiempo “razonable” y en el
segundo resultaría intratable). Sin embargo, hasta el momento nadie ha sido capaz
de demostrar que las clases P y NP sean distintas (o sea, nadie ha podido encontrar
un problema que esté en NP-P, o bien demostrar que esto es imposible), siendo uno
de los grandes problemas que quedan abiertos.
Como conclusión, queda la idea de que con el computador no todos los problemas
son abordables y por tanto, cada vez que nos planteemos un algoritmo, sea de la
clase que sea, lo primero a considerar son sus posibilidades reales de ser resuelto a
través de un programa de computador, ya que por mucho que mejore la tecnología
en el futuro, la naturaleza de la solución propuesta la puede hacer no computable.
90705" KPVTQFWEEKłP"C"NCU"OCSWKPCU"FG"VWTKPI"["C"NQU
RTQDNGOCU"CNIQTKVOKECOGPVG"KTTGUQNWDNGU
Hasta este momento hemos tratado problemas para los que existe un algoritmo
(sea determinista o no) que los resuelve, aunque como hemos visto esa solución sea
en muchos casos inviable en la práctica por el desmesurado tiempo de computación
requerido. Sin embargo, no hemos abordado hasta ahora si para cualquier problema
podemos encontrar un algoritmo que lo resuelva, o si por lo contrario, hay
problemas que no son resolubles algorítmicamente. Esta motivación llevó a Alan
Turing en 1936 (como puede observarse antes de que existiesen los computadores
en su concepción actual, y antes de que existiese el concepto de lenguaje de
programación) a definir una herramienta teórica, conocida como máquina de
Turing, que le permitiera analizar las limitaciones de los algoritmos.
Una máquina de Turing está compuesta por una unidad de control de estados
finitos y una cinta, que se supone dividida en tramos, e infinita en ambas
direcciones. Cada tramo contiene un símbolo perteneciente a un alfabeto finito
prefijado. La comunicación entre la unidad de control y la cinta está permitida sólo
a través de una cabeza de lectura/escritura que es capaz de leer símbolos de la cinta
6
Por extensión, se habla de algoritmos P y algoritmos NP.
278
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
y escribirlos, así como de moverse en ambas direcciones a un tramo de la cinta
adyacente al actual. La unidad de control opera en pasos discretos, y en cada paso
sus acciones dependen del estado en el que esté y del último símbolo leído de la
cinta (ver Figura 7.4).
Figura 7.4 Representación de una Máquina de Turing
Para definir una máquina de Turing, además de los símbolos del alfabeto y los
posibles estados, es necesario definir, para cualquier combinación de estado actual
y cualquier símbolo leído, tres valores:
1. El estado siguiente que corresponde a esa combinación.
2. El símbolo a escribir en la cinta, correspondiente a esa combinación.
3. El movimiento de la cinta que corresponde a esa combinación. Este
movimiento sólo puede tomar tres valores: quedarse en el tramo actual,
moverse al tramo adyacente derecho y moverse al tramo adyacente
izquierdo.
La máquina comienza a funcionar cuando se pone en un determinado estado que
llamaremos “arranque” y se para al alcanzar un estado que llamaremos “parada”
(no tiene por qué ser único). El funcionamiento de la máquina se rige por el
siguiente ciclo:
Paso 1: La máquina lee un símbolo de la cinta, si no está en un estado de
parada.
Paso 2: Dado el estado actual y el símbolo leído, escribe en la cinta el
símbolo correspondiente a esa combinación.
Paso 3: Dado el estado actual y el símbolo leído, pasa al nuevo estado
correspondiente a esa combinación.
ALGORITMOS Y SU COMPLEJIDAD
279
Paso 4: Dado el estado actual y el símbolo leído, mueve la cabeza de
lectura según el movimiento correspondiente a esa combinación, y
vuelve al paso 1.
Como puede observarse hay una gran similaridad en la arquitectura y en la forma
de trabajar entre un computador y una máquina de Turing, si bien este dispositivo
teórico supone una simplificación respecto a un computador. Así, la unidad de
control de estados finitos desempeña el papel de la CPU, y la cinta el papel de la
memoria RAM en la que se guardan los datos (se supone que inicialmente hay un
conjunto finito de símbolos puestos sobre la cinta, estando el resto de la cinta “en
blanco”). Por otra parte, un programa para una máquina de Turing, viene
determinado por los tres valores correspondientes a cada combinación estado actual
/ símbolo leído, que como podrá observarse en el siguiente ejemplo permite
representar algoritmos (evidentemente con una adecuada elección de estados y del
alfabeto a utilizar).
Ejemplo 11:
Definir una máquina de Turing que detecte si un número binario tiene ceros
sobrantes al principio del número, y que en este caso los borre. Se supone que cada
dígito está en un tramo de la cinta, de forma consecutiva, y que el cabezal de
lectura está situado en el espacio anterior al último dígito (el menos significativo
del número), posición en la que el programa debe dejarlo al finalizar.
En este problema el alfabeto será {0,1,b}, donde 0 representa el número cero, 1 el
número 1 y b blanco en la cinta. Los estados a definir pueden ser estos ocho, que se
pueden interpretar de la forma siguiente:
Ar:
qo:
q1:
q2:
q3:
q4:
Si:
No:
estado en el que se encuentra el programa al inicio
“ir a la izquierda hasta encontrar el primer dígito del número”
“mirar primer dígito”
“seguir borrando”
“ir a la posición inicial, sabiendo que no se han borrado dígitos”
“ir a la posición inicial, sabiendo que se han borrado dígitos”
“Si que sobran dígitos”
“No sobran dígitos”
El estado inicial o de arranque es el “Ar” y los estados “Si” y “No” se consideran
como estados de parada, cada uno de ellos dando la respuesta correspondiente. El
“programa” que completa la definición de la máquina de Turing para este ejemplo,
viene dado por la siguiente tabla:
280
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Estado
Actual
Ar
qo
qo
qo
q1
q1
q1
q2
q2
q2
q3
q3
q3
q4
q4
q4
Símbolo Valor a Nuevo
leído
escribir estado
b
b
qo
0
0
qo
1
1
qo
b
b
q1
0
b
q2
1
1
q3
b
b
No
0
b
q2
1
1
q4
b
b
Si
0
0
q3
1
1
q3
b
b
No
0
0
q4
1
1
q4
b
b
Si
Movimiento
Izquierda
Izquierda
Izquierda
Derecha
Derecha
Derecha
No_mover
Derecha
Derecha
No_mover
Derecha
Derecha
No_mover
Derecha
Derecha
No_mover
En la página siguiente podemos seguir el resultado de aplicar esta máquina de
Turing a distintos datos de entrada.
Como puede observarse con la evolución del cabezal, de los estados y del
contenido de la cinta, el diseño de un programa con una máquina de Turing se
asemeja mucho al de un algoritmo, si bien en la máquina de Turing disponemos de
instrucciones mucho más elementales de las que estamos acostumbrados a manejar,
lo cual hace más complejo el trabajo de construcción del algoritmo. Sin embargo,
con una máquina de Turing es posible realizar tareas mucho más complicadas que
las del ejemplo expuesto, y existen estudios de cómo una máquina de Turing puede
realizar los trabajos que hace un computador en su concepción actual.
ALGORITMOS Y SU COMPLEJIDAD
Caso 1: número 00010
Caso 2: número 01010
281
Caso 3: número 1001
282
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
El gran resultado de Turing se basa en la conjetura (conocida como Tesis de
Church) de que la potencia computacional de la máquina de Turing es al menos
como la de los algoritmos (y por tanto todo problema que no pueda resolverse con
la máquina de Turing tampoco tendrá solución algorítmica). Más concretamente,
Turing demostró que existen problemas que no tienen solución con su máquina. Su
resultado se basa en el problema conocido como “problema de parada de una
máquina de Turing”, cuyo enunciado es el siguiente:
Problema de Parada de la Máquina de Turing:
Dada una máquina de Turing M y una cinta C, ¿puede definirse una
máquina de Turing que decida si la máquina M parará al procesar la
cinta C?
Al demostrar que ello no es posible, Turing sentó las bases para demostrar que
otros problemas tampoco tienen solución algorítmica7 (o empleando otras
terminologías también se dice que son irresolubles o que no son decidibles, dado
que no se puede contestar ni que sí, ni que no). La técnica empleada se basa en
reducir estos problemas al problema de parada de una máquina de Turing, y ha sido
utilizada para demostrar la irresolubilidad de otros problemas como sería el caso de
cuestiones sobre gramáticas en teoría de lenguajes, de teselamiento del plano en
geometria (dada una figura, saber si es posible construir un mosaico sobre una
superficie dada), de decidibilidad del cálculo de predicados de primer orden en
lógica, etc.
7
Este resultado, con lo expuesto hasta este momento, sólo es extensible a algoritmos deterministas; sin embargo,
es fácil definir una máquina de Turing no-determinista que capture el concepto de algoritmo no-determinista, y se
puede demostrar que estas máquinas son equivalentes, al poderse transformar una en la otra, con un algoritmo de
complejidad polinomial. Por tanto, los resultados sobre irresolubilidad son también extensibles a los algoritmos
no-deterministas.
ALGORITMOS Y SU COMPLEJIDAD
283
7.1. MEDIDA DE LA EFICIENCIA Y DE LA COMPLEJIDAD
ALGORITMICA.................................................................................................245
7.1.1 ORDEN DE COMPLEJIDAD .............................................................................247
7.1.2 ANÁLISIS DE COMPLEJIDAD DE LOS ALGORITMOS DE BÚSQUEDA ................249
7.2. ALGORITMOS DE ORDENACIÓN Y SU COMPLEJIDAD ................249
7.2.1 ORDENACIÓN POR INSERCIÓN ......................................................................250
7.2.2 ORDENACIÓN POR INTERCAMBIO .................................................................252
7.2.3 ALGORITMO DE SHELL .................................................................................256
7.2.4 ALGORITMO DE ORDENACIÓN RÁPIDA (“QUICKSORT”) ...............................258
7.3. EVALUACIÓN DE UN POLINOMIO ......................................................266
7.3.1 EVALUACIÓN DIRECTA .................................................................................266
7.3.2 ALGORITMO DE HORNER ..............................................................................267
7.3.3 MÉTODO DEL ÁRBOL ....................................................................................268
7.4. ALGORITMOS PARA LA BÚSQUEDA DE CADENAS DE
CARACTERES ...................................................................................................271
7.4.1 ALGORITMO DE COMPARACIÓN....................................................................271
7.4.2 ALGORITMO DE BOYER-MOORE ..................................................................273
7.5. NOTAS FINALES SOBRE COMPLEJIDAD...........................................275
7.5.1 ALGORITMOS NO-DETERMINISTAS....................................................275
7.5.2 PROBLEMAS DE CLASE P Y NP.............................................................276
7.5.3 INTRODUCCION A LAS MAQUINAS DE TURING Y A LOS
PROBLEMAS ALGORITMICAMENTE IRRESOLUBLES ..............................277
ANEXO
SOPORTE FÍSICO DE UN COMPUTADOR
Aunque no sea inmediato identificar los elementos físicos que constituyen un
computador en cada uno de estos tipos, a lo largo de este apéndice vamos a
exponer algunos de ellos, así como algunos procesos básicos y principios de
organización de los componentes de un computador. Las siguientes no pretenden
ser definiciones conceptuales ni relaciones exhaustivas, sino ampliaciones o
sugerencias surgidas a raíz de cada término. En primer lugar se presenta un grupo
de términos relacionados con la arquitectura u organización de los computadores,
para después incluir dos grupos de epígrafes adicionales: uno sobre periféricos de
los computadores y otro sobre redes y conexiones de computadores.
CTSWKVGEVWTC"FG"EQORWVCFQTGU
Dwu"fg"fcvqu
El bus de datos es una vía eléctrica de acceso que conecta la CPU, la memoria y
otros dispositivos de hardware en la tarjeta principal. De hecho, el bus es un grupo
de líneas paralelas. El número de líneas en el bus afecta la velocidad de los datos al
viajar entre los componentes de hardware, así como el número de carriles en una
carretera afectan el tiempo que le toma a la gente llegar a su destinos. Como cada
alambre puede transferir un bit a la vez, un bus de ocho alambres puede mover
ocho bits a la vez, que es un byte completo. Un bus de 16 bits pude transferir dos
bytes, y un bus de 32 bits puede transferir cuatro bytes a la vez.
Los buses de PC están diseñados para corresponder a las capacidades de los
dispositivos conectados a ellos. Así que cuando las CPU podían enviar y recibir
únicamente un byte de datos a la vez, no tenía mucho sentido conectarlas a un bus
que pudiera mover más datos que esos. Conforme mejoró la tecnología de los
microprocesadores, se construyeron chips que podían enviar y recibir más datos a
la vez, y los diseños de bus permitieron una vía de acceso más amplia a través de la
cual podían fluir los datos.
Cuando IBM introdujo la PC-AT, una de las mejoras más sobresalientes fue un
bus de datos más amplio que correspondía a las capacidades de un nuevo
microprocesador, el Intel 80286. El bus de datos de la AT era de 16 bits y se
convirtió en un estándar de facto en la industria que todavía se usa extensamente.
El bus de la AT es también llamado bus de Arquitectura Estándar de la Industria
(ISA).
285
286
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Existen otras dos arquitecturas de bus. Cuando IBM empezó primero a usar las
CPU que podían aprovechar un bus de 32 bits, sus computadoras incorporaron otra
nueva tecnología de bus, el bus de Arquitectura de Microcanal (MCA). Esta nueva
arquitectura de bus de IBM era mucho más rápida que el bus ISA. También se
diseñó en forma diferente, tanto que las tarjetas de expansión que funcionaban en
un bus ISA no funcionaban en el bus MCA. Con el MCA, IBM había roto la
tendencia a la escalabilidad, y al hacerlo, hizo enfurecer a muchas de las compañías
que fabricaban tarjetas de expansión anteriores.
En respuesta al MCA, un grupo de fabricantes de hardware se reunieron para
desarrollar una alternativa de bus de 32 bits que pudiera todavía aceptar y utilizar
las antiguas tarjetas de expansión ISA. Este bus se ha venido a conocer como el bus
de Arquitectura Estándar Extendida de la Industria (EISA). El EISA es más rápido
que el ISA, pero no tanto como el MCA, consecuencia de buscar la compatibilidad
con las antiguas tarjetas de expansión de 16 bits.
Dwu"fg"fktgeekqpgu
Es un conjunto de líneas semejante al bus de datos, pero sólo conecta a la CPU
con la memoria, usándose para transmitir direcciones de memoria. La razón por la
cual es importante el bus de direcciones es que su número de líneas determina el
tamaño del espacio de direcciones. Por ejemplo, recuérdese que un byte de datos es
suficiente para representar 256 valores diferentes. Si el bus de direcciones pudiera
llevar sólo un byte a la vez, la CPU podría direccionar únicamente 256 bytes de
memoria. De hecho, la mayoría de los primeros PCs tenían buses de direcciones de
20 bits, así que la CPU podía direccionar 220 bytes o 1 MByte de datos.
Actualmente, la mayoría de las CPU tienen buses de direcciones de 32 bits que
pueden direccionar 4 GBytes (más de 4 mil millones de bytes) de memoria.
Ecrvcekôp"fg"kpuvtweekqpgu
Cuando la computadora ejecute el programa, comenzará a leer números de una
posición particular de la memoria. Puesto que la unidad de control continuará
leyendo las instrucciones de programa de la memoria, tiene que tener algún tipo de
puntero que le indique qué posición de la memoria debe leer a continuación. Este
puntero lo almacena en un registro interno especial denominado contador de
programa (CP). Además, para facilitar la ejecución de instrucciones sin necesidad
de realizar continuas referencias a la memoria principal, la instrucción -es decir, el
contenido de la memoria ‘apuntado’ por el contador de programa- se traslada desde
la memoria a otro registro interno especial denominado registro de instrucción (RI)
previamente al análisis y la ejecución de la instrucción.
Ektewkvqu"kpvgitcfqu
SOPORTE FÍSICO DE UN COMPUTADOR
287
La tecnología de circuitos integrados (en inglés, chip) ha evolucionado a lo
largo de varias etapas y hemos pasado desde los años sesenta hasta ahora de
fabricar circuitos equivalentes a 10 transistores a hacerlo con otros equivalentes a
cientos de miles. De hecho, después de conseguir construir una CPU en un solo
chip, se ha llegado más lejos, hasta los chips que combinan en una sola unidad muy
rápida, CPU, memoria y canales de E/S.
La consecución de estos resultados ha sido posible tanto por la forma como se
ha resuelto la implantación física de las operaciones lógicas, como gracias a las
propiedades electrónicas de los materiales semiconductores (arseniuro de silicio o
galio) que permiten simular operaciones booleanas, donde, las variables
manipuladas son niveles de tensión (un voltaje bajo o nulo representa ”0” y un
voltaje elevado, no nulo, representa 1). Ello ha propiciado el llamado proceso de
integración a gran escala, esto es conseguir el equivalente a un gran número de
componentes en un circuito integrado de reducidas dimensiones.
Hoy en día los chips son de reducidas dimensiones, consumen poca potencia
eléctrica, casi no generan calor, son fiables y su costo no ha cesado de disminuir.
Eqpuvtweekôp"fg"ogoqtkcu
Sabemos que la unidad fundamental que es necesario almacenar es el dígito
binario o bit. Por tanto, podemos utilizar cualquier dispositivo que sea capaz de
representar dos estados estables. Un poco de reflexión nos sugiere, sin embargo,
que debemos añadir la exigencia de que el dispositivo sea capaz de conmutarse
entre los dos estados un número indefinido de veces y que el dispositivo sea capaz
de ser leído de forma no destructiva. En la segunda y tercera generaciones (19561975) de computadoras se utilizaron pequeños núcleos magnéticos para almacenar
cada bit, con la forma de una pequeña rosquilla construida de óxido férrico, con
tres hilos atravesando su centro. El núcleo almacenará un 0 o un 1, dependiendo de
la dirección de la corriente eléctrica en el hilo de corriente que pasa a través suyo.
Las memorias de núcleos se utilizaron durante mucho tiempo en las computadoras
y tenían la ventaja de no ser volátiles -mantenían su información aunque se apagase
la máquina o hubiera un fallo en la corriente eléctrica-. Sin embargo, a medida que
crecieron el tamaño de la memoria y la velocidad de las computadoras, los núcleos
fueron sustituidos por dispositivos basados en semiconductores, que eran varios
ordenes de magnitud más rápidos y pequeños.
Hemos visto que la mayoría de los datos se almacenan en un byte o en un
múltiplo de bytes. Parece deseable poder leer o escribir los 8 bits de un dato
simultáneamente. Podemos conseguir esto construyendo la memoria como “pilas”
de ocho alturas, arrays de j x j x 8 dispositivos de la memoria(8 planos de
dimensión j x j ) basados en el estado sólido. Una referencia a memoria (o
dirección) específica una columna de 8 bits que deben ser leídos o escritos
simultáneamente.
Toda la memoria de la computadora está construida con un conjunto de bancos
de memoria, dependiendo del número exacto de éstos, del tamaño de cada banco y
288
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
del espacio de direcciones de la computadora. Los bancos de memoria se
construyen en la actualidad con un número de planos j igual a 256, 512, 1024 o
incluso 2048 (obteniendo respectivamente, 64 K= 65.536, 256 K= 262.144,1M=
1.048.576, o 4M=4.194.306 direcciones distintas).
Direccion 0
Direccion 1
Direccion 2
Referencia
el byte
de la direccion 12
Dirección 4
Plano para el bit 7
Direccion 3
Direccion 15
Plano para el bit 6
Plano para el bit 5
Plano para el bit 4
Plano para el bit 3
Plano para el bit2
Plano para el bit1
Plano para el bit 0
Eqrtqegucfqt"ocvgoâvkeq
Algunas computadoras aceleran algunos tipos de procesamiento añadiendo un
coprocesador matemático; se trata de un chip o parte de un chip diseñado
especialmente para manejar operaciones matemáticas complicadas, Las CPU 80486
y Pentium de Intel tiene un coprocesador matemático integrado. Los chips más
antiguos no lo tenían, sin embargo, se podía agregar un coprocesador matemático a
una computadora mediante su inserción en la tarjeta principal del sistema. Los
coprocesadores matemáticos de Intel tienen los números de modelo 8087, 80287 y
80387 para las CPU 8086, 80286 y 80386, respectivamente.
La ALU, que maneja la mayor parte de las operaciones de procesamiento,
manipula el código binario que representa números, texto, imágenes, sonido o
cualquier forma de los datos que puede guardar la computadora. Por ello, en
términos de procesamiento, la ALU es para uso general.
El problema con la ALU de propósito general es que tiene dificultad para
realizar ciertas operaciones matemáticas, ya que está diseñada para manipular
números enteros que no sean ni muy grandes ni muy pequeños. Si es forzada a
trabajar con decimales, puede hacerse muy lento. El coprocesador matemático es
un especialista de procesamiento diseñado para trabajar específicamente con este
SOPORTE FÍSICO DE UN COMPUTADOR
289
tipo de números. Puede ejecutar rutinas aritméticas más rápidamente que la ALU,
porque usa aritmética de punto flotante.
Cuando la computadora tiene que realizar mucha aritmética de punto flotante, la
presencia de un coprocesador matemático, ya sea integrado a la CPU o agregado a
la tarjeta principal, puede acelerar considerablemente el procesamiento. Entre las
aplicaciones que se benefician de los coprocesadores matemáticos se incluyen las
hojas de cálculo y los programas de dibujo (los programas de CAD -diseño gráfico
por computador- generalmente no correrán sin un coprocesador debido a que cada
punto de un diseño en pantalla debe ser calculado numéricamente).
Fkugòq"fg"wp"ektewkvq"kpvgitcfq
Es un importante proceso que pasa por tres fases y cuya realización solo es
posible gracias a sofisticados sistemas informáticos:
1.- Diseño lógico Partiendo de sus requisitos funcionales (puede ser un
microprocesador, un chip de memoria, un chip de control de comunicaciones, etc)
se obtiene un esquema del circuito con todos los transistores necesarios
interconectados.
2.- Simulación. Su objeto es comprobar, como la bondad de este diseño, para
ello se proporciona un conjunto de datos de entrada al simulador y se estudia el
comportamiento del circuito ante estos impulsos.
3.- Realización en silicio. Consiste en pasar del diseño lógico a un diseño en
silicio que incluye puertas y otros componentes eléctricos y lógicos.
Gurcekq"fg"fktgeekqpgu
Ver Tamaño de la memoria.
Ogoqtkc"ecejê
Entre las operaciones que debe realizar una CPU y que más tiempo consume
está mover los datos de ida y vuelta entre la memoria y los registros de la CPU. El
problema es , simplemente, que la CPU es más rápida que la RAM. Una solución
parcial a este problema es incluir una memoria caché (del francés, caché,
escondido) en la CPU. Una memoria caché es similar a la RAM, excepto que es
extremadamente rápida comparada con la memoria normal y se usa en forma
diferente.
Cuando un programa está en ejecución y la CPU necesita leer datos o
instrucciones de la memoria regular, verifica primero si los datos están en la caché.
Si los datos que necesita no están ahí, continúa y lee los datos de la memoria
regular y los lleva a sus registros, pero también carga los datos en la memoria
caché al mismo tiempo. La siguiente vez que la CPU necesita los mismo datos, los
encuentra en la caché y ahorra el tiempo que se necesita para cargar los datos de la
memoria regular. Podrías pensar que las posibilidades de que la CPU encuentre los
datos que necesita en la caché son pequeñas, pero, de hecho, encuentra ahí los
290
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
datos que necesita tan frecuentemente que mejora perceptiblemente el rendimiento
del computador.
Las instrucciones de programa son un buen ejemplo de los datos que la CPU
encuentra a menudo en la caché. Un ejemplo lo constituye el procesamiento de
bucles. Si las instrucciones que le indican a la ALU el cuerpo del bucle se
encuentran en la caché, entonces la unidad de control no tiene que cargarlas en
forma repetida desde la memoria. Como resultado el proceso dura menos tiempo.
Son tamaños habituales de cachés 32, 64, 128 ó 256 KBytes.
Ogoqtkc"gzrcpfkfc"{"ogoqtkc"gzvgpfkfc
Uno de los problemas más serios en la evolución de los PCs fue que el sistema
operativo DOS usado en la gran mayoría de ellas, fue diseñado para máquinas que
podían direccionar únicamente 1 MByte de memoria. Cuando las PC empezaron a
incluir más memoria de software, tuvieron que diseñarse métodos especiales para
direccionarla. Los dos métodos se llaman memoria expandida y memoria
extendida. Sin entrar en ella diremos que la memoria extendida es un método más
rápido que la expandida pero todavía es más lento que el direccionamiento de
memoria directo.
Ogoqtkc"tgcn"{"ogoqtkc"xktvwcn
En principio el tamaño real de la memoria en una computadora puede tener un
efecto profundo sobre su poder de cómputo. Para empezar, más RAM significa que
la computadora puede usar programas más grandes y más poderosos.
Hoy en día los computadores pueden ejecutar programas cuyo tamaño
(instrucciones+datos) sea mayor que el tamaño real de la memoria: el programa no
necesita cargarse totalmente en la memoria para poder ejecutarse. La computadora
carga en la memoria únicamente las partes más esenciales y sitúa el resto del
programa en un área especial del disco, el area de memoria virtual; cuando
necesita acceder a partes del programa situadas en memoria virtual se pueden
intercambiar éstas con partes no esenciales situadas en la memoria real
Sin embargo más RAM puede hacer que la computadora corra más rápido. No
es necesario que la computadora cargue un programa completo en su memoria para
ejecutarlo, pero mientras más parte del programa quepa en la memoria, menos
tiempo se perderá en intercambios entre memoria real y memoria virtual
Afortunadamente, se decide que se necesita más memoria real, se puede
comprar más, abrir la computadora e insertarla. Aun tipos diferentes de
computadoras, como clones de IBM, Macintosh y estaciones de trabajo. Sun, todas
pueden usar los mismos chips de memoria. Los chips de memoria vienen en tarjetas
miniatura con los chips ya integrados (p.e. un módulo individual de memoria en
línea, SIMM por sus iniciales en inglés).
SOPORTE FÍSICO DE UN COMPUTADOR
291
Oketqrtqegucfqt
Circuito integrado que contiene como mínimo una CPU, pudiendo contener
además parte de la memoria y circuitos adicionales. Téngase en cuenta que el
término procesador es equívoco ya que a veces se utiliza para designar la CPU
tanto si incluye la memoria como si no. En tal caso es mejor hablar de módulo de
proceso.
El módulo de proceso es la entidad encargada del tratamiento y distribución de
la información y normalmente se halla físicamente en una sola placa, que debe
trabajar de la forma mas rápida posible, consumiendo poca potencia y libre de
errores y paradas. A pesar de lo exigente de estos requisitos, podemos decir que en
la actualidad contamos con módulos de proceso rápidos, potentes, seguros,
eficientes y baratos.
Qticpk|cekôp"fg"nc"ogoqtkc
En la tercera generación de hardware, a principios de 1964, se adoptó un
método según el cual los sistemas identificaron el carácter como la unidad básica, y
establecieron el byte (8 bits) como la mínima unidad direccionable de la memoria.
Con este esquema, los enteros y los números en como flotante se almacenan en
grupos adyacentes de bytes con direcciones consecutivas denominadas palabras.
Más formalmente, definimos una palabra como el conjunto de bytes contiguos que
son necesarios para almacenar un entero de longitud normal. Por ejemplo, los
enteros normales del PC de IBM y del MacIntosh de Apple son de 16 bits (2
bytes), mientras que en la Sparc de SUN y en las grandes computadoras de IBM
son de 32 bits ( 4 bytes).
Tgikuvtqu"fg"ogoqtkc
Esencialmente la memoria de una computadora realiza dos funciones: debe
permitir el almacenamiento de un elemento de información en una dirección o
secuencia de direcciones determinada (y que dicha información permanezca ahí de
forma indefinida) y debe permitir la lectura de un elemento de un byte o secuencia
de bytes contiguos.
Para facilitar estas tareas el sistema de memoria, además de las celdas de
almacenamiento, emplea dos registros internos y un descodificador que ‘encuentra’
una determinada posición cuando se le suministra su dirección en binario. Estos
dos registros se denominan, respectivamente, registro de direcciones de memoria
(MAR o memory address register) y registro de intercambio de memoria (MBR o
memory buffer register). El registro MAR almacena la dirección en binario de la
posición de la que se quiere leer o sobre la que se quiere escribir. Por tanto, el
tamaño del registro MAR limita la cantidad de memoria direcionable por una
máquina determinada (y debe coincidir con el tamaño del bus de direcciones). Si el
MAR consta de n bits, entonces se podrán direccionar hasta 2n posiciones distintas.
292
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
El registro MBR se utiliza para almacenar la información que se desea escribir o
que se acaba de leer, sobre o de la posición que contiene el registro MAR.
Para poder realizar una operación de lectura o de escritura, necesitamos una
manera de indicar una lectura o una escritura desde el almacenamiento, y una
forma de acceder de la dirección especificada en el MAR a la dirección de
almacenamiento actual. Lo primero se consigue directamente añadiendo líneas de
control de lectura/escritura, que especifican LEER o ESCRIBIR e inician la
operación; lo segundo es un poco más complejo. Precisa el diseño e
implementación de un descodificador, cuya descripción supera la panorámica de
este texto.
Tgnql"kpvgtpq
Todas las computadoras incluyen dentro de su unidad de control tienen un
sistema de reloj accionado por un cristal de cuarzo. La computadora usa las
vibraciones en el reloj del sistema para temporizar sus operaciones de
procesamiento.
A lo largo de los años, las velocidades de los relojes se ha incrementado de
forma constante. Por ejemplo la primera PC operaba a 4,77 Megahertz (Hertz
significa ciclos de reloj por segundo). El computador sólo realizará una operación
simple (como mover un byte de un lugar de la memoria a otro, por ejemplo);
cuanto más corto sea un ciclo, más ciclos y por consiguiente más operaciones
realizará un computador por segundo; no obstante, un ciclo no podrá ser más corto
que el tiempo que cuesta la operación simple más larga (algunas operaciones
complejas si podrán durar más de un ciclo). Actualmente, las PC más rápidas se
acercan a velocidades de 100 MHz. En igualdad de todos los demás factores
(aunque nunca llegan a serlo), una CPU operando a 66 MHz puede procesar datos
14 veces más rápido que otra operando a 4,77 MHz.
Vcocòq"fg"nc"ogoqtkc
Es la capacidad de la memoria o cantidad de memoria disponible de una
computadora concreta, es decir, el número de bytes disponibles. Se suele expresar
en kilobytes (Kbytes) o megabytes (Mbytes). No debe confundirse con el espacio
de direcciones, que también se expresa en Kbytes y Mbytes. Una computadora con
un espacio de direcciones de 256 Kbytes tendrá 264.144 posiciones direccionables,
y una con 16 Mbytes tendrá 224 =16.777.216 posiciones disponibles. El tamaño de
la memoria en cada caso puede ser igual o menor que el del espacio de direcciones.
Vkrqu"fg"tgikuvtqu"gp"nc"CNW
Existen en realidad cuatro tipos de registros: Registros de datos, Registros de
índice, Registros de estado y Registros de trabajo. Como ya sabemos, uno de los
SOPORTE FÍSICO DE UN COMPUTADOR
293
cometidos más importantes de los registros de datos es el de almacenar datos y
resultados de operaciones aritméticas.
Por su parte los registros de índice se utilizan en el cálculo de direcciones. Por
ejemplo, se puede utilizar un registro de índice para almacenar la dirección base de
una lista, con objeto de recorrerla y realizar una operación sobre cada uno de los
elementos de la misma.
El tercer tipo de registro (registros de estado) se utiliza para almacenar
información sobre el estado actual como, por ejemplo, si ha habido
desbordamiento. Algunas de esas condiciones se indican utilizando códigos de
condiciones, que se almacenan en el registro de código de condición. También
existen otros, como aquellos que almacenan códigos que señalan errores que se
producen durante la transferencia de operaciones de E/S.
El último grupo, los registros de trabajo, los utilizan los distintos componentes
de la computadora para almacenamiento intermedio, por ejemplo el MAR y el
MBR usados por la memoria. Al contrario que los otros tres tipos de registros, los
registros de trabajo no son directamente accesibles por programa. Otros registros
de trabajo fundamentales son el contador de programa (CP) y el registro de
instrucción (RI).
Para proporcionar la máxima eficacia en la utilización de los registros, los
registros de datos (también llamados acumuladores) y los registros de índices
suelen combinarse en un conjunto de registro de propósito general.
Vtcpukuvqt
Un transistor es un componente electrónico con tres conexiones, que funciona a
modo de un interruptor muy rápido y preciso, que permite el paso de corriente o no
a través de dos conexiones (emisor y colector) dependiendo de la existencia o no de
corriente en su tercera conexión (base). Ver las distintas posibilidades en la Figura.
Combinando transistores podemos reproducir las funciones lógicas a través de
puertas lógicas que son elementos funcionales que ejecutan estas funciones en un
circuito lógico.
294
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
No
voltaje
Voltaje
o no voltaje
0 50
No
voltaje
0 50
Voltaje
a)
b)
Voltaje
0 50
Voltaje
c)
En la configuración del transistor de la figura, en el caso a) no se aplica voltaje en el emisor (A=0) e
independientemente de que se haga o no a la base (B=X) no se obtiene corriente (C=0);
en el caso c) se aplica voltaje en ambos (A=1,B=1) y tampoco se obtiene corriente (C=0);
sólo se obtendrá corriente en el caso b) cuando se aplique voltaje en el emisor (A=1) y no se aplique
en la base (B=0); con lo que la función lógica implementada es A and (not (B))
Superada la etapa del uso de los tubos de vacío, de 1955 a 1965, los circuitos
lógicos de los computadores se realizaban a base de transistores conectados hasta
que se descubrió que se podían construir circuitos que contuvieran varios
transistores y otros componentes en una sola unidad de estado sólido. Estos
circuitos integrados realizan las funciones de un gran número de puertas lógicas,
aunque los principios que rigen su funcionamiento son los mismos que se aplican
para el caso de un solo transistor.
RGTKHÖTKEQU"FG"NQU"EQORWVCFQTGU
Cnvcxqegu
Los altavoces se utilizan tanto para sonidos musicales como para la voz, siendo
la síntesis de voz la contrapartida al reconocimiento de la voz. Como en el caso de
esta última, la síntesis de voz es un campo de gran actividad investigadora. La
síntesis de voz funciona a base de almacenar muestras codificadas digitalmente de
sonidos clave. Las palabras se construyen utilizando estas muestras previamente
codificadas y a continuación descodificando el resultado mediante un conjunto
apropiado de circuitos conectados a algún medio de reproducción del sonido.
Dwhhgtu"fg"rgtkhêtkequ
SOPORTE FÍSICO DE UN COMPUTADOR
295
Para facilitar la transmisión de datos entre la memoria principal y un dispositivo
periférico, se crea un área de almacenamiento intermedio, llamada buffer, que se
emplea para almacenar bloques de datos durante diversas etapas de la transferencia
desde o hacia un periférico. (Ver también Comprobaciones automáticas durante la
transferencia de datos). Una parte de la memoria principal se reserva para los
buffers de los periféricos, y la mayoría de los dispositivos contienen buffers de uso
particular. El tamaño de los buffers empezó correspondiendo al número de
caracteres que se intercambian durante una transferencia entre el procesador central
y el dispositivo en cuestión, pero en la actualidad, con el abaratamiento de las
memorias, tienen una capacidad sensiblemente más alta.
Ekpvcu"FCV"*Fkikvcn"Cwfkq"Vcrg+
Son unas cintas de pequeño tamaño (aproximadamente la mitad de una cinta de
cassette) que también se utilizan en aparatos musicales. A pesar de su reducido
tamaño pueden almacenar varios gigabytes de información.
Ekpvcu"ocipêvkecu
La cinta magnética es el medio más barato y mas veterano, para almacenar
grandes cantidades de datos. Las cintas están constituidas por una sustancia plástica
recubierta de material magnetizable, y, por su aspecto, recuerdan a las cintas
empleadas para la reproducción de sonido aunque son de un tamaño mucho mayor.
Para poder acceder a los datos , la cinta tiene que estar montada sobre un periférico
constituido por dos ruedas que mueven el carrete de la cinta y una cabeza lectora,
que bajo el control del computador puede leer, escribir y rebobinar la cinta (Ver
Figura 3.2). Las cintas magnéticas tienen una longitud que oscila entre varios
centenares y el millar de metros. Las estaciones de trabajo emplean cintas de
cartucho que contienen una cinta de longitud fija enrollada por sus dos extremos,
de aspecto similar a las cintas de casette, pero de tamaño entre 2 y 3 veces más
grande.
296
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
La unidad de transferencia de datos desde y hacia la cinta es el bloque. Como
en el caso del sector en los discos, un bloque es un unidad de datos de un tamaño
determinado en cada sistema de computador. Entre dos bloques consecutivos se
deja un espacio en blanco denominado inter-block gap. La razón para disponer los
datos de esta forma se encuentra en el hecho de que sólo se puede leer o escribir en
la cinta cuando se está moviendo a velocidad normal. Los inter-block gaps
permiten que se pueda parar, arrancar o invertir el movimiento de la cinta de forma
sencilla.
Los datos se disponen sobre las cintas magnéticas en pistas que recorren la cinta
a lo largo. Lo más frecuente es que en una cinta se dispongan ocho pistas. Cada
dato se representa por el conjunto de zonas magnetizadas o no, que se encuentran
perpendicularmente a la cinta.
Eqortqdcekqpgu"cwvqoâvkecu"fwtcpvg"nc"vtcpuhgtgpekc"fg"fcvqu
Las transferencias de datos desde y hacia los medios de almacenamiento masivo
son operaciones sensibles a los errores. Por tanto, en la mayoría de los sistemas se
incluyen una serie de comprobaciones automáticas durante estas operaciones.
.Además de las conocidas comprobaciones de paridad, existen otros tipos de
comprobaciones, como leer-tras-escribir o sumas de comprobación, y técnicas
de corrección de errores, como los códigos Hamming.
Las técnicas del tipo leer-tras-escribir se emplean en la mayoría de los sistemas.
Una vez que se ha escrito un bloque de datos en el disco se lee de nuevo y se
compara con el original que aún se encuentra en el buffer. Si las dos versiones no
coinciden exactamente, los datos se vuelven a escribir. Si el error persiste tras un
determinado número de intentos, se aborta la acción y se emite un mensaje al
usuario.
Más concretamente, cuando se transfiere un bloque de datos, se obtiene, a partir
del valor numérico del código de cada dato, un check sum, o suma de
comprobación. Una vez que se leen los datos y su check sum, se calcula éste de
nuevo. Si el nuevo valor no coincide con el anterior, entonces es que se ha
producido un error durante la transferencia. En algunos casos se informa del error
una vez que se detecta. En otros casos, se transmiten de nuevo los datos y se realiza
otra comprobación. Si tras un determinado número de reintentos el error persiste,
se detiene el proceso y se informa de esta circunstancia.
Los códigos Hamming son códigos binarios que se usan para representar datos
que tienen un número adicional de bits a fin de detectar errores. Los bits de
comprobación se disponen de tal modo que es posible corregir un error en la
transmisión de un bit y detectar los errores que se produzcan en más de uno. La
teoría de la codificación y de los códigos de Hamming, constituyen una interesante
aplicación práctica de la teoría de grupos.
Eqpxgtuqtgu"cpcnôikeq/fkikvcngu
SOPORTE FÍSICO DE UN COMPUTADOR
297
Muchos sistemas de control están conectados a dispositivos de entrada que
toman medidas de forma analógica. Estas medidas son generalmente voltajes,
proporcionales a alguna magnitud física, (temperatura, capacidad, etc). Para que
estas magnitudes puedan utilizarse en un computador, es necesario convertir las
medidas analógicas a forma digital. Esto se consigue empleando un convertidor
analógico-digital (Analog to Digital Converter, ADC), que puede ser parte integral
de un computador, o más generalmente, una unidad aparte. Algunos convertidores
analógico-digitales son parte de sistemas de registro de datos que admiten varios
canales de datos, convierten la señal y la almacenan en RAM.
Un ADC muestra los voltajes de forma regular y convierte estas muestras a
señales digitales de acuerdo con alguna escala adecuada. La velocidad de muestreo
suele ser variable y suele estar controlada por el computador empleando algún
mecanismo adecuado.
Eqpxgtuqtgu"fkikvcn/cpcnôikeq
El proceso de conversión contrario al analógico-digital lo efectúa un
convertidor digital-analógico (Digital to Analog Converter, DAC). Este dispositivo
acepta una secuencia de señales digitales y las convierte en voltajes de acuerdo a
algún algoritmo apropiado.
La combinación de entradas analógicas y de salida con tratamiento digital de
señales es extremadamente útil en un amplio rango de aplicaciones científicas e
industriales, especialmente en aquellas que suponen control de procesos.
Fkuequ"eqorcevqu"*EF/TQO+
El CD-ROM utiliza la misma tecnología usada en los discos compactos de
música. Por el momento es un medio solo de lectura. El hecho de que no se pueda
escribir información en un CD-ROM no significa que no sea un medio útil de
almacenamiento, gracias a su alta precisión un CD-ROM, puede almacenar hasta
600 MB de información. De hecho, muchas aplicaciones dependen de grandes
volúmenes de información que raramente cambia, como diccionarios,
enciclopedias etc. Además de estos usos, las compañías de software distribuyen
sus productos en CD-ROM basándose en sus altas capacidades y en el hecho de
que nadie puede cambiar la información en ellos. Una de estas compañías es Sun
Microsystems, la cual fábrica y vende estaciones de trabajo Unix de alto
rendimiento. Sun no sólo distribuye sus sistemas operativos Unix en un solo CD,
sino que puede distribuir cada una de las versiones y actualizaciones de los
sistemas operativos que ha fabricado en un solo disco.
Otra aplicación interesante de la tecnología del CD-ROM es el CD interactivo
(CD-I) El CD-I almacena audio, vídeo en movimiento y gráficos. Lo interesante de
esta idea no es tanto lo que puede almacenarse en un CD, sino la manera en que se
tiene acceso a la información. Con el CD-I, se escoge lo que se quiere ver y oír en
un ambiente interactivo.
298
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Fkuequ"ocipêvkequ
Los discos magnéticos son la forma más común de almacenar datos para su
acceso por el computador. Un disco está constituido por una superficie metálica o
plástica recubierta por una capa de una sustancia magnetizable. Los datos se
almacenan mediante pequeños cambios en la magnetización, en uno o u otro
sentido.
Los discos magnéticos se fabrican en diferentes tamaños. En lo alto de la gama
se encuentran los paquetes de discos intercambiables, formados por un conjunto de
discos montados sobre un eje común. En la mitad de la escala se encuentran los
cartuchos de un solo disco, que se usan principalmente en minicomputadores. Los
computadores personales usan disquetes de 3.5 ó 5.25 pulgadas generalmente
construidos en plástico. Un desarrollo importante es el disco Winchester,
popularmente llamado disco duro. Este es un disco de pequeño tamaño pero de
gran precisión y con una gran capacidad de almacenamiento. Está
permanentemente montado en su unidad. Las capacidades de almacenamiento
varían entre los pocos gigabytes para los paquetes de discos más grandes, hasta el
orden del megabyte para los disquetes.
Los discos magnéticos generalmente almacenan datos por las dos caras. En cada
cara los datos se disponen en anillos concéntricos denominados pistas. Las pistas
correspondientes, unas encima de otras, forman un cilindro. Todos los datos en un
cilindro pueden alcanzarse sin necesidad de mover la cabeza de lectura/escritura
del disco, gracias a que existen tantas cabezas como pistas/cilindro. Cada pista se
divide en unidades denominadas sectores o bloques. El paso de un cilindro a otro
se hace a través del movimiento del brazo que en su extremo lleva la cabeza lectora
Los datos se transfieren desde o hacia los discos sector a sector. Los espacios
entre sectores, denominados gaps, facilitan el posicionamiento de la cabeza de
lectura/escritura. Para localizar un bloque de datos en un disco hay que reconocer
la cara, el cilindro (pista) y el sector. Esta información se expresa generalmente
como una secuencia de números que constituyen la dirección del bloque. La
dirección de un dato en un disco es muy similar al concepto de dirección en la
memoria principal del computador.
SOPORTE FÍSICO DE UN COMPUTADOR
299
La unidad de transferencia de datos desde y hacia un disco magnético es el
bloque. El disco gira a gran velocidad y la cabeza de lectura/escritura se mueve
muy próxima a la superficie para detectar o producir cambios en la magnetización
(ver figura adjunta). Existe, sin embargo, un intervalo de tiempo hasta que se
localiza el dato y puede comenzar la transferencia. Este intervalo tiene dos
componentes, un tiempo hasta que la cabeza de lectura/escritura se sitúa en la pista
indicada y un tiempo de acceso hasta que el disco gira y presenta el sector deseado
a la cabeza de lectura/escritura. El primero de ellos se reduce transfiriendo datos
desde cilindros o sectores consecutivos, y el segundo se reduce transfiriendo datos
situados en sectores consecutivos. Muchos discos disponen de controladores que
utilizando algoritmos adecuados almacenan los datos de forma que optimizan el
movimiento de la cabeza llevando un control cuidadoso de la disposición de los
datos en las pistas y cilindros y atendiendo las peticiones de transferencia de modo
que se reduzca el movimiento de la cabeza.
El mayor problema que afecta a los discos magnéticos es el polvo. Los discos
de mayor capacidad se construyen de metal mecanizado con gran precisión. El
espacio entre la superficie del disco, que gira a gran velocidad, y la cabeza de
lectura/escritura es muy pequeño. Si una mota de polvo se mete entre la cabeza de
lectura/escritura y la superficie, puede dañar la superficie magnética y también la
cabeza lectura/escritura , provocando la pérdida de la información contenida en el
disco. Para leer los disquetes se emplea una cabeza de lectura/escritura que
presiona contra el disco. En este caso, el polvo puede provocar que el disco se
estropee. Los discos Winchester se sellan en entornos libres de polvo,
constituyendo un todo con sus unidades de control.
Fkuequ"ôrvkequ
La continua necesidad de mayores capacidades de almacenamiento ha llevado a
los fabricantes de hardware a una búsqueda continua de medios de
almacenamiento alternativos y, cuando no hay opciones, a mejorar las tecnologías
disponibles y desarrollar otras nuevas. Actualmente, el almacenamiento óptico es
la principal alternativa para el almacenamiento magnético.
Las técnicas de almacenamiento óptico hacen posible el uso de la localización
precisa mediante rayos láser. El láser utiliza un haz de luz concentrado y delgado.
La única diferencia con la luz normal radica en que, en el rayo láser, la luz es
coherente, es decir, toda la energía de la luz está perfectamente alineada en la
misma dirección, permitiendo enfocarla con extraordinaria precisión en un área
extremadamente pequeña.
Los dispositivos de almacenamiento óptico enfocan el rayo láser sobre el medio
de grabación: un disco girando. Algunas áreas del medio reflejan la luz del láser
dentro de un sensor, mientras que otras la dispersan. Mientras el disco gira al pasar
la luz y el sensor, un punto que refleja el rayo láser dentro del sensor es
interpretado como un 1, y la ausencia de reflexión es interpretada como un 0.
300
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
En un disco óptico, la información está más bien acomodada como en una
grabación fonográfica que como en un disco magnético. Como en aquélla, un
disco óptico tiene pista larga que comienza en la orilla exterior y viaja en espiral
hacia el centro. Además, como en una grabación fonográfica, la información en el
disco óptico queda permanentemente grabada en la superficie del mismo. El punto
que refleja la luz dentro del sensor es llamado pozo, y el que la dispersa, plano.
Como en un disco magnético, la pista de un disco óptico se divide en sectores,
pero en los disco ópticos cada sector tiene la misma longitud. Por lo tanto, la
unidad tiene que disminuir la rotación del disco para permitir a las cabezas leer la
información almacenada en los sectores más cercanos al centro del disco.
Aunque leer información de un medio óptico es una tarea relativamente fácil
escribirla es otro asunto. El problema es la dificultad para modificar la superficie
de un medio óptico. A diferencia de los medios magnéticos donde cualquier punto
en la superficie es físicamente igual a cualquier otro, aun cuando haya información
en él con los medios ópticos, la superficie es físicamente igual a cualquier otro,
aun cuando haya información en él con los medios ópticos, la superficie está
físicamente perforada para reflejar o dispersar la luz del láser.
(Ver también Discos compactos)
Kortguqtcu
Las impresoras son uno de los tipos más frecuentes de dispositivo de salida.
Producen una copia permanente en papel de los resultados, y son de diversos tipos:
Impresoras de líneas. Son las más grandes e imprimen todos los caracteres de
una línea cada vez. Las líneas contienen entre cien y ciento treinta caracteres y la
velocidad de impresión varia entre las trescientas a mil doscientas líneas por
minuto. En lo más alto de la gama se encuentran las impresoras láser de alta
velocidad para textos, que pueden llegar a producir hasta veinte mil líneas por
minuto.
Impresoras de caracteres: Imprimen carácter a carácter, son más lentas pero
también más baratas que las impresoras de líneas, con velocidades del orden de
cien líneas por minuto, que se superan a base de imprimir en ambas direcciones.
Los tipos más comunes de impresoras de caracteres son las impresoras matriciales,
las impresoras de margarita y las impresoras de chorro de tinta.
Impresoras matriciales e impresoras de margarita: Las impresoras
matriciales construyen los caracteres combinando puntos producidos por una
matriz de agujas situadas en la cabeza de la impresora. Son dispositivos simples y
de bajo costo que pueden utilizarse también para imprimir gráficos de baja
resolución. Las impresoras de margarita disponen de una rueda que tienen un
carácter en cada “pétalo”. La rueda gira para seleccionar los caracteres que deben
imprimirse. Las impresoras de margarita producen caracteres de la misma calidad
que una máquina de escribir, pero no pueden reproducir gráficos.
SOPORTE FÍSICO DE UN COMPUTADOR
301
Impresoras de chorro a tinta: Estas impresoras lanzan un pequeño chorro de
tinta sobre el papel empleando una matriz de mucha más resolución que en el caso
de las impresoras matriciales, ya que mientras éstas usan agujas, las de chorro de
tinta, utilizan corrientes eléctricas para componer la matriz. Algunos modelos
pueden imprimir en más de un color. Se trata de dispositivos de propósito especial
utilizados fundamentalmente para imprimir textos y gráficos cuando se necesita
color. Su principal ventaja es que son mucho más silenciosas que las impresoras
matriciales o de margarita y de mucha mayor resolución. La bajada de coste que
están teniendo junto con la mejora de resolución (las hay que mejoran la resolución
de impresoras láser y a mitad de precio) está popularizando su uso.
Impresoras láser: Pueden producir, como las de chorro de tinta, una
combinación de gráficos y textos. Las impresoras láser (de construcción diferente
de las impresoras láser de alta velocidad para textos) son los dispositivos de salida
más populares para imprimir imágenes de alta calidad que permitan combinar texto
y gráficos. La salida se mide en términos de puntos de una matriz, del orden de
unos 300 puntos por pulgada, tanto en horizontal, como en vertical, que dan una
primera sensación de encontrarnos frente a una impresión en bloque, ya que los
puntos apenas pueden verse. El compromiso entre velocidad de impresión, calidad
de la misma y resolución, hace a estas impresoras y a las de chorro de tinta una
opción muy interesante para muchas aplicaciones.
Kpvgthc|"{"Eqpvtqncfqt"fg"rgtkhêtkequ
Los periféricos se interconectan al bus del sistema, bien directamente, bien a
través de circuitos que constituyen el interfaz. Al existir una gran diversidad de
periféricos con distinta características eléctricas y velocidades de funcionamiento,
las respectivas interfaces adaptan las características de los periféricos a las del bus
del sistema, estableciendo los protocolos de comunicación para controlar el flujo de
información de forma adecuada y eficaz. Las interfaces particulares para conexión
de equipos periféricos a una computadora cubren básicamente tres objetivos:
1.- Conversión de datos.- Adaptan la representación de datos del bus del
sistema a la representación de datos del periférico. Si el periférico, por
ejemplo, es de tipo serie, la interfaz realiza la conversión paralelo a serie (si
es un dispositivo de salida) o serie a paralelo (si es un dispositivo de
entrada).
2.- Sincronización.- Al ser la velocidad operativa del procesador mucho
mayor que la de los periféricos, la interfaz regula el tráfico de información
,para evitar problemas de sincronización o de pérdidas de información. La
interfaz suele actuar con unas señales de control y estado que intercambia
con la CPU, indicando situaciones tales como: que está preparada o lista
para recibir o transmitir, que ha reconocido la llegada de unos datos, que
desea ser atendida por la CPU, que ha recibido una interrupción, etc
302
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
3.- Selección de dispositivos.- Las interfaces también se encargan de
identificar la dirección de los periférico que deben intervenir en el tráfico de
datos.
Los interfaces de periféricos son un aspecto importante del diseño de
computadores, puesto que un periférico puede desconectarse y sustituirse por otro
que realice la misma tarea de forma diferente, sin que el sistema se vea afectado.
Nârkegu"ôrvkequ
Un lápiz óptico es un dispositivo manual, con forma de lápiz, que permite al
usuario dibujar directamente en la pantalla. Al igual que un digitalizador, es un
dispositivo de propósito especial diseñado para aplicaciones gráficas y de diseño
asistido por computador. La precisión con la que pueden situarse los puntos en la
pantalla depende de la resolución de la propia pantalla. La ventaja de los lápices
ópticos sobre las tabletas digitalizadoras es que se puede dibujar directamente sobre
la pantalla. Sus desventajas son que no pueden “copiarse” documentos a la pantalla
y que la posición de empleo del lápiz (perpendicular a la pantalla) resulta cansada.
El uso de los lápices ópticos es menos común que el de las tabletas digitalizadoras.
Ngevqtgu"fg"dcpfcu"ocipêvkecu
Las bandas magnéticas se emplean en productos como tarjetas de crédito,
tarjetas de acceso a edificios y etiquetas de algunos productos. Contienen datos
como números de cuenta, códigos de productos, precios, etc. Las bandas se leen
mediante detectores situados en los dispositivos en los que éstas se introducen. La
ventaja de este método es que la información es difícil de alterar una vez que se ha
grabado en la banda. Esto proporciona un notable grado de seguridad frente a los
sistemas convencionales de identificación. Una evolución de estos sistemas son las
tarjetas con chip que pueden almacenar mucha mayor información y permiten
tanto la lectura como la escritura sobre ellas.
Ngevqtgu"fg"eôfkiqu"fg"dcttcu
Los códigos de barras se están transformando en la forma estándar de
representar información en los productos de mercado, en un formato accesible para
las máquinas. Un código de barras consiste en un conjunto de barras verticales
pintadas en negro (o en un color oscuro) sobre un fondo blanco (o claro). Los
caracteres se codifican empleando combinaciones de barras más o menos estrechas
y siempre se incluyen caracteres de comprobación. El código de barras más común
empleado fuera de Estados Unidos es el código europeo de numeración de
artículos (ENA). Cada artículo dispone de un código único de doce dígitos junto
con un dígito de paridad. Los dígitos se imprimen bajo las barras para
comprobación visual cuando sea necesario. Los códigos de barras disponen de un
SOPORTE FÍSICO DE UN COMPUTADOR
303
sistema de protección frente a errores (mediante dígitos redundantes) y pueden
leerse en ambos sentidos.
Un lector de código de barras interpreta la secuencia de barras y produce el
conjunto de caracteres equivalente. Los lectores de código de barras tienen bien la
forma de un lápiz, que se pasa sobre el código a leer o bien son dispositivos
mayores de carácter fijo que disponen de una ventana sobre la que se apoya el
producto cuyo código se quiere leer. Las experiencias hasta la fecha indican que los
códigos de barras constituyen un método de codificación bastante rápido y fiable.
Oketôhqpq
Los micrófonos se utilizan para introducir información en el computador a
través de voz humana, para lo cual se utilizan métodos de reconocimiento de la
voz que ha sido un campo en el que se han llevado a cabo intensas investigaciones
durante mucho tiempo. Aunque el éxito ha sido limitado hasta la fecha, es un área
prometedora para el futuro. Los sistemas actuales de reconocimiento de voz pueden
responder a un pequeño número de palabras o frases de una persona cuya voz han
“aprendido”. Los rangos en los que puede garantizarse actualmente el
reconocimiento de la voz son bastantes altos, pero aún no son apropiados para la
mayoría de las aplicaciones. La velocidad a que se pueden adquirir datos está
limitada, lógicamente, por la máxima velocidad a que una persona puede hablar de
forma coherente.
Oqpkvqt
La forma más común de comunicación con el usuario se hace vía una pantalla
de rayos catódicos, también llamada unidad de representación visual, o VDU
(visual display unit). Los datos de entrada se introducen mediante el teclado, y la
salida aparece representada, mediante caracteres, en la pantalla. Algunos sistemas
operativos, permiten la posibilidad de que las pantallas presenten varias ventanas
simultáneamente, en cada una de las cuales se puede estar trabajando con un
programa distinto.
Una versión mejorada de las VDU la constituyen los monitores, que permiten
representar en la pantalla, normalmente en color, además de caracteres, líneas,
formas y figuras que se forman en la pantalla mediante hileras de puntos situadas
muy próximas unas a otras. A cada uno de estos puntos se le denomina pixel y es la
mínima información que puede representarse en una pantalla. La resolución del
monitor indica el número de puntos que se pueden representar en él, tanto vertical
como horizontalmente.
A la combinación de monitor y teclado conectados por un único canal con un
computador, se les conoce con el nombre de terminal.
Rcpvcnncu"ugpukdngu"cn"vcevq
304
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Las pantallas de computador pueden dotarse de un dispositivo sensible al tacto
que detecta la posición de cualquier objeto cercano a la pantalla. Una pantalla
sensible al tacto es mucho menos precisa que un lápiz óptico. Es un dispositivo de
propósito especial restringido a ciertas aplicaciones. Su principal función es la de
seleccionar opciones de control directamente de los menús presentados en la
pantalla. También se emplean en computadores utilizados por personas con
minusvalías.
Rnqvvgtu
En las aplicaciones de diseño asistido por computador en áreas como el diseño
de chips, así como en aplicaciones en arquitectura e ingeniería, se utilizan plotters
para representar los resultados que produce el computador. Estos dispositivos
producen planos, dibujos técnicos, representaciones de los chips y mapas. Un
plotter dispone de una pluma que se mueve sobre la superficie del papel bajo el
control de un procesador.
En algunos modelos (como, por ejemplo en los plotters de sábana) la pluma se
mueve tanto vertical como horizontalmente. En otros, la pluma se mueve
horizontalmente y el papel verticalmente. Los plotters del primer tipo pueden
emplear tamaños de papel mucho mayores que los del segundo.
Tcvqpgu
Al objeto de superar la falta de habilidad para teclear de algunas personas y de
facilitar la entrada de datos al computador, han surgido distintos dispositivos que
explicitan con mas claridad el tipo de ordenes introducidas y que complementan la
tarea del teclado, uno de estos elementos que se ha popularizado, gracias a la
introducción de los iconos, como parte del interfaz del sistema operativo es el
ratón. Un ratón es un dispositivo manual de entrada de datos que mueve el usuario
sobre una superficie plana. y que está conectado a un terminal o a un computador
personal. A medida que se mueve el ratón, un puntero se traslada también por la
pantalla de forma análoga. Pulsando un botón del ratón se selecciona un dato o la
opción de control que, en ese momento, esté bajo el puntero (por ejemplo
seleccionar opciones de menú). Los ratones suelen simplificar mucho el trabajo
reduciendo o eliminando la necesidad de un teclado. La posibilidad de emplear un
ratón ha sido una de las soluciones al problema de la falta de habilidad con el
teclado mencionada anteriormente, a la vez que ha posibilitado el desarrollo de
sistemas operativos en los que el uso de un amplio repertorio de órdenes y opciones
(que debía memorizar el usuario) ha sido reemplazado por menús e iconos que se
manejan gracias al movimiento del ratón y a la pulsación de sus botones.
El ratón es en realidad un dispositivo sencillo. El tipo más común tiene adentro
una bola que sobresale por la parte inferior de su cubierta. Cuando el ratón se
desplaza por una superficie plana, la bola gira. Por ambos lados de la bola, en un
ángulo de 90 grados, se encuentran dos rodillos o ruedas que giran a la misma
SOPORTE FÍSICO DE UN COMPUTADOR
305
velocidad que la bola. Unos detectores indican cuánto ha girado cada rueda y
envían esta información a la computadora en forma de cambios en la posición
actual del puntero.
Un ratón o mouse óptico no tiene partes móviles. En lugar de una bola, el ratón
óptico tiene construido internamente un detector internamente un detector de luz
que sigue el movimiento del ratón sobre una superficie especial que tiene las líneas
de una malla impresas sobre él. El detector de luz ubica cada línea horizontal y
vertical a medida que pasan por abajo del ratón, luego manda esta información a la
computadora de la misma manera como lo hace el ratón mecánico.
Al igual que el teclado, el ratón no envía en realidad un mensaje directamente al
programa que está corriendo la computadora. Más bien, envía una solicitud de
interrupción a la CPU. El programa que se encuentra en ejecución revisa
regularmente para ver si ha ocurrido o no un evento proveniente del ratón; si ha
ocurrido, el programa lee una dirección de memoria para ver qué pasó en realidad y
luego reacciona apropiadamente.
Tgeqpqegfqtgu"ôrvkequ"fg"ectcevgtgu
El reconocimiento óptico de caracteres (OCR) está basado en el uso de un
dispositivo de exploración óptica (scanning) que puede reconocer la letra impresa.
Muchos documentos comerciales, como las facturas del gas, la luz ó el teléfono,
disponen de una banda que se puede leer mediante un dispositivo de OCR. (Los
nuevos pasaportes de la Unidad Europea disponen de una página de texto OCR en
la que se incluyen todos los detalles del titular del pasaporte). Para los OCR se
emplea un tipo de imprenta especial para facilitar su lectura. (Algunos dispositivos
OCR pueden leer tipos de imprenta comunes, y otros, como los empleados por las
administraciones postales para los procesos de clasificación, pueden reconocer la
letra manuscrita siempre que ésta sea suficientemente clara). Una variante sencilla
de este sistema la constituye el método de reconocimiento de marcas. En este caso
el dispositivo de lectura puede reconocer cuándo ciertas áreas se han ennegrecido
con un lápiz u otro instrumento de escritura. Entre los documentos sometidos a esta
forma de lectura se encuentran los cupones de las quinielas, los formularios para la
lectura de los contadores del gas, y la luz, y los cuestionarios con respuestas de
elección múltiple. Los métodos de OCR y de reconocimiento de marcas tienen la
ventaja de que se pueden emplear para leer datos directamente de los documentos
originales, pero son lentos y sensibles a los errores, en comparación con otros
métodos.
Uecppgtu
Un scanner es un dispositivo que recuerda una fotocopiadora o una vídeo
cámara (según los modelos) que se emplea para introducir imágenes, normalmente
en color o blanco y negro, en un computador. Las imágenes que desee capturar
deben estar correctamente iluminadas para evitar brillo y tonos no deseados. Son
306
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
dispositivos de entrada de datos de propósito especial que se emplean
conjuntamente con paquetes software para gráficos y pantallas de alta resolución.
La resolución de las imágenes varía, desde la de una cámara de vídeo
convencional, hasta resoluciones profesionales, considerablemente mayores. En
algunos computadores es posible emplear una vídeo cámara a modo de scanner,
aunque dada la cantidad de espacio de almacenamiento que se necesita para una
imagen no estamos hablando de capturar imágenes en movimiento.
Vcdngvcu"fkikvcnk|cfqtcu
Una tableta digitalizadora es un dispositivo que permite al usuario “dibujar”
mediante una superficie de tamaño moderado. Consiste en un dispositivo similar a
un ratón, aunque mucho más preciso, que el usuario mueve sobre la superficie de la
tableta. La disposición del dispositivo sobre la tableta se refleja exactamente
mediante un cursor que aparece en la pantalla. La tableta suele tener una parte
transparente en la que se dispone algún tipo de marca para alinear de forma precisa
los puntos de referencia. Las tabletas digitalizadoras son dispositivos de entrada de
datos de propósito especial empleados principalmente junto con programas de
dibujo o programas de diseño asistido por computador y pantallas gráficas de alta
resolución. Sobre la tableta pueden disponerse mapas, planos o diagramas y
transferirse de forma precisa a la pantalla.
Vgencfqu
Los teclados, inspirados en las maquinas de escribir tradicionales, son, con
mucho, los dispositivos más comunes para la entrada de datos en los distintos tipos
de computadores. El teclado de una computadora es sólo una colección de
interruptores, aunque estén bien escondidos debajo de las tapas de las teclas. Los
diferentes modelos pueden variar en tamaño, forma y “sensación”, pero fuera de
algunas cuantas teclas, la mayoría de los teclados están distribuidos en una forma
casí idéntica, la distribución de teclas más común usada en la actualidad fue
establecida por el teclado mejorado por IBM con las teclas arregladas en cuatro
grupos. Los dos primeros, el teclado alfanumérico y el teclado numérico, son
usados para introducir textos y números a la computadora.
La teclas alfanuméricas, la parte del teclado que parece una máquina de escribir,
están distribuidas de la misma manera en casi todos los teclados llamada
distribución QWERTY por ser estas las seis primeras letras de la hilera superior. El
teclado numérico, generalmente localizado del lado derecho del teclado, es la parte
que parece una máquina sumadora, con sus diez digitos y los operadores
matemáticos (+,-,* y /).
Las otras dos partes del teclado son las teclas de función y las teclas para
movimiento de cursor. Las teclas de función (F1, F2, etc), generalmente
distribuidas en una hilera a lo largo de la parte superior del teclado, permiten dar
órdenes a la computadora sin tener que teclear largas series de caracteres. Lo que
SOPORTE FÍSICO DE UN COMPUTADOR
307
haga cada tecla de función depende del programa que estés usando. La cuarta parte
del teclado es una serie de teclas para movimiento cuyo uso también depende del
programa que esté ejecutándose.
Cuando se presiona una tecla, por ejemplo la letra A, tal vez se piense que el
teclado simplemente manda esa letra a la computadora, después de todo, eso es lo
que parece que sucede. En realidad, es más complejo: cuando se presionas la tecla,
un pequeño chip dentro de la computadora o el teclado, llamado controlador del
teclado, se percata que una tecla ha sido presionada y coloca un código en parte de
su memoria, llamada memoria temporal (buffer) del teclado, que indica qué tecla
fue presionada. Este código es llamado código de rastreo de la tecla; a
continuación, el controlador del teclado indica a los componentes de procesamiento
de la computadora que algo ha ocurrido en el teclado, sin especificar qué fué, sólo
que algo ocurrió. La señal que el teclado envia a la computadora es un mensaje
especial llamado solicitud de interrupción. El controlador del teclado envia una
solictud de interrupción a la CPU cuando recibe un golpe de tecla. Por ejemplo, si
se teclea una r, el controlador manda inmediatamente una solicitud de interrupción.
Pero si primero, se presiona la tecla de shift para teclear R, el controlador se espera
hasta que la combinación completa de teclas haya sido tecleada.
Cuando los componentes de procesamiento de la computadora reciben la
solicitud de interrupción, el programa que está controlando el sistema evalúa en ese
momento la solicitud para determinar la respuesta apropiada. En el caso de que se
haya presionado una tecla, el programa lee, de la posición indicada de la memoria
temporal del teclado, el código de rastreo de la tecla que se presionó y coloca la
letra tecleada en memoria principal.
TGFGU"["EQPGZKQPGU"GPVTG"EQORWVCFQTGU
Ecdng"eqczkcn
El cable coaxial, algunas veces llamado coax, es ampliamente utilizado para la
televisión por cable y ha suplantado al cable de par trenzado desde hace tiempo
como el medio preferido para las redes. En un cable coaxial hay dos conductores:
uno es un alambre sencillo en el centro del coax; el otro es un forro que cubre al
primer alambre, con un aislante en medio de los dos. Aún cuando no cuenta con
más conductores que un cable de par trenzado, el cable coaxial, debido a su forro,
puede transportar más datos que los tipos más antiguos de cables de par trenzado.
Se usan dos tipos de cable coaxial en las redes: gruesos y delgados. El coaxial
grueso es el estándar más antiguo y rara vez se instala en redes nuevas. El cable
coaxial delgado puede transportar tanta información como el grueso, pero es más
pequeño, más ligero y más fácil de doblar en la esquinas. El cable coaxial actual
puede transportar datos a una velocidad cercana a 10 Mbits por segundo.
308
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
Ecdng"fg"hkdtc"ôrvkec
Un cable de fibra óptica es un fino hilo de vidrio que transmite pulsaciones de
luz, en lugar de frecuencias eléctricas. Cuando un extremo del hilo es expuesto a la
luz, el hilo la transporta a través del mismo hasta el otro extremo, doblándose en las
esquinas con sólo un mínimo de pérdida de energía en el camino.
Debido a que la luz viaja mucho más rápido que la electricidad, el cable de fibra
óptica puede fácilmente transportar datos a 100 Mbits por segundo. Aun cuando el
cable de par trenzado también puede alcanzar la misma velocidad de transferencia
de datos, el cable de fibra óptica es inmune a la interferencia electromagnética, que
representa un problema para el cable de cobre. Teóricamente, una pulsación de luz
podría circundar el ecuador de la tierra en aproximadamente 1/8 de segundo; a una
señal eléctrica le tomaría mucho más tiempo hacer el mismo viaje, y tendría que ser
interceptada y amplificada en numerosos intervalos durante el viaje. La luz que
fluye a través de un cable de fibra óptica también debe ser amplificada pero mucho
menos que la electricidad.
Uno de los problemas con la fibra óptica es la distribución física del cable.
Debido a que el medio de transporte en el mismo es un hilo de vidrio, no puede
doblar las esquinas fácilmente. Un delgado hilo de vidrio es más flexible de lo que
piensas, pero ni remotamente más flexible que un hilo de cable de cobre. El cable
de fibra óptica sólo puede dar la vuelta en aquellas esquinas que tienen un radio de
varios centímetros.
Aún cuando es eficiente, rápido y preciso, el cable de fibra óptica fue hasta hace
poco relativamente caro. Al ir bajando los costos, ha ido aumentando su
popularidad y ahora está revolucionando las telecomunicaciones. En especial, las
compañías de teléfono están cambiando del cable de par trenzado y coaxial a la
fibra óptica como soporte de las llamadas autopistas de la información.
Ecdng"fg"Rct"vtgp|cfq
El cable de par trenzado consta de dos filamentos de cobre, individualmente
cubiertos por plástico, después entrelazados y cubiertos por otra capa de plástico
aislante. A excepción de la capa plástica, nada protege a este tipo de cable de la
interferencia a exterior, por eso también se llama cable de par trenzado no
blindado.
El cable de par trenzado es comúnmente conocido como cable telefónico.
Debido a su disponibilidad y bajo costo, el cable telefónico ganó popularidad en
los albores de la comunicación de datos. El cable de par trenzado se desarrolló a
partir de esa tecnología, pero actualmente se fabrica para especificaciones de
mayor demanda que la de uso de transferencia de voz. Todo lo que se necesita para
conectar un teléfono a un conector de pared es un par plano de cables, pero al
entrelazar los cables se obtiene una señal más fuerte y de mejor calidad.
SOPORTE FÍSICO DE UN COMPUTADOR
309
Eqpgzkqpgu"vgngoâvkecu
Pensemos como es posible, que con la actual extensión de las redes telefónicas
podamos interconectarnos con toda facilidad. La respuesta está en las técnicas de
conmutación de circuitos utilizadas por las centrales telefónicas. En ellas, el equipo
de conmutación recibe e interpreta los dígitos marcados por el abonado llamante e
inicia una cadena de conmutaciones, que permiten la conexión entre dos abonados,
sin que ésta exista de forma permanente. Las primeras centrales se construyeron
utilizando interruptores electromecánicos que han sido posteriormente superados,
utilizando hardware y software, diseñado especialmente para ello (centrales de
conmutación digital).
Estas formas de conexión han afectado la evolucion de los ordenadores, de esta
forma, las máquinas o entes a intercomunicar se denominan estaciones y si estamos
en una red de ordenadores las estaciones decimos que son equipos terminales de
datos. Las líneas de interconexión y conmutadores, se denominan sistema de
transporte o red de transporte que adoptan distintas topologías
Están ocurriendo tantas cosas en la comunicación de datos que es difícil saber
cual es el futuro, veamos un par de las tendencias:
Las redes continuarán haciéndose más sofisticadas, pudíendose esperar que sus
capacidades aumente, y lo que es mas importantee, las técnicas para la
computación par a par y cliente-servidor continuarán incrementando su
flexibilidad. Ello supone una tendencia emocionante, la computación distribuida, la
cual permite a las computadoras compartir el poder de procesamiento, así como
dispositivos y espacio de almacenamiento.
Por otro lado, la comunicación de datos a través del módem se está moviendo
hacía horizontes igualmente prometedores con la aparición de servicios más
valiosos a medida que más gente se conecta y comparte su experiencia.
Gpncegu"kpcnâodtkequ
Al irse haciendo más comunes las comunicaciones de datos, ha habido una
tendencia hacia los medios más flexibles y hacia los que puedan cubrir distancias
más grandes. Varios tipos de enlaces de comunicación inalámbricos
proporcionan estas ventajas. Las redes permanentes con enlaces inalámbricos
también se están haciendo importantes, especialmente en situaciones donde es
difícil cablear.
Las frecuencias de radio pueden ser utilizadas en una escala geográfica amplia y
como ejemplo, los teléfonos celulares móviles transmiten utilizando frecuencias de
radio. Las microondas, que son un tipo de ondas de radio, son a menudo utilizadas
cuando se necesita enviar información a varios kilómetros de distancia. Los enlaces
310
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
de comunicación por microondas requieren de una línea sin obstáculos entre las
dos antenas.
Otro medio, es el uso de stélites, cuando los enlaces de comunicación cubren
miles de kilómetros. Cuando se llama por teléfono alrededor del mundo, la voz
viaja por cable solamente hasta la estación de transmisión de satélite más cercana.
De ahí, la señal es emitida a un satélite, el cual la manda a otra estación de
transmisión cercana al destino de la llamada. Por este medio, como si fuera voz, se
pueden transmitir datos.
Eqortgukôp"fg"fcvqu
Existe algoritmos para compactar la información mediante la representación de
la misma con sucesiónes de bits más cortas; estos algoritmos comprimen los datos
mediante el remplazo de patrones repetidos con símbolos que indican cuál es el
patrón y cuántas veces se repite. El éxito del algoritmo depende en gran parte de la
clase de información que se está comprimiendo. Usualmente, los programas son
muy compactados, sin embargo, los textos y gráficos, pueden ser muy
compresibles, con rangos tan altos como 10:1.
La compresión de datos reduce la cantidad de tiempo requerido para enviar
información de un módem a otro mediante la reducción del volumen de la
información. Los módem que cuentan con técnicas interconstruidas de
comprensión de datos, utilizan Existen varios esquemas para llevar a cabo la
comprensión basada en hardware. La especificación de Microcom MNP Class 5,
comúnmente de 2400 bps. El estándar más popular para comprensión de datos en
módem de alta velocidad es la especificación V.42 bis de CCITT. Puesto que la
MNP5 puede casi duplicar la velocidad de transmisión de un módem, la V.42 bis
casi la cuadruplica.
Por lo tanto, un módem de 2400 bps haciendo una comprensión de datos,
mediante la V.42 bis, tendrá un rendimiento efectivo real de hasta 2400 x 4=9600
bps. De igual forma, un módem de 14 400 bps (V.32 bis) haciendo una
comprensión de datos V.42 bis teóricamente puede alcanzar hasta 14 400 x 4=
57600 bps. Claro que, para que funcione la comprensión de datos por hardware, los
módem emisor y receptor deben soportar un estándar común de comprensión de
datos. La mayoría de los módem pueden determinar y ajustarse automáticamente a
las capacidades de comprensión de otro módem.
Una velocidad de 57 600 bps es el equivalente a 7200 bytes por segundo. Para
tener una idea de lo rápido que es esto, considera que un monitor común puede
mantener 2000 caracteres (80 columnas de caracteres por 25 líneas). A 7200
caracteres por segundo tomaría cerca de un cuarto de segundo actualizar toda la
pantalla, asumiendo que cada posición en la pantalla fuera ocupada por un carácter
(lo cual nunca sucede).
SOPORTE FÍSICO DE UN COMPUTADOR
311
Oqfgo0"Eqttgeekôp"fg"gttqtgu
Cuando las computadoras se comunican a través de las líneas telefónicas, la
información se mueve tan rápido que aun la más pequeña cantidad de electricidad
estática puede causar errores significativos. Un ruido no perceptible en una
conversación telefónica puede causar estragos en la información de la
computadora. Para evitar este problema, los módem y el software de comunicación
deben contar con métodos de recuperación de los errores de transmisión. Uno de
los estándares para la corrección de errores por hardware, es el MNP, que es un
popular protocolo de corrección de errores para módem de baja velocidad (9600
y 14400 bps).
Oqfgo0"Xgnqekfcf"fg"vtcpuokukôp
Con los módem antiguo, la gente utilizaba a menudo el término baud rate
(velocidad en baudios) para describir las velocidades del módem. En aquel
tiempo, el término, aun cuando no era técnicamente correcto, describía
cercanamente el número de bits por segundo (bps) que un módem podía transmitir.
La velocidad en baudios es una medida de la velocidad de modulación, el número
de sucesos de señal separados por segundo, y no de la velocidad de transferencia de
información.
Existen actualmente muchas técnicas para alcanzar velocidades mayores a los
2400 bps, que fué la velocidad establecida por el Comité Consultivo Internacional
Telegráfico y Telefónico de las Naciones Unidas (CCITT).Sin embargo, el primer
estándar establecido por el CCITT, que fue llamado V32, alcanza velocidades de
transmisión de 9600 bps, cuatro veces la velocidad de un módem de 2400 bps. Un
estándar más reciente llamado V32 bis permite a los módem transmitir a 14 400
bps.
Actualmente, 9600 bps es la velocidad estándar para la mayoría de las
transmisiones de fax y el estándar de 14.4 Kbps se está convirtiendo rápidamente
en la norma para los módem, especialmente cuando se necesita transmitir grandes
volúmenes de información.
Tgf"fg"dwu"nkpgcn
Una red de bus lineal, como el bus de una computadora, es un solo conducto al
cual están conectados todos los nodos y dispositivos periféricos de la red. Los
nodos en una red de bus transmiten la información y esperan que ésta no vaya a
chocar con otra información transmitida por otro de los nodos. Si esto ocurre, cada
nodo espera una pequeña cantidad de tiempo al azar, después intenta retransmitir la
información.
Aun cuando la topología de bus lineal es muy común, tiene desventajas
inherentes: la evasión de colisiones y su corrección requiere de la implantación
312
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
adicional de circuitos y software y desgraciadamente una conexión interrumpida
puede echar abajo toda la red.
Tgf"gp"Cpknnq
La topología en anillo conecta a los nodos de la red en una cadena circular,
cada nodo está conectado al siguiente. El último nodo de la cadena se conecta al
primero cerrando al anillo. Con esta metodología, cada nodo examina la
información que es enviada a través del anillo. Si la información no está dirigida al
nodo que la examina, la pasa al siguiente en el anillo.
La implantación más importante de la topología en anillo es el Token Ring de
IBM. El Token Ring tiene una ventaja sustancial ya que no existe peligro de
colisiones debido a que la información siempre fluye en una sola dirección. La
desventaja del anillo es que si se rompe una conexión, se ‘cae’ la red completa.
Tgf"gp"guvtgnnc
Una red en estrella coloca un panel de control al centro de los nodos de la red.
Los bloques de información son dirigidos a través del panel de control central.
hacia sus destinos. Este esquema tiene una ventaja al tener un panel de control que
monitoriza el tráfico y evita las colisiones, y una conexión interrumpida no afecta
al resto de la red. Sin embargo, si se pierde el panel de control central, se cae la red.
Tgfgu"fg"âtgc"nqecn
Una red de área local (LAN) es una red de computadoras de cualquier variedad
que están ubicadas relativamente cerca una de otra y conectadas por un cable
contiguo (o por enlace inalámbrico). Una LAN puede consistir de sólo dos o tres
computadoras interconectadas para compartir recursos, o puede incluir varios
cientos de ellas. Cualquier red que resida dentro de una sola edificación e incluso
dentro de un grupo de edificaciones contiguas, se considera una LAN.
Una LAN permite, a todas las computadoras conectadas a ella, compartir
hardware, software e información. Los recursos más a menudo compartidos son los
dispositivos de discos de almacenamiento e impresoras. Un disco de
almacenamiento compartido en una LAN es llamado servidor de archivos o
servidor de la red. Para los usuarios de la LAN , la red es o debe ser
completamente transparente. Entre mejor sea su implementación, más invisible será
la LAN; idealmente, los usuarios ni siquiera deberían estar conscientes de su
existencia.
Vêepkecu"fg"vtcpuokukqp"fg"fcvqu
SOPORTE FÍSICO DE UN COMPUTADOR
313
Existen diversas técnicas para la transmisión de valores binarios 0 y 1,
dependiendo de la distancia y del soporte físico que se utiliza. A cortas distancias
se emplean presencias y ausencias de voltajes, o una tensión que cambia de un
valor positivo a otro negativo. Cuando se emplea un enlace de fibra óptica de
cualquier longitud, un pulso indica un 1 y la ausencia de señal indica un 0. La
transmisión de datos que se basa en la presencia o ausencia de señales para indicar
un 0 o un 1 se denomina transmisión en banda base. En las comunicaciones a
larga distancia por medio de enlaces por cable o radio se utiliza una técnica más
sofisticada denominada comunicación en banda ancha. En este caso se utiliza un
onda portadora de señales, de alta frecuencia, sobre la que se envían las señales, en
la mayoría de los casos, una variación en la frecuencia, de un tipo sirve para indicar
un 1, y otra variación distinta indicará un 0. Estos sistemas en banda ancha
permiten una mayor velocidad de transmisión de datos que los sistemas en banda
base y son menos sensibles al ruido. Los detalles de las técnicas de transmisión
están fuera del alcance de este libro; es suficiente saber que se utilizan dispositivos
de interfaz en cada uno de los extremos de la línea de transmisión para recibir y
emitir las señales apropiadas para los valores 0 y 1. Los interfaces se ocupan
generalmente de convertir los datos en paralelo que envía el ordenador a datos en
serie, que serán transmitidos por las líneas de comunicación.
Vgngeqowpkecekqpgu"ogfkcpvg"gn"wuq"fg"oqfgo
Un teléfono convierte el sonido de tu voz en una señal eléctrica que viaja a
través de los cables de teléfono, otro teléfono, al otro extremo, vuelve a convertir
esta señal en sonido, de tal forma que la persona con la cual estás hablando pueda
escuchar la voz. Este proceso de convertir la información en una señal que puede
recorrer una línea telefónica se llama modulación. El proceso de convertir las
señales nuevamente en sonido u otra información se llama demodulación. Los
teléfonos cuentan con los circuitos necesarios para modular y demodular las
señales de voz, así el módem (por modulador/demodulador) maneja esta
conversión para los datos de la computadora.
El teléfono toma la voz, la cual es una onda sonora, y la convierte en una
frecuencia electromagnética que cambia para representar volumen y graduación. La
onda sonora y la señal telefónica son señales analógicas (varían en forma continua
al pasar el tiempo). Sin embargo, la computadora puede enviar y recibir
únicamente señales digitales que consisten de ceros y unos separados. El trabajo
del módem es convertir estas cadenas de ceros y unos en frecuencias
electromagnéticas que el teléfono pueda transmitir.
Vkrqu"fg"oqfgo
Los módem externos son cajas que contienen circuitos y lógica para modular
señales de datos. Se conectan a la computadora mediante un puerto serie y al
sistema telefónico mediante un conector normal. En la parte frontal del módem hay
314
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
una hilera de luces que indican el estado del módem y cuando está enviando o
recibiendo información. Una desventaja de los módem externos es que utilizan uno
de los puertos serie.
Un módem interno es una placa de circuitos que se conecta a una de las
ranuras de expansión del computador. Una de las ventajas con los módem internos
es que no tienen muchos cables y clavijas con los cuales batallar.
Algunos módem son capaces de emular a un fax, llamados FAX módem. Si un
FAX módem tiene capacidad de emisión y recepción, puede enviar información de
computadora como un Fax o aceptar imágenes de cualquier máquina de FAX.
Como las otras clases de módem, los FAX módem pueden ser externos o internos.
Vqrqnqiîcu"fg"tgfgu
La topologia de una red es la distribución física de los cables que conectan los
nodos a la misma. Existen tres topologías comunes: bus lineal, en estrella y en
anillo. existe un número de factores a considerar para determinar cuál topología es
la más apropiada para una situación dada. Entre estas consideraciones están el tipo
de computadoras a instalar, el tipo de cableado actualmente en el lugar (si lo hay),
el costo de los componentes y servicios requeridos para implementar la red y el
desempeño deseado.
El bus lineal, la estrella y el anillo se combinan algunas veces para formar
combinaciones de redes híbridas. Una red híbrida en un edificio elevado puede
utilizar un bus lineal que corra de arriba hacia abajo la altura del edificio, y
topologías de anillo u otras en cada piso.
SOPORTE FÍSICO DE UN COMPUTADOR
315
316
FUNDAMENTOS DE INFORMÁTICA Y PROGRAMACIÓN
ARQUITECTURA DE COMPUTADORES ...............................................285
PERIFÉRICOS DE LOS COMPUTADORES............................................294
REDES Y CONEXIONES ENTRE COMPUTADORES ...........................307
Descargar