Programa de computadora

Compartir Imprimir Citar

Un programa de computadora o programa informático es una secuencia o conjunto de instrucciones en un lenguaje de programación para que una computadora las ejecute. Los programas de computadora son un componente del software, que también incluye documentación y otros componentes intangibles.

Un programa de computadora en su forma legible por humanos se llama código fuente. El código fuente necesita otro programa de computadora para ejecutarse porque las computadoras solo pueden ejecutar sus instrucciones de máquina nativas. Por lo tanto, el código fuente puede traducirse a instrucciones de máquina usando el compilador del lenguaje. (Los programas de lenguaje de máquina se traducen utilizando un ensamblador). El archivo resultante se denomina ejecutable. Alternativamente, el código fuente puede ejecutarse dentro del intérprete del lenguaje.

Si se solicita la ejecución del ejecutable, el sistema operativo lo carga en la memoria e inicia un proceso. La unidad central de procesamiento pronto cambiará a este proceso para que pueda obtener, decodificar y luego ejecutar cada instrucción de la máquina.

Si se solicita el código fuente para su ejecución, el sistema operativo carga el intérprete correspondiente en la memoria e inicia un proceso. Luego, el intérprete carga el código fuente en la memoria para traducir y ejecutar cada declaración. Ejecutar el código fuente es más lento que ejecutar un ejecutable. Además, el intérprete debe estar instalado en la computadora.

Ejemplo de programa de computadora

El "¡Hola, mundo!" El programa se utiliza para ilustrar la sintaxis básica de un lenguaje. La sintaxis del lenguaje interpretado Basic (1964) se limitó intencionalmente para que el lenguaje fuera fácil de aprender. Por ejemplo, las variables no se declaran antes de ser utilizadas. Además, las variables se inicializan automáticamente a cero. Aquí hay un programa de computadora de ejemplo, en Basic, para promediar una lista de números:

10 ENTRADA "¿Cuántos números promediar?", A 20 FOR I = 1 TO A 30 INPUT "Ingrese número:", B 40 LET C = C + B 50 NEXT I 60 LET D = C / A 70 PRINT "El promedio es", D 80 END   
      
   
      
  
    
   
 

Una vez que se aprende la mecánica de la programación informática básica, se dispone de lenguajes más sofisticados y potentes para construir grandes sistemas informáticos.

Historia

Las mejoras en el desarrollo de software son el resultado de mejoras en el hardware de la computadora. En cada etapa de la historia del hardware, la tarea de la programación de computadoras cambió drásticamente.

Motor analítico

En 1837, Charles Babbage se inspiró en el telar de Jacquard para intentar construir la Máquina Analítica. Los nombres de los componentes del dispositivo de cálculo se tomaron prestados de la industria textil. En la industria textil, el hilo se traía de la tienda para ser molido. El dispositivo tenía una "tienda" que era una memoria para almacenar 1000 números de 50 dígitos decimales cada uno. Los números de la "tienda" se transfirieron al "molino" para su procesamiento. Se programó utilizando dos juegos de tarjetas perforadas. Un conjunto dirigía la operación y el otro conjunto ingresaba las variables. Sin embargo, después de más de 17,000 libras del dinero del gobierno británico, las miles de ruedas dentadas y engranajes nunca funcionaron completamente juntos.

Ada Lovelace trabajó para Charles Babbage para crear una descripción del motor analítico (1843). La descripción contenía la Nota G que detallaba completamente un método para calcular los números de Bernoulli utilizando el motor analítico. Esta nota es reconocida por algunos historiadores como el primer programa informático del mundo.

Máquina universal de Turing

Máquina universal de Turing.svg

En 1936, Alan Turing presentó la máquina Universal de Turing, un dispositivo teórico que puede modelar cada cálculo. Es una máquina de estado finito que tiene una cinta de lectura/escritura infinitamente larga. La máquina puede mover la cinta de un lado a otro, cambiando su contenido mientras ejecuta un algoritmo. La máquina arranca en el estado inicial, sigue una secuencia de pasos y se detiene cuando llega al estado de parada. Todas las computadoras actuales son Turing completas.

ENIAC

El integrador numérico electrónico y la computadora (ENIAC) se construyó entre julio de 1943 y el otoño de 1945. Era una computadora Turing completa de propósito general que usaba 17,468 tubos de vacío para crear los circuitos. En esencia, era una serie de Pascalines conectados entre sí. Sus 40 unidades pesaban 30 toneladas, ocupaban 1.800 pies cuadrados (167 m) y consumían $ 650 por hora (en moneda de la década de 1940) en electricidad cuando estaban inactivos. Tenía 20 acumuladores de base 10. La programación de la ENIAC llevó hasta dos meses.Tres mesas de funciones estaban sobre ruedas y era necesario trasladarlas a paneles de funciones fijas. Las mesas de funciones se conectaban a los paneles de funciones enchufando pesados ​​cables negros en tableros de conexiones. Cada mesa de funciones tenía 728 perillas giratorias. La programación de ENIAC también implicó configurar algunos de los 3.000 interruptores. La depuración de un programa tomó una semana. Funcionó desde 1947 hasta 1955 en Aberdeen Proving Ground, calculando parámetros de bombas de hidrógeno, prediciendo patrones climáticos y produciendo mesas de tiro para apuntar armas de artillería.

Computadoras con programa almacenado

En lugar de enchufar cables y encender interruptores, una computadora con programa almacenado carga sus instrucciones en la memoria al igual que carga sus datos en la memoria. Como resultado, la computadora podría programarse rápidamente y realizar cálculos a velocidades muy rápidas. Presper Eckert y John Mauchly construyeron la ENIAC. Los dos ingenieros introdujeron el concepto de programa almacenado en un memorando de tres páginas con fecha de febrero de 1944. Posteriormente, en septiembre de 1944, el Dr. John von Neumann comenzó a trabajar en el proyecto ENIAC. El 30 de junio de 1945, von Neumann publicó el primer borrador de un informe sobre el EDVAC que equiparaba las estructuras de la computadora con las estructuras del cerebro humano.El diseño se conoció como la arquitectura de von Neumann. La arquitectura se implementó simultáneamente en las construcciones de las computadoras EDVAC y EDSAC en 1949.

El IBM System/360 (1964) era una línea de seis computadoras, cada una con la misma arquitectura de conjunto de instrucciones. El Model 30 era el más pequeño y menos costoso. Los clientes podían actualizar y conservar el mismo software de aplicación. El Modelo 75 fue el más premium. Cada modelo System/360 presentaba multiprogramación: tener múltiples procesos en la memoria a la vez. Cuando un proceso estaba esperando entrada/salida, otro podía calcular.

IBM planeó que cada modelo se programara utilizando PL/1. Se formó un comité que incluía programadores de COBOL, Fortran y ALGOL. El propósito era desarrollar un lenguaje que fuera completo, fácil de usar, extensible y que reemplazara a Cobol y Fortran. El resultado fue un lenguaje grande y complejo que llevó mucho tiempo compilar.

Las computadoras fabricadas hasta la década de 1970 tenían interruptores en el panel frontal para la programación manual. El programa de computadora fue escrito en papel como referencia. Una instrucción estaba representada por una configuración de ajustes de encendido/apagado. Después de establecer la configuración, se presionó un botón de ejecución. Luego se repitió este proceso. Los programas de computadora también se ingresaban automáticamente a través de cintas de papel o tarjetas perforadas. Después de cargar el medio, la dirección de inicio se estableció a través de interruptores y se presionó el botón de ejecución.

Integración a muy gran escala

Un hito importante en el desarrollo de software fue la invención del circuito de integración a gran escala (VLSI) (1964). Después de la Segunda Guerra Mundial, la tecnología basada en válvulas fue reemplazada por transistores de contacto puntual (1947) y transistores de unión bipolar (finales de la década de 1950) montados en una placa de circuito. Durante la década de 1960, la industria aeroespacial reemplazó la placa de circuito con un chip de circuito integrado.

Robert Noyce, cofundador de Fairchild Semiconductor (1957) e Intel (1968), logró una mejora tecnológica para refinar la producción de transistores de efecto de campo (1963). El objetivo es alterar la resistividad eléctrica y la conductividad de una unión semiconductora. En primer lugar, los minerales de silicato naturales se convierten en varillas de polisilicio mediante el proceso de Siemens. El proceso Czochralski luego convierte las varillas en un silicio monocristalino, cristal boule. Luego, el cristal se corta en rodajas finas para formar un sustrato de oblea. El proceso planar de fotolitografía luego integra transistores unipolares, capacitores, diodos y resistencias en la oblea para construir una matriz de transistores de metal-óxido-semiconductor (MOS).El transistor MOS es el componente principal de los chips de circuitos integrados.

Originalmente, los chips de circuitos integrados tenían su función establecida durante la fabricación. Durante la década de 1960, el control del flujo eléctrico migró a la programación de una matriz de memoria de solo lectura (ROM). La matriz se asemejaba a un arreglo bidimensional de fusibles. El proceso para incrustar instrucciones en la matriz consistía en quemar las conexiones innecesarias. Había tantas conexiones que los programadores de firmware escribieron un programa de computadora en otro chip para supervisar la grabación. La tecnología se conoció como ROM programable. En 1971, Intel instaló el programa de computadora en el chip y lo llamó microprocesador Intel 4004.

Los términos microprocesador y unidad central de procesamiento (CPU) ahora se usan indistintamente. Sin embargo, las CPU son anteriores a los microprocesadores. Por ejemplo, IBM System/360 (1964) tenía una CPU hecha de placas de circuito que contenían componentes discretos sobre sustratos cerámicos.

Saco Estado 8008

El Intel 4004 (1971) fue un microprocesador de 4 bits diseñado para ejecutar la calculadora Busicom. Cinco meses después de su lanzamiento, Intel lanzó el Intel 8008, un microprocesador de 8 bits. Bill Pentz dirigió un equipo en Sacramento State para construir la primera microcomputadora con Intel 8008: Sac State 8008 (1972). Su propósito era almacenar registros médicos de pacientes. La computadora admitía un sistema operativo de disco para ejecutar una unidad de disco duro Memorex de 3 megabytes. Tenía una pantalla a color y un teclado que estaba empaquetado en una sola consola. El sistema operativo del disco se programó utilizando el lenguaje ensamblador básico (BAL) de IBM. La aplicación de historias clínicas se programó mediante un intérprete BASIC.Sin embargo, la computadora fue un callejón sin salida evolutivo porque era extremadamente costosa. Además, fue construido en un laboratorio de una universidad pública para un propósito específico. No obstante, el proyecto contribuyó al desarrollo del conjunto de instrucciones Intel 8080 (1974).

Serie x86

En 1978, el entorno moderno de desarrollo de software comenzó cuando Intel actualizó el Intel 8080 al Intel 8086. Intel simplificó el Intel 8086 para fabricar el Intel 8088 más económico. IBM adoptó el Intel 8088 cuando ingresaron al mercado de las computadoras personales (1981). A medida que aumentó la demanda de los consumidores de computadoras personales, también lo hizo el desarrollo de microprocesadores de Intel. La sucesión de desarrollo se conoce como la serie x86. El lenguaje ensamblador x86 es una familia de instrucciones de máquina compatibles con versiones anteriores. Las instrucciones de la máquina creadas en microprocesadores anteriores se mantuvieron durante las actualizaciones del microprocesador. Esto permitió a los consumidores comprar nuevas computadoras sin tener que comprar un nuevo software de aplicación. Las principales categorías de instrucciones son:

Cambiando el entorno de programación

Los circuitos VLSI permitieron que el entorno de programación avanzara desde una terminal de computadora (hasta la década de 1990) a una computadora con interfaz gráfica de usuario (GUI). Los terminales informáticos limitaban a los programadores a un solo shell que se ejecutaba en un entorno de línea de comandos. Durante la década de 1970, la edición del código fuente a pantalla completa se hizo posible a través de una interfaz de usuario basada en texto. Independientemente de la tecnología disponible, el objetivo es programar en un lenguaje de programación.

Paradigmas y lenguajes de programación

Las características del lenguaje de programación existen para proporcionar bloques de construcción que se combinarán para expresar los ideales de programación. Idealmente, un lenguaje de programación debería:

El estilo de programación de un lenguaje de programación para proporcionar estos componentes básicos puede clasificarse en paradigmas de programación. Por ejemplo, diferentes paradigmas pueden diferenciar:

Cada uno de estos estilos de programación ha contribuido a la síntesis de diferentes lenguajes de programación.

Un lenguaje de programación es un conjunto de palabras clave, símbolos, identificadores y reglas mediante las cuales los programadores pueden comunicar instrucciones a la computadora. Siguen un conjunto de reglas llamadas sintaxis.

Los lenguajes de programación obtienen su base de los lenguajes formales. El propósito de definir una solución en términos de su lenguaje formal es generar un algoritmo para resolver el problema subyacente. Un algoritmo es una secuencia de instrucciones simples que resuelven un problema.

Generaciones de lenguaje de programación.

La evolución del lenguaje de programación comenzó cuando EDSAC (1949) utilizó el primer programa informático almacenado en su arquitectura von Neumann. La programación del EDSAC estaba en la primera generación del lenguaje de programación.

La característica clave de un programa en lenguaje ensamblador es que forma un mapeo uno a uno con su objetivo de lenguaje de máquina correspondiente.

Idiomas imperativos

Los lenguajes imperativos especifican un algoritmo secuencial usando declaraciones, expresiones y sentencias:

Fortran

FORTRAN (1958) se presentó como "El sistema de traducción de fórmulas matemáticas de IBM". Fue diseñado para cálculos científicos, sin instalaciones de manejo de cuerdas. Junto con declaraciones, expresiones y sentencias, admitía:

Tuvo éxito porque:

Sin embargo, los proveedores que no son de IBM también escribieron compiladores de Fortran, pero con una sintaxis que probablemente fallaría en el compilador de IBM. El American National Standards Institute (ANSI) desarrolló el primer estándar Fortran en 1966. En 1978, Fortran 77 se convirtió en el estándar hasta 1991. Fortran 90 admite:

COBOL

COBOL (1959) significa "Lenguaje común orientado a los negocios". Símbolos manipulados en Fortran. Pronto se dio cuenta de que los símbolos no tenían por qué ser números, por lo que se introdujeron las cadenas. El Departamento de Defensa de EE. UU. influyó en el desarrollo de COBOL, y Grace Hopper fue una de las principales contribuyentes. Las declaraciones eran parecidas a las inglesas y detalladas. El objetivo era diseñar un lenguaje para que los gerentes pudieran leer los programas. Sin embargo, la falta de declaraciones estructuradas obstaculizó este objetivo.

El desarrollo de COBOL estuvo estrictamente controlado, por lo que no surgieron dialectos que requirieran estándares ANSI. Como consecuencia, no se modificó durante 15 años hasta 1974. La versión de la década de 1990 sí realizó cambios consecuentes, como la programación orientada a objetos.

Algol

ALGOL (1960) significa "Lenguaje ALGOrítmico". Tuvo una profunda influencia en el diseño de lenguajes de programación. Surgido de un comité de expertos en lenguajes de programación europeos y estadounidenses, utilizaba notación matemática estándar y tenía un diseño estructurado legible. Algol fue el primero en definir su sintaxis utilizando la forma Backus-Naur. Esto condujo a compiladores dirigidos por la sintaxis. Agregó características como:

Los descendientes directos de Algol incluyen a Pascal, Modula-2, Ada, Delphi y Oberon en una rama. En otra rama hay C, C++ y Java.

Básico

BASIC (1964) significa "Código de instrucción simbólica de propósito general para principiantes". Fue desarrollado en Dartmouth College para que todos sus estudiantes lo aprendan. Si un estudiante no pasara a un lenguaje más poderoso, el estudiante aún recordaría el Básico. Se instaló un intérprete básico en las microcomputadoras fabricadas a fines de la década de 1970. A medida que crecía la industria de las microcomputadoras, también lo hacía el lenguaje.

Basic fue pionera en la sesión interactiva. Ofrecía comandos del sistema operativo dentro de su entorno:

Sin embargo, la sintaxis básica era demasiado simple para programas grandes. Los dialectos recientes agregaron estructura y extensiones orientadas a objetos. Visual Basic de Microsoft todavía se usa ampliamente y produce una interfaz gráfica de usuario.

C

El lenguaje de programación C (1973) recibió su nombre porque el lenguaje BCPL fue reemplazado por B, y AT&T Bell Labs llamó a la siguiente versión "C". Su propósito era escribir el sistema operativo UNIX. C es un lenguaje relativamente pequeño, lo que facilita la escritura de compiladores. Su crecimiento reflejó el crecimiento del hardware en la década de 1980. Su crecimiento también se debió a que tiene las facilidades del lenguaje ensamblador, pero utiliza una sintaxis de alto nivel. Agregó características avanzadas como:

C permite que el programador controle qué región de datos de memoria se va a almacenar. Las variables globales y las variables estáticas requieren la menor cantidad de ciclos de reloj para almacenar. La pila se usa automáticamente para las declaraciones de variables estándar. La memoria del montón se devuelve a una variable de puntero desde la malloc()función.

Por otro lado, las declaraciones de variables dentro de main()otras funciones o dentro de los {}delimitadores de bloque son variables locales. Las variables locales también incluyen variables de parámetros formales. Las variables de parámetro se encierran entre paréntesis de definiciones de función. Proporcionan una interfaz para la función.

C++

En la década de 1970, los ingenieros de software necesitaban soporte lingüístico para dividir grandes proyectos en módulos. Una característica obvia era descomponer físicamente proyectos grandes en archivos separados. Una característica menos obvia fue descomponer lógicamente grandes proyectos en tipos de datos abstractos. En ese momento, los lenguajes admitían tipos de datos concretos (escalares) como números enteros, números de coma flotante y cadenas de caracteres. Los tipos de datos concretos tienen su representación como parte de su nombre. Los tipos de datos abstractos son estructuras de tipos de datos concretos, con un nuevo nombre asignado. Por ejemplo, una lista de números enteros podría llamarse integer_list.

En la jerga orientada a objetos, los tipos de datos abstractos se denominan clases. Sin embargo, una clase es solo una definición; no se asigna memoria. Cuando la memoria se asigna a una clase, se llama objeto.

Lenguajes imperativos orientados a objetos desarrollados combinando la necesidad de clases y la necesidad de una programación funcional segura. Una función, en un lenguaje orientado a objetos, se asigna a una clase. Una función asignada se denomina método, función miembro u operación. La programación orientada a objetos está ejecutando operaciones en objetos.

Los lenguajes orientados a objetos admiten una sintaxis para modelar relaciones de subconjunto/superconjunto. En la teoría de conjuntos, un elemento de un subconjunto hereda todos los atributos contenidos en el superconjunto. Por ejemplo, un estudiante es una persona. Por lo tanto, el conjunto de estudiantes es un subconjunto del conjunto de personas. Como resultado, los estudiantes heredan todos los atributos comunes a todas las personas. Además, los estudiantes tienen atributos únicos que otras personas no tienen. Los lenguajes orientados a objetos modelan las relaciones de subconjuntos/superconjuntos mediante la herencia. La programación orientada a objetos se convirtió en el paradigma del lenguaje dominante a fines de la década de 1990.

C++ (1985) se llamó originalmente "C con clases". Fue diseñado para expandir las capacidades de C al agregar las funciones orientadas a objetos del lenguaje Simula.

Un módulo orientado a objetos se compone de dos archivos. El archivo de definiciones se denomina archivo de encabezado. Aquí hay un archivo de encabezado C++ para la clase GRADE en una aplicación escolar simple:

// nota.h 
// -------

// Se utiliza para permitir que varios archivos de origen incluyan 
// este archivo de encabezado sin errores de duplicación. 
// ---------------------------------------------- 
#ifndef GRADO_H 
#definir GRADO_H

clase  GRADO { 
público :
    // Esta es la operación del constructor. 
// ---------------------------------- GRADO (const char letra);    
         

    // Esta es una variable de clase. 
// ------------------------- char letra;    
     

    // Esta es una operación miembro. 
// --------------------------- int grade_numeric (const char letra);    
         

    // Esta es una variable de clase. 
// ------------------------- int numérico;    
     
};
#terminara si

Una operación constructora es una función con el mismo nombre que el nombre de la clase. Se ejecuta cuando la operación de llamada ejecuta la newinstrucción.

El otro archivo de un módulo es el archivo fuente. Aquí hay un archivo fuente de C++ para la clase GRADE en una aplicación escolar simple:

// nota.cpp 
// --------- 
#incluye "nota.h" 

GRADO:: GRADO (const char letra)    
{
    // Hace referencia al objeto usando la palabra clave 'esto'. 
// ---------------------------------------------- esto - > letra = letra;    
      

    // Esto es Cohesión Temporal 
// ------------------------- this -> numeric = grade_numeric (letra);    
        
}

int GRADE:: grade_numeric (const char letra)     
{
    si ((letra == 'A' || letra == 'a'))           
        devolver 4; 
    más
    si ((letra == 'B' || letra == 'b'))           
        devolver 3; 
    más
    si ((letra == 'C' || letra == 'c'))           
        devolver 2; 
    más
    si ((letra == 'D' || letra == 'd'))           
        devolver 1; 
    más
    si ((letra == 'F' || letra == 'f'))           
        devolver 0; 
    más
        devolver -1; 
}

Aquí hay un archivo de encabezado C++ para la clase PERSONA en una aplicación escolar simple:

// persona.h 
// -------- 
#ifndef PERSONA_H 
#define PERSONA_H

clase  PERSONA { 
público :
    PERSONA (const char * nombre);     
    const char * nombre;  
};
#terminara si

Aquí hay un archivo fuente de C++ para la clase PERSONA en una aplicación escolar simple:

// persona.cpp 
// ---------- 
#incluye "persona.h" 

PERSONA:: PERSONA (const char * nombre)     
{
    esto -> nombre = nombre;  
}

Aquí hay un archivo de encabezado C ++ para la clase ESTUDIANTE en una aplicación escolar simple:

// estudiante.h 
// --------- 
#ifndef ESTUDIANTE_H 
#define ESTUDIANTE_H

#include "persona.h" 
#include "grado.h" 

// UN ESTUDIANTE es un subconjunto de PERSONA. 
// -------------------------------- 
clase  ESTUDIANTE : public PERSON {   
público :
    ESTUDIANTE (const char * nombre);     
    GRADO * grado; 
};
#terminara si

Aquí hay un archivo fuente de C++ para la clase ESTUDIANTE en una aplicación escolar simple:

// estudiante.cpp 
// ----------- 
#incluir "estudiante.h" 
#include "persona.h" 

ESTUDIANTE:: ESTUDIANTE (const char * nombre):     
    // Ejecutar el constructor de la superclase PERSONA. 
// ------------------------------------------------ - PERSONA (nombre)    
      
{
    // Nada más que hacer. 
// ------------------- }    

Aquí hay un programa controlador para demostración:

// estudiante_dvr.cpp 
// --------------- 
#include <iostream> 
#include "estudiante.h" 

int principal (vacío)   
{
    ESTUDIANTE * estudiante = nuevo ESTUDIANTE ("El Estudiante");      
    estudiante -> grado = new GRADO ('a');     

    std:: cout // Aviso estudiante hereda el nombre de PERSONA << estudiante -> nombre 
        
         
        << ": Calificación numérica = " 
        << estudiante -> grado -> numérico 
        << " n "; 
	devolver 0; 
}

Aquí hay un archivo MAKE para compilar todo:

# makefile 
# -------- 
todo:  estudiante_dvr

limpio:
    rm estudiante_dvr *.o

estudiante_dvr:  estudiante_dvr. grado cpp. o estudiante. o persona. o  
    c++ estudiante_dvr.cpp grado.o estudiante.o persona.o -o estudiante_dvr

grado.o:  grado. grado cpp. h
    c++ -c grado.cpp

estudiante.o:  estudiante. estudiante de cp. h
    c++ -c estudiante.cpp

persona.o:  persona. persona cpp. h
    c++ -c persona.cpp

Lenguajes declarativos

Los lenguajes imperativos tienen una crítica importante: asignar una expresión a una variable no local puede producir un efecto secundario no deseado. Los lenguajes declarativos generalmente omiten la declaración de asignación y el flujo de control. Describen qué cálculo debe realizarse y no cómo calcularlo. Dos amplias categorías de lenguajes declarativos son los lenguajes funcionales y los lenguajes lógicos.

El principio detrás de un lenguaje funcional es utilizar el cálculo lambda como guía para una semántica bien definida. En matemáticas, una función es una regla que asigna elementos de una expresión a un rango de valores. Considere la función:

times_10(x) = 10 * x

La función asigna la expresión a un rango de valores. Un valor resulta ser 20. Esto ocurre cuando x es 2. Entonces, la aplicación de la función se escribe matemáticamente como: 10 * xtimes_10()

times_10(2) = 20

Un compilador de lenguaje funcional no almacenará este valor en una variable. En cambio, empujará el valor a la pila de la computadora antes de volver a configurar el contador del programa en la función de llamada. La función de llamada sacará el valor de la pila.

Los lenguajes imperativos soportan funciones. Por lo tanto, la programación funcional se puede lograr en un lenguaje imperativo, si el programador usa disciplina. Sin embargo, un lenguaje funcional impondrá esta disciplina al programador a través de su sintaxis. Los lenguajes funcionales tienen una sintaxis adaptada para enfatizar el qué.

Un programa funcional se desarrolla con un conjunto de funciones primitivas seguidas de una sola función de controlador. Considere el fragmento:

function max(a,b){ /* code omitted */}

function min(a,b){ /* code omitted */}

function difference_between_largest_and_smallest(a,b,c) {return max(a,max(b,c)) - min(a, min(b,c));

}

Las primitivas son max()y min(). La función del controlador es difference_between_largest_and_smallest(). Ejecutando:

put(difference_between_largest_and_smallest(10,4,7));dará salida a 6.

Los lenguajes funcionales se utilizan en la investigación informática para explorar nuevas características del lenguaje. Además, su falta de efectos secundarios los ha hecho populares en la programación paralela y la programación concurrente. Sin embargo, los desarrolladores de aplicaciones prefieren las funciones orientadas a objetos de los lenguajes imperativos.

Ceceo

Lisp (1958) significa "LISt Processor". Se adapta a las listas de procesos. Una estructura completa de los datos se forma construyendo listas de listas. En la memoria, se construye una estructura de datos de árbol. Internamente, la estructura de árbol se presta muy bien para funciones recursivas. La sintaxis para construir un árbol es encerrar los elementos separados por espacios entre paréntesis. La siguiente es una lista de tres elementos. Los primeros dos elementos son en sí mismos listas de dos elementos:

((A B) (HELLO WORLD) 94)

Lisp tiene funciones para extraer y reconstruir elementos. La función head()devuelve una lista que contiene el primer elemento de la lista. La función tail()devuelve una lista que contiene todo menos el primer elemento. La función cons()devuelve una lista que es la concatenación de otras listas. Por lo tanto, la siguiente expresión devolverá la lista x:

cons(head(x), tail(x))

Un inconveniente de Lisp es que cuando se anidan muchas funciones, los paréntesis pueden parecer confusos. Los entornos modernos de Lisp ayudan a garantizar la coincidencia de paréntesis. Aparte, Lisp admite las operaciones de lenguaje imperativas de la declaración de asignación y los bucles goto. Además, Lisp no se preocupa por el tipo de datos de los elementos en tiempo de compilación. En su lugar, asigna (y puede reasignar) los tipos de datos en tiempo de ejecución. La asignación del tipo de datos en tiempo de ejecución se denomina vinculación dinámica. Mientras que el enlace dinámico aumenta la flexibilidad del lenguaje, los errores de programación pueden persistir hasta el final del proceso de desarrollo de software.

Escribir programas Lisp grandes, fiables y legibles requiere previsión. Si se planifica adecuadamente, el programa puede ser mucho más breve que un programa de idioma imperativo equivalente. Lisp es ampliamente utilizado en inteligencia artificial. Sin embargo, su uso se ha aceptado solo porque tiene operaciones de lenguaje imperativas, lo que hace posibles los efectos secundarios no deseados.

ML

ML (1973) significa "Metalenguaje". ML comprueba para asegurarse de que solo los datos del mismo tipo se comparen entre sí. Por ejemplo, esta función tiene un parámetro de entrada (un número entero) y devuelve un número entero:

diversión  times_10 (n:  int):  int  =  10  *  n;

ML no es excéntrico entre paréntesis como Lisp. La siguiente es una aplicación de times_10():

veces_10 2

Devuelve "20: int". (Se devuelven tanto los resultados como el tipo de datos).

Al igual que Lisp, ML se adapta a las listas de procesos. A diferencia de Lisp, cada elemento es del mismo tipo de datos. Además, ML asigna el tipo de datos de un elemento en tiempo de compilación. La asignación del tipo de datos en tiempo de compilación se denomina enlace estático. El enlace estático aumenta la confiabilidad porque el compilador verifica el contexto de las variables antes de usarlas.

Prolog (1972) significa "PROGRAMACIÓN EN LÓGICA". Fue diseñado para procesar lenguajes naturales. Los componentes básicos de un programa Prolog son los objetos y sus relaciones con otros objetos. Los objetos se construyen declarando hechos verdaderos sobre ellos.

Los hechos de la teoría de conjuntos se forman asignando objetos a conjuntos. la sintaxis essetName(object).

animal(cat).

animal(mouse).

cat(tom).

mouse(jerry).

Los hechos adjetivos se forman usandoadjective(object).

big(cat).

small(mouse).

Las relaciones se forman utilizando varios elementos dentro de los paréntesis. En nuestro ejemplo tenemos verb(object,object)y verb(adjective,adjective).

eat(mouse,cheese).

eat(big,small).

Después de ingresar todos los hechos y relaciones, se puede hacer una pregunta:¿Tom se comerá a Jerry??- eat(tom,jerry).

El uso de Prolog se ha expandido para convertirse en un lenguaje orientado a objetivos. En una aplicación orientada a objetivos, el objetivo se define proporcionando una lista de subobjetivos. Luego, cada subobjetivo se define proporcionando además una lista de sus subobjetivos, etc. Si un camino de subobjetivos no logra encontrar una solución, entonces ese subobjetivo se retrocede y se intenta sistemáticamente otro camino. Las aplicaciones prácticas incluyen resolver el problema del camino más corto y producir árboles genealógicos.

Programación orientada a objetos

La programación orientada a objetos es un método de programación para ejecutar operaciones (funciones) en objetos. La idea básica es agrupar las características de un fenómeno en un contenedor de objetos y darle un nombre al contenedor. Las operaciones sobre el fenómeno también se agrupan en el contenedor. Programación orientada a objetos desarrollada combinando la necesidad de contenedores y la necesidad de una programación funcional segura. Este método de programación no necesita limitarse a un lenguaje orientado a objetos. En un lenguaje orientado a objetos, un contenedor de objetos se denomina clase. En un lenguaje no orientado a objetos, una estructura de datos (que también se conoce como registro) puede convertirse en un contenedor de objetos. Para convertir una estructura de datos en un contenedor de objetos, las operaciones deben escribirse específicamente para la estructura. La estructura resultante se denomina tipo de datos abstracto. Sin embargo, faltará la herencia. No obstante, esta deficiencia puede ser superada.

Aquí hay un archivo de encabezado del lenguaje de programación C para el tipo de datos abstracto GRADE en una aplicación escolar simple:

/* nota.h */
/* ------- */

/* Se utiliza para permitir que se incluyan varios archivos de origen */
/* este archivo de encabezado sin errores de duplicación. */
/* ---------------------------------------------- */
#ifndef GRADO_H 
#define GRADO_H

estructura typedef { 

    carta de caracteres; 
} GRADO; 

/* Constructor */
/* ----------- */
CALIFICACIÓN * grade_new (letra char);    

int grade_numeric (letra char);    
#terminara si

La grade_new()función realiza el mismo algoritmo que la operación del constructor de C++.

Aquí hay un archivo fuente del lenguaje de programación C para el tipo de datos abstracto GRADE en una aplicación escolar simple:

/* nota.c */
/* ------- */
#include "grado.h" 

CALIFICACIÓN * grade_new (letra char)    
{
    GRADO * grado; 

    /* Asignar memoria de montón */
    /* -------------------- */
    if (! (grado = calloc (1, tamaño de (GRADO))))             
    {
        fprintf (stderr,
                "ERROR en %s/%s/%d: calloc() devolvió vacío. n ",
                __ARCHIVO__,
                __FUNCIÓN__,
                __LINE__); 
        salida (1);  
    }

    grado -> letra = letra;  
    grado de retorno ; 
}

int grade_numeric (letra char)    
{
    si ((letra == 'A' || letra == 'a'))           
        devolver 4; 
    más
    si ((letra == 'B' || letra == 'b'))           
        devolver 3; 
    más
    si ((letra == 'C' || letra == 'c'))           
        devolver 2; 
    más
    si ((letra == 'D' || letra == 'd'))           
        devolver 1; 
    más
    si ((letra == 'F' || letra == 'f'))           
        devolver 0; 
    más
        devolver -1; 
}

En el constructor, la función calloc()se usa en lugar de malloc()porque cada celda de memoria se establecerá en cero.

Aquí hay un archivo de encabezado de lenguaje de programación C para el tipo de datos abstracto PERSON en una aplicación escolar simple:

/* persona.h */
/* -------- */
#ifndef PERSONA_H 
#define PERSONA_H

estructura typedef { 

    char * nombre; 
} PERSONA; 

/* Constructor */
/* ----------- */
PERSONA * person_new (char * nombre);    
#terminara si

Aquí hay un archivo fuente del lenguaje de programación C para el tipo de datos abstracto PERSON en una aplicación escolar simple:

/* persona.c */
/* -------- */
#include "persona.h" 

PERSONA * person_new (char * nombre)    
{
    PERSONA * persona; 

    if (! (persona = calloc (1, tamaño de (PERSONA)))))             
    {
        fprintf (stderr,
                "ERROR en %s/%s/%d: calloc() devolvió vacío. n ",
                __ARCHIVO__,
                __FUNCIÓN__,
                __LINE__); 
        salida (1);  
    }

    persona -> nombre = nombre;  
    persona de regreso ; 
}

Aquí hay un archivo de encabezado de lenguaje de programación C para el tipo de datos abstracto ESTUDIANTE en una aplicación escolar simple:

/* alumno.h */
/* --------- */
#ifndef ESTUDIANTE_H 
#define ESTUDIANTE_H

#include "persona.h" 
#include "grado.h" 

estructura typedef { 

    /* UN ESTUDIANTE es un subconjunto de PERSONA. */
    /* -------------------------------- */
    PERSONA * persona; 

    GRADO * grado; 
} ESTUDIANTE; 

/* Constructor */
/* ----------- */
ESTUDIANTE * estudiante_nuevo (char * nombre);    
#terminara si

Aquí hay un archivo fuente del lenguaje de programación C para el tipo de datos abstracto ESTUDIANTE en una aplicación escolar simple:

/* estudiante.c */
/* --------- */
#include "estudiante.h" 
#include "persona.h" 

ESTUDIANTE * estudiante_nuevo (char * nombre)    
{
    ESTUDIANTE * estudiante; 

    if (! (estudiante = calloc (1, tamaño de (ESTUDIANTE))))             
    {
        fprintf (stderr,
                "ERROR en %s/%s/%d: calloc() devolvió vacío. n ",
                __ARCHIVO__,
                __FUNCIÓN__,
                __LINE__); 
        salida (1);  
    }

    /* Ejecuta el constructor de la superclase PERSONA. */
    /* ------------------------------------------------ - */
    estudiante -> persona = persona_nueva (nombre);    
    estudiante de regreso ; 
}

Aquí hay un programa controlador para demostración:

/* estudiante_dvr.c */
/* -------------*/
#incluir <stdio.h> 
#include "estudiante.h" 

int principal (vacío)   
{
    ESTUDIANTE * estudiante = estudiante_nuevo ("El estudiante");     
    estudiante -> grado = grado_nuevo ('a');    

    printf ("%s: Nota numérica = %d n ", 
            /* Mientras que existe un subconjunto, no existe la herencia. */
            estudiante -> persona -> nombre,
            /* La programación funcional está ejecutando funciones justo a tiempo (JIT) */
            grade_numeric (estudiante -> grado -> letra));   

	devolver 0; 
}

Aquí hay un archivo MAKE para compilar todo:

# makefile 
# -------- 
todo:  estudiante_dvr

limpio:
    rm estudiante_dvr *.o

estudiante_dvr:  estudiante_dvr. grado c. o estudiante. o persona. o  
    gcc estudiante_dvr.c grado.o estudiante.o persona.o -o estudiante_dvr

grado.o:  grado. grado c. h
    gcc -c grado.c

estudiante.o:  estudiante. estudiante c. h
    gcc -c estudiante.c

persona.o:  persona. persona c. h
    gcc -c persona.c

La estrategia formal para construir objetos orientados a objetos es:

Por ejemplo:

Sintaxis y semántica

La sintaxis de un lenguaje de programación es una lista de reglas de producción que gobiernan su forma. La forma de un lenguaje de programación es la ubicación correcta de sus declaraciones, expresiones y sentencias. Complementando la sintaxis de un lenguaje está su semántica. La semántica describe los significados asociados a varias construcciones sintácticas. Una construcción sintáctica puede necesitar una descripción semántica porque una forma puede tener una interpretación no válida. Además, diferentes idiomas pueden tener la misma sintaxis; sin embargo, sus comportamientos pueden ser diferentes.

La sintaxis de un lenguaje se describe formalmente enumerando las reglas de producción. Mientras que la sintaxis de un lenguaje natural es extremadamente complicada, un subconjunto del idioma inglés puede tener esta lista de reglas de producción:

  1. una oración se compone de un sintagma nominal seguido de un sintagma verbal;
  2. un sintagma nominal se compone de un artículo seguido de un adjetivo seguido de un sustantivo;
  3. un sintagma verbal se compone de un verbo seguido de un sintagma nominal;
  4. un artículo es 'el';
  5. un adjetivo es 'grande' o
  6. un adjetivo es 'pequeño';
  7. un sustantivo es 'gato' o
  8. un sustantivo es 'ratón';
  9. un verbo es 'come';

Las palabras en negrita se conocen como "no terminales". Las palabras entre comillas simples se conocen como "terminales".

A partir de esta lista de reglas de producción, se pueden formar oraciones completas usando una serie de reemplazos. El proceso consiste en reemplazar los no terminales con un no terminal válido o un terminal válido. El proceso de reemplazo se repite hasta que solo quedan terminales. Una oración válida es:

Sin embargo, otra combinación da como resultado una oración inválida:

Por lo tanto, es necesaria una semántica para describir correctamente el significado de una actividad de comer.

Un método de enumeración de reglas de producción se denomina formulario Backus-Naur (BNF). BNF describe la sintaxis de un lenguaje y en sí mismo tiene una sintaxis. Esta definición recursiva es un ejemplo de metalenguaje. La sintaxis de BNF incluye:

Usando BNF, un subconjunto del idioma inglés puede tener esta lista de reglas de producción:

< oración >::=  < frase nominal >< frase verbal > 
< frase nominal >::=  < artículo >< adjetivo >< sustantivo > 
< frase verbal >::=  < verbo >< frase nominal > 
< artículo >::= el
 < adjetivo >::= grande | pequeño
 < sustantivo >::= gato | ratón
 < verbo >::= come

Usando BNF, un entero con signo tiene la lista de reglas de producción:

< entero con signo >::=  < signo >< entero > 
< signo >::= + | -
 < entero >::=  < dígito > | < dígito >< entero > 
< dígito >::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

Observe la regla de producción recursiva:

< entero >::=  < dígito > | < dígito >< entero >

Esto permite un número infinito de posibilidades. Por lo tanto, es necesaria una semántica para describir una limitación del número de dígitos.

Observe la posibilidad del cero inicial en las reglas de producción:

< entero >::=  < dígito > | < dígito >< entero > 
< dígito >::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

Por lo tanto, es necesaria una semántica para describir que los ceros iniciales deben ignorarse.

Hay dos métodos formales disponibles para describir la semántica. Son la semántica denotacional y la semántica axiomática.

Ingeniería de software y programación informática

La ingeniería de software es una variedad de técnicas para producir software de calidad. La programación informática es el proceso de escribir o editar código fuente. En un entorno formal, un analista de sistemas recopilará información de los gerentes sobre todos los procesos de la organización para automatizar. Este profesional luego prepara un plan detallado para el sistema nuevo o modificado. El plan es análogo al plano de un arquitecto.

Objetivos de rendimiento

El analista de sistemas tiene como objetivo entregar la información adecuada a la persona adecuada en el momento adecuado. Los factores críticos para lograr este objetivo son:

  1. La calidad de la salida. ¿El resultado es útil para la toma de decisiones?
  2. La precisión de la salida. ¿Refleja la situación real?
  3. El formato de la salida. ¿Se entiende fácilmente el resultado?
  4. La velocidad de la salida. La información sensible al tiempo es importante cuando se comunica con el cliente en tiempo real.

Objetivos de costes

El logro de los objetivos de desempeño debe equilibrarse con todos los costos, incluidos:

  1. Costos de desarrollo.
  2. Costos de singularidad. Un sistema reutilizable puede ser costoso. Sin embargo, podría preferirse a un sistema de uso limitado.
  3. Costos de hardware.
  4. Costos de operacion.

La aplicación de un proceso de desarrollo de sistemas mitigará el axioma: cuanto más tarde en el proceso se detecta un error, más costoso es corregirlo.

Modelo de cascada

El modelo en cascada es una implementación de un proceso de desarrollo de sistemas. Como implica la etiqueta de la cascada, las fases básicas se superponen entre sí:

  1. La fase de investigación consiste en comprender el problema subyacente.
  2. La fase de análisis consiste en comprender las posibles soluciones.
  3. La fase de diseño consiste en planificar la mejor solución.
  4. La fase de implementación consiste en programar la mejor solución.
  5. La fase de mantenimiento dura toda la vida del sistema. Es posible que sea necesario realizar cambios en el sistema después de su implementación. Pueden existir fallas, incluidas fallas de especificación, fallas de diseño o fallas de codificación. Pueden ser necesarias mejoras. La adaptación puede ser necesaria para reaccionar a un entorno cambiante.

Programador

Un programador de computadoras es un especialista responsable de escribir o modificar el código fuente para implementar el plan detallado. Es probable que se necesite un equipo de programación porque la mayoría de los sistemas son demasiado grandes para que los complete un solo programador. Sin embargo, es posible que agregar programadores a un proyecto no acorte el tiempo de finalización. En cambio, puede disminuir la calidad del sistema. Para ser efectivos, los módulos del programa deben definirse y distribuirse entre los miembros del equipo. Además, los miembros del equipo deben interactuar entre sí de manera significativa y efectiva.

Los programadores de computadoras pueden estar programando en lo pequeño: programando dentro de un solo módulo. Lo más probable es que un módulo ejecute módulos ubicados en otros archivos de código fuente. Por lo tanto, los programadores de computadoras pueden estar programando en general: módulos de programación para que se acoplen entre sí de manera efectiva.

Módulos del programa

La programación modular es una técnica para refinar programas de lenguaje imperativo. Los programas refinados pueden reducir el tamaño del software, separar las responsabilidades y, por lo tanto, mitigar el envejecimiento del software. Un módulo de programa es una secuencia de declaraciones que están limitadas dentro de un bloque y juntas identificadas por un nombre. Los módulos tienen una función, contexto y lógica:

El nombre del módulo debe derivarse primero de su función y luego de su contexto. Su lógica no debe ser parte del nombre. Por ejemplo, function compute_square_root(x)o function compute_square_root_integer(i: integer)son nombres de módulos apropiados. Sin embargo, function compute_square_root_by_division(x)no lo es.

El grado de interacción dentro de un módulo es su nivel de cohesión. La cohesión es un juicio de la relación entre el nombre de un módulo y su función. El grado de interacción entre módulos es el nivel de acoplamiento. El acoplamiento es un juicio de la relación entre el contexto de un módulo y los elementos sobre los que se está realizando.

Cohesión

Los niveles de cohesión de peor a mejor son:

Acoplamiento

Los niveles de acoplamiento de peor a mejor son:

Análisis de flujo de datos

El análisis de flujo de datos es un método de diseño utilizado para lograr módulos de cohesión funcional y acoplamiento de datos. La entrada al método es un diagrama de flujo de datos. Un diagrama de flujo de datos es un conjunto de óvalos que representan módulos. El nombre de cada módulo se muestra dentro de su óvalo. Los módulos pueden estar en el nivel ejecutable o en el nivel de función.

El diagrama también tiene flechas que conectan los módulos entre sí. Las flechas que apuntan a los módulos representan un conjunto de entradas. Cada módulo debe tener solo una flecha que apunte desde él para representar su único objeto de salida. (Opcionalmente, una flecha de excepción adicional señala). Una cadena de margaritas de óvalos transmitirá un algoritmo completo. Los módulos de entrada deben comenzar el diagrama. Los módulos de entrada deben conectarse a los módulos de transformación. Los módulos de transformación deben conectarse a los módulos de salida.

Categorías funcionales

Los programas de computadora pueden clasificarse según líneas funcionales. Las principales categorías funcionales son software de aplicación y software de sistema. El software del sistema incluye el sistema operativo, que combina el hardware de la computadora con el software de la aplicación. El propósito del sistema operativo es proporcionar un entorno en el que el software de aplicación se ejecute de manera conveniente y eficiente. Tanto el software de aplicación como el software del sistema ejecutan programas de utilidad. A nivel de hardware, un programa de microcódigo controla los circuitos a lo largo de la unidad central de procesamiento.

Software de la aplicacion

El software de aplicación es la clave para desbloquear el potencial del sistema informático. El software de aplicaciones empresariales incluye aplicaciones de contabilidad, personal, clientes y proveedores. Los ejemplos incluyen la planificación de recursos empresariales, la gestión de relaciones con los clientes y el software de gestión de la cadena de suministro.

Las aplicaciones empresariales pueden desarrollarse internamente como un software propietario único en su tipo. Alternativamente, se pueden comprar como software listo para usar. El software comprado puede modificarse para proporcionar software personalizado. Si se personaliza la aplicación, se utilizan los recursos de la empresa o se subcontratan los recursos. El desarrollo de software subcontratado puede ser del proveedor de software original o de un desarrollador externo.

Las ventajas del software propietario son las funciones y los informes pueden ser exactos según las especificaciones. La gerencia también puede estar involucrada en el proceso de desarrollo y ofrecer un nivel de control. La gerencia puede decidir contrarrestar la nueva iniciativa de un competidor o implementar un requisito del cliente o proveedor. Una fusión o adquisición requerirá cambios en el software empresarial. Las desventajas del software propietario son que los costos de tiempo y recursos pueden ser elevados. Además, pueden acechar riesgos relacionados con las características y el rendimiento.

Las ventajas del software listo para usar son sus costos iniciales identificables, las necesidades básicas deben satisfacerse y su rendimiento y confiabilidad tienen un historial. Las desventajas del software comercial son que puede tener funciones innecesarias que confunden a los usuarios finales, puede carecer de funciones que la empresa necesita y el flujo de datos puede no coincidir con los procesos de trabajo de la empresa.

Un enfoque para obtener económicamente una aplicación empresarial personalizada es a través de un proveedor de servicios de aplicaciones. Las empresas especializadas proporcionan el hardware, el software personalizado y la asistencia al usuario final. Pueden acelerar el desarrollo de nuevas aplicaciones porque cuentan con personal capacitado en sistemas de información. La mayor ventaja es que libera recursos internos de la dotación de personal y la gestión de proyectos informáticos complejos. Muchos proveedores de servicios de aplicaciones se dirigen a empresas pequeñas y de rápido crecimiento con recursos de sistemas de información limitados. Por otro lado, es probable que las empresas más grandes con sistemas importantes cuenten con su infraestructura técnica. Un riesgo es tener que confiar en una organización externa con información confidencial. Otro riesgo es tener que confiar en la confiabilidad de la infraestructura del proveedor.

Sistema operativo

Un sistema operativo es el software de bajo nivel que admite las funciones básicas de una computadora, como la programación de procesos y el control de periféricos.

En la década de 1950, el programador, que también era el operador, escribía un programa y lo ejecutaba. Una vez que el programa terminó de ejecutarse, es posible que la salida se haya impreso o se haya perforado en cinta de papel o tarjetas para su posterior procesamiento. La mayoría de las veces el programa no funcionó. Luego, el programador miró las luces de la consola y jugueteó con los interruptores de la consola. Si tenía menos suerte, se hacía una copia impresa de la memoria para su posterior estudio. En la década de 1960, los programadores redujeron la cantidad de tiempo perdido al automatizar el trabajo del operador. Un programa llamado sistema operativo se mantuvo en la computadora en todo momento.

El término sistema operativo puede referirse a dos niveles de software. El sistema operativo puede referirse al programa kernel que administra los procesos, la memoria y los dispositivos. En términos más generales, el sistema operativo puede referirse al paquete completo del software central. El paquete incluye un programa kernel, un intérprete de línea de comandos, una interfaz gráfica de usuario, programas de utilidad y un editor.

Programa del núcleo

El propósito principal del kernel es administrar los recursos limitados de una computadora:

Originalmente, los sistemas operativos se programaban en ensamblador; sin embargo, los sistemas operativos modernos suelen estar escritos en lenguajes de nivel superior como C, Objective-C y Swift.

Programa de utilidad

Un programa de utilidad está diseñado para ayudar a la administración del sistema y la ejecución del software. Los sistemas operativos ejecutan programas de utilidad de hardware para comprobar el estado de las unidades de disco, la memoria, los altavoces y las impresoras. Un programa de utilidad puede optimizar la ubicación de un archivo en un disco lleno. Los programas de utilidades del sistema supervisan el rendimiento del hardware y de la red. Cuando una métrica está fuera de un rango aceptable, se genera una alerta de activación.

Los programas de utilidad incluyen programas de compresión para que los archivos de datos se almacenen en menos espacio en disco. Los programas comprimidos también ahorran tiempo cuando los archivos de datos se transmiten a través de la red. Los programas de utilidad pueden ordenar y combinar conjuntos de datos. Los programas de utilidad detectan virus informáticos.

Programa de microcódigo

Un programa de microcódigo es el intérprete de nivel inferior que controla la ruta de datos de las computadoras controladas por software. (Los avances en hardware han migrado estas operaciones a los circuitos de ejecución de hardware). Las instrucciones de microcódigo permiten al programador implementar más fácilmente el nivel lógico digital: el hardware real de la computadora. El nivel de lógica digital es el límite entre la informática y la ingeniería informática.

Una puerta lógica es un pequeño transistor que puede devolver una de dos señales: encendido o apagado.

Estas cinco puertas forman los componentes básicos del álgebra binaria: las funciones lógicas digitales de la computadora.

Las instrucciones de microcódigo son mnemónicos que los programadores pueden usar para ejecutar funciones lógicas digitales en lugar de formarlas en álgebra binaria. Se almacenan en el almacén de control de una unidad central de procesamiento (CPU). Estas instrucciones a nivel de hardware mueven datos a lo largo de la ruta de datos.

El ciclo de microinstrucciones comienza cuando el microsecuenciador usa su contador de microprogramas para obtener la siguiente instrucción de máquina de la memoria de acceso aleatorio. El siguiente paso es decodificar la instrucción de la máquina seleccionando la línea de salida adecuada para el módulo de hardware. El paso final es ejecutar la instrucción utilizando el conjunto de puertas del módulo de hardware.

Las instrucciones para realizar aritmética se pasan a través de una unidad lógica aritmética (ALU). La ALU tiene circuitos para realizar operaciones elementales para sumar, desplazar y comparar números enteros. Al combinar y enlazar las operaciones elementales a través de la ALU, la CPU realiza su aritmética compleja.

Las instrucciones de microcódigo mueven datos entre la CPU y el controlador de memoria. Las instrucciones de microcódigo del controlador de memoria manipulan dos registros. El registro de dirección de memoria se utiliza para acceder a la dirección de cada celda de memoria. El registro de datos de la memoria se utiliza para configurar y leer el contenido de cada celda.

Las instrucciones de microcódigo mueven datos entre la CPU y los muchos buses de la computadora. El bus del controlador de disco escribe y lee desde las unidades de disco duro. Los datos también se mueven entre la CPU y otras unidades funcionales a través del bus expreso de interconexión de componentes periféricos.