Está en la página 1de 25

2.

2 Algunos conceptos básicos de fortran 90


El programa escrito en el ejemplo 2.1 es muy simple, pero contiene muchos de los
elementos básicos y conceptos básicos que se aplican a todos los programas Fortran 90.
Por lo tanto, lo examinaremos cuidadosamente línea por línea para establecer estos
conceptos antes de pasar a examinar el lenguaje en sí mismo con detalle. Sin embargo,
antes de hacerlo, debemos enfatizar que el código que se muestra en el Ejemplo 2.1 no
es todo el programa, ya que el procedimiento Calculate_circle también es parte del mismo
programa Lo que se muestra es simplemente el programa principal o, más correctamente,
la unidad del programa principal.
Cada unidad principal del programa debe comenzar con una instrucción PROGRAM que
consta de la palabra PROGRAMA seguida del nombre del programa. Este nombre debe
seguir las reglas que se aplican a todos los nombres de Fortran 90, a saber:

 Debe comenzar con una letra, ya sea mayúscula o minúscula


 Solo puede contener las letras A-Z y a-z, los dígitos 0-9 y el carácter de subrayado
 Debe constar de un máximo de 31 caracteres.

Primeros pasos en la programación de Fortran 90


En Fortran 90 nombres y palabras clave, las letras mayúsculas y minúsculas se tratan
como idénticas, pero el programador puede utilizarlas para ayudar a la legibilidad del
programa.
El nombre del programa debe elegirse para indicar lo que hace el programa y debe ser
diferente de cualquier otro nombre utilizado para otros fines en otras partes del programa.
Puede haber cualquier cantidad de espacios en blanco entre las palabras sucesivas en
una declaración Fortran 90, siempre que haya al menos una, pero el compilador las
tratará como si hubiera una sola cuando esté analizando el programa. No es necesario
incluir espacios en blanco entre elementos sucesivos en una lista separada por comas u
otros caracteres de puntuación, aunque pueden incluirse si se desea para que el
programa sea más fácil de leer. Sin embargo, no está permitido incluir espacios dentro de
una palabra clave Fortran o un nombre especificado por el usuario, excepto cuando se
usa el estilo de programación de forma fija anterior que se describe en la Sección 2.6.
IMPLICIT NONE
Esta es una declaración especial que se utiliza para inhibir una característica
particularmente indeseable de Fortran que se transfiere de versiones anteriores de
Fortran. Explicaremos su significado completo en el Capítulo 3; por el momento,
simplemente indicaremos que siempre debe colocarse inmediatamente después de la
instrucción PROGRAM.
Un comentario es una línea, o parte de una línea, que se incluye únicamente para
información del programador o de cualquier otra persona que lea el programa; es
ignorado por el compilador. Una línea de comentario es una línea cuyo primer carácter no
en blanco es un signo de exclamación, ! ; alternativamente, un comentario, precedido por
un signo de exclamación, puede seguir cualquier declaración o declaraciones de Fortran
en una línea, como se puede ver más adelante en este programa. Normalmente
usaremos líneas de comentarios en programas de ejemplo, pero también usaremos
comentarios finales cuando estos sean más apropiados.
Siempre debe usar comentarios generosamente en sus programas para explicar cualquier
cosa que no sea obvia en el código mismo. Siempre debe errar con precaución, ya que lo
que es claro para usted puede no ser claro para otra persona que tenga que leer su
programa. De hecho, ¡puede que ni siquiera te quede claro seis meses después de que
se escribió el código!
La primera de estas líneas es un comentario que indica que la siguiente línea contiene
una o más declaraciones variables. No es obligatorio, pero tales comentarios ayudan al
lector a seguir el programa más fácilmente.
La siguiente línea es una declaración de especificación y proporciona información
importante sobre el programa al compilador. En este caso, especifica que los nueve
nombres xl, y1, ..., r son los nombres de las variables que se utilizarán para contener
información numérica. Como veremos en el Capítulo 3, hay varias formas en que la
información numérica puede almacenarse en una computadora, pero el tipo más común
se conoce como un número real. Examinaremos la sintaxis detallada de las declaraciones
de variables en el Capítulo 3.
El siguiente bloque de declaraciones está precedido por el comentario Paso 1,
simplemente para indicar que estas declaraciones corresponden al paso 1 de nuestro plan
de estructura.
Las siguientes dos declaraciones son las primeras declaraciones que se deben obedecer
durante la ejecución del programa y se denominan declaraciones ejecutables. Estas
declaraciones ejecutables particulares se conocen como declaraciones de salida dirigidas
por lista y harán que el texto contenido entre comillas (o comillas) se muestre en el
dispositivo de salida predeterminado de su computadora, probablemente en la pantalla.
Examinaremos la forma en que funcionan estas declaraciones en el Capítulo 3.
Esta declaración está claramente relacionada con las dos declaraciones anteriores y tiene
una estructura muy similar. Se llama una declaración de entrada dirigida por la lista y
leerá información del teclado u otro dispositivo de entrada predeterminado. Se discutirá en
detalle en el Capítulo 3. Observe el uso de un comentario final.
Ahora pasamos al paso 2 del plan de estructura. La instrucción CALL hace que el
procesamiento de la unidad principal del programa se interrumpa y que el procesamiento
continúe con el procedimiento, o subrutina, cuyo nombre se proporciona en la instrucción.
Por lo tanto, como anticipamos en nuestro plan de estructura, no necesitamos saber en
esta etapa (o tal vez, si alguien más lo escribe) cómo el procedimiento calculará los
coeficientes de la ecuación que define el círculo requerido.
los elementos encerrados entre paréntesis después del nombre del procedimiento se
conocen como argumentos y se utilizan para transmitir información entre el programa
principal y el procedimiento; en este caso, la información relevante requerida por el
procedimiento son las coordenadas proporcionadas por el usuario, mientras que la
información devuelta por el procedimiento serán las coordenadas del centro del círculo y
su radio. Investigaremos la forma en que se utilizan y escriben los procedimientos en el
Capítulo 4.
El paso 3 del plan de estructura se relaciona con la visualización de los resultados
requeridos.
La primera declaración PRINT, sin embargo, incorpora un nuevo concepto: el de una línea
de continuación. Si el último carácter no en blanco de una línea es un signo "&", entonces,
esto es una indicación de que la declaración continúa en la siguiente línea.
Hay dos casos aquí. Si, como en este caso, el ampersand ocurre en un contexto de
caracteres, es decir, en el medio de una cadena de caracteres encerrada entre comillas (o
una encerrada en apóstrofes), entonces el primer carácter no en blanco en la línea
siguiente también debe ser un ampersand, y la cadena de caracteres continúa del
carácter después de ese ampersand. Por lo tanto, las dos líneas anteriores son idénticas
a la línea única.
La otra situación es donde el primer signo "&" no ocurre dentro de una cadena de
caracteres entre comillas o apóstrofes. En este caso hay dos posibilidades. La primera es
que, como en el caso de la cadena de caracteres, el primer carácter que no está en
blanco de la siguiente línea es un ampersand, en cuyo caso el efecto es igual que antes.
Sin embargo, si el primer carácter que no está en blanco en la siguiente línea no es un
ampersand, entonces el efecto es como si toda esa línea sigue a la anterior (excluyendo
el ampersand).
que se trataría como si hubiera varios espacios antes de a, aunque, como esos espacios
se encuentran entre los elementos de la lista de argumentos, no importan.
Estas dos declaraciones PRINT son diferentes de las anteriores en que imprimirán
información variable, así como cadenas de caracteres constantes. Debería ser obvio para
el lector que imprimirán o mostrarán el texto apropiado seguido del valor de la variable o
variables especificadas, según lo calculado por el procedimiento Calculate_circle. Este
uso extendido se describirá en detalle en el Capítulo 3.
La declaración final de un programa debe ser una declaración END. En este contexto,
puede tomar tres formas:
END, END PROGRAM, END PROGRAM nombre
donde nombre, si está presente, debe ser el mismo que el nombre en la instrucción
PROGRAM correspondiente. En general, es una buena práctica y hace que el programa
sea más fácil de seguir, para utilizar la tercera forma completa de la declaración, como
haremos en todos los ejemplos de este libro.
Como podría esperarse, la ejecución de la instrucción END pone fin a la ejecución del
programa y el control se devuelve al sistema operativo de la computadora.
2.3 Ejecutar programas de Fortran en una computadora.
En las secciones anteriores hemos considerado un programa Fortran de forma aislada,
con poca referencia al método por el cual el programa se ingresa a la computadora, se
compila y se ejecuta. Esta omisión es deliberada y se debe al hecho de que, si bien el
lenguaje Fortran está estandarizado, el sistema operativo de la computadora no lo es. Por
lo tanto, nos desviaremos un poco en este punto y veremos los principios generales del
sistema informático general antes de volver a discutir el idioma Fortran 90 en detalle. En
los primeros días de la informática, los programadores tenían que hacer todo por sí
mismos. Cargarían sus programas (probablemente escritos en un lenguaje ensamblador o
incluso código de máquina) y presionarían los botones apropiados en la máquina para
que funcione. Cuando un programa requería datos, los escribía o, más probablemente,
cargaba algunas tarjetas de datos. Cuando un programa quería imprimir resultados, los
programadores se aseguraban de que la impresora (u otro dispositivo de salida) estaba
listo. En poco tiempo, las computadoras se desarrollaron en dos direcciones: primero, se
agregaron cintas magnéticas (y luego discos) para proporcionar una tienda de respaldo, y
en segundo lugar, los idiomas de alto nivel como Fortran estuvieron disponibles. Ahora los
programadores tenían que cargar primero el compilador y hacer que ingresara sus
programas como datos (de un tipo especial).
El programa compilado (posiblemente en tarjetas perforadas binarias producidas por el
compilador) se ingresaría como antes. Además, si se requería algún almacenamiento de
archivos, los programadores tenían que cargar las cintas correctas. En algunos casos, se
empleó un operador a tiempo completo para llevar a cabo todas estas tareas, pero esto,
por supuesto, significaba que se requerían instrucciones detalladas para garantizar que el
trabajo se procesara correctamente, y muchos programadores todavía preferían ejecutar
sus propios programas.
Un gran cambio fue anunciado por el desarrollo en la Universidad de Manchester, en Gran
Bretaña, del sistema de multiprogramación para la computadora Atlas. Esto aprovechó la
alta velocidad de los fondos aritméticos y lógicos de una computadora en comparación
con sus fondos de entrada / salida para procesar varios programas aparentemente
simultáneamente. El efecto es similar al experimentado por los jugadores de ajedrez
aficionados cuando se enfrentan a un maestro de ajedrez en una pantalla simultánea,
donde el master juega contra varios oponentes al mismo tiempo. De hecho, por supuesto,
el maestro se mueve de un tablero a otro, pero, debido a su mayor habilidad y velocidad
para evaluar las posiciones de las piezas, el maestro parece que cada oponente les
dedica la mayor parte del tiempo. . El sistema Atlas aprovechó los retrasos (relativamente)
largos durante la entrada o salida de incluso un solo número para abandonar ese
programa (cuya entrada / salida podría proceder de forma autónoma) y comenzar a
procesar otro.
El siguiente desarrollo importante tuvo lugar más o menos al mismo tiempo tanto en
Dartmouth College como en el Instituto de Tecnología de Massachusetts en los EE. UU.,
Y condujo al concepto de tiempo compartido, que colocó al usuario en un terminal a
través del cual la mayoría de las entradas / salidas tuvo lugar, y cada usuario tuvo un
pequeño intervalo de tiempo por turno. La velocidad mucho más lenta de un terminal
permitió que se ejecutaran más programas a la vez, pero, debido a que los usuarios se
comunicaban directamente con la computadora, su trabajo se procesó mucho más rápido
en este nuevo modo interactivo de operación de lo que era posible con el trabajo por
lotes.
El advenimiento de la primera multiprogramación y luego el tiempo compartido significaba
que ya no era posible que un programador, o incluso un operador a tiempo completo,
llevara a cabo todas las tareas de rutina asociadas con la carga y ejecución de un
programa; Demasiadas cosas estaban sucediendo en diferentes trabajos al mismo
tiempo. Como la computadora ahora estaba haciendo varias cosas a la vez, era natural
que se le diera la tarea adicional de organizar su propio trabajo. Por lo tanto, se
escribieron programas especiales, llamados sistemas operativos, que permitieron a un
programador definir lo que se requería en forma de instrucciones especiales, y causaron
que la computadora llevara a cabo estas instrucciones. Lo que surgió gradualmente
fueron nuevos lenguajes (lenguajes de control de trabajos) con los cuales los
programadores instruyeron a la computadora cómo ejecutar sus trabajos.
Con la llegada de los microordenadores y las estaciones de trabajo personales en la
década de 1980, la situación cambió nuevamente, y aunque siempre existe alguna forma
de lenguaje del sistema operativo, a menudo se oculta a los usuarios, que simplemente
escriben un solo comando en sus teclados o seleccionan un símbolo apropiado con un
mouse.
Sin embargo, se requiere alguna acción para ejecutar un programa Fortran en una
computadora en particular e identificar cualquier requisito específico, y esta acción será
específica para el sistema informático y el compilador en particular que se esté utilizando.

2.4 Errores en programas


Es un hecho desafortunado que los programas a menudo (incluso podría decirse que
usualmente) contienen errores. Estos se dividen en dos grupos distintos: errores
sintácticos (o gramaticales) y errores semánticos (o lógicos). Antes de examinar cómo
pueden ocurrir estos dos tipos de errores en los programas de Fortran, y para enfatizar la
diferencia entre ellos, consideraremos cómo pueden ocurrir en inglés natural
considerando el dicho bien conocido (entre aquellos que recién comienzan a leer y
escribir) en el sentido de que:
el gato se sentó en la alfombra; Si esta oración estuviera siendo analizada por algún
dispositivo automático (¿un robot, tal vez?) Que tenía un buen conocimiento de la
gramática inglesa y del significado de las palabras, pero no tenía intuición u otros medios
para interpretar lo que el autor podría haber querido entonces la oración está mal escrita
El dat sentado en el tapete no tendría sentido. Este es un error sintáctico, ya que la
palabra 'dat' no existe en el idioma inglés, y nuestro robot lo diagnosticaría como tal. Por
otro lado, la declaración ¨el gato se sentó en la estera¨ contiene solo palabras en inglés
válidas, pero la gramática es incorrecta ya que una preposición ('on') no puede aparecer
entre el artículo definido ('the') y un sustantivo ('mat'). Una vez más, por lo tanto, nuestro
robot indicaría que hubo un error sintáctico en la oración.
Sin embargo, la oración:
La estera se sentó sobre el gato
satisface todas las reglas de la gramática, y todas las palabras son palabras válidas en
inglés. Nuestro robot pasará a la siguiente etapa e intentará entender lo que significa la
oración. ¡Aquí puede tener un problema! Por lo tanto, este es un ejemplo de error
semántico, ya que no hay nada incorrecto gramaticalmente (o sintácticamente) con la
oración; simplemente no tiene ningún sentido lógico.
Observe, por cierto, que un error de mecanografía no necesariamente conducirá a un
error sintáctico. Por ejemplo, las siguientes oraciones tienen un solo error de
mecanografía, pero todas tienen un núcleo sintáctico e incluso tienen sentido, aunque no
el sentido que se pretendía:
El gato escupió en el tapete.
La cuna se sentó sobre la estera
El gato se sentó sobre el hombre.
A partir de estos ejemplos, podemos ver que un error sintáctico o gramatical es
relativamente fácil de definir, y un compilador Fortran siempre eliminará dichos errores en
un programa. Por otro lado, un error semántico o lógico puede dar lugar a un significado
sin sentido, o puede dar lugar a un significado razonable pero incorporado. En términos
de programación, un error semántico puede hacer que el programa falle durante la
ejecución, o simplemente puede dar lugar a respuestas incorporadas.

2.5 El diseño y prueba de programas.


En los capítulos siguientes de este libro, conoceremos la gama completa de declaraciones
e instalaciones de Fortran 90, y comenzaremos a apreciar la riqueza del lenguaje, que es
la base de su capacidad para permitir que el programador de Fortran resuelva una gama
enormemente amplia de problemas. De manera fácil y eficiente. Sin embargo, los
ejercicios y ejemplos que se utilizarán para ilustrar esa riqueza serán necesariamente
breves, de modo que su complejidad no se interponga en los puntos que están tratando
de hacer. Los programas reales casi siempre serán sustancialmente más grandes que los
que encontrará en este libro.
Aunque todos los ejemplos trabajados desarrollarán el diseño del programa mediante
planes de estructura, a veces puede parecer que esto está haciendo que el proceso sea
innecesariamente difícil. ¡Tal actitud no podría estar más equivocada! La programación de
computadoras es una actividad que es extremadamente interesante, y que a menudo
puede ejercer una fascinación muy considerable sobre los involucrados. Es muy
interesante porque requiere una cuidadosa combinación de conocimiento de varias áreas
diferentes, y porque el programador está involucrado en un proceso creativo que casi no
tiene restricciones, más allá de la necesidad de ser lógicamente consistente y obedecer la
sintaxis y la semántica del lenguaje usado. En esto, tiene similitudes con las matemáticas
puras y con las bellas artes. Como consecuencia de esta libertad, el programador es libre
de ser muy creativo, pero el abuso de esta libertad inevitablemente conducirá a
programas deficientes.
En matemáticas, una prueba correcta pero fea incomoda a los matemáticos, y se
esforzarán por encontrar una prueba elegante para reemplazarla. Lo mismo es cierto para
los programas de computadora, y un programa correcto pero feo hará que la gente quiera
rediseñarlo y reescribirlo. Es importante enfatizar que esto no es solo una estética que
entra en juego, ya que hay razones sólidas y muy prácticas para escribir programas
elegantes.
• El primero de ellos es que un programa feo es casi sinónimo de
diseño deficiente y con la codificación que comenzó antes de que el programa estuviera
bien pensado. Esto da como resultado programas que solo pueden funcionar
correctamente con dificultades considerables. De hecho, si un programa está
suficientemente mal construido, incluso después de haber resuelto varios casos de
prueba correctamente, el escritor puede tener la sensación incómoda de que no es
realmente confiable.
La experiencia de muchas personas a lo largo de muchos años ha demostrado que el
tiempo dedicado a un diseño inicial cuidadoso, antes de escribir cualquier código, es más
que recuperado durante el proceso de verificación (a menudo llamado depuración).
Cuanto más grande es el proyecto, más entra en juego este principio. Sin embargo, esto
no significa que los proyectos pequeños no se beneficien de una planificación inicial. El
diseño inicial cuidadoso siempre vale la pena, incluso en el proyecto más pequeño.
• Una segunda cuestión, y para muchas personas de mayor importancia que el desarrollo
inicial de un programa, es la mantenibilidad de los programas.
Los programas necesitan mantenimiento por varias razones. Si un proyecto de
programación va más allá de cierto tamaño pequeño, es casi seguro que, en algún
momento de su vida útil, se encontrará errores en circunstancias especiales que no se
pensaron o se manejaron incorrectamente durante el diseño inicial. Los programas a
menudo tienen una vida inesperadamente larga (¡a veces para vergüenza de sus
autores!). Casi inevitablemente, la mayoría de los programas, por lo tanto, se extenderán
posteriormente para tratar nuevos problemas que no se encuentran en los requisitos
originales. Como resultado, es bastante normal que se dedique más tiempo y esfuerzo a
extender y mantener un programa de lo que se gastó en desarrollarlo originalmente. La
frase "escribir una vez y leer muchas veces" es un truismo en la programación.
• Finalmente, si ha escrito un programa de interés más que parroquial, sin duda recibirá
solicitudes de amigos y colegas para copias El mundo está lleno de diferentes tipos de
computadoras. ¡Imagine la angustia de sus colegas si no pueden compilar y ejecutar
fácilmente programa en sus máquinas! También puede encontrar que la computadora en
la que se desarrolló originalmente un programa está siendo reemplazada por una nueva,
una circunstancia que parece estar sucediendo con una frecuencia cada vez mayor. Por
lo tanto, escribir programas portátiles es importante. Solo por razones bien consideradas
deben usarse características no estándar u obsoletas de Fortran.
En resumen, los programas deben estar bien diseñados antes de comenzar.
Esto conducirá a programas confiables, eficientes, fáciles de mantener y portátiles que
son agradables de crear y trabajar.
Hay muchos elementos que intervienen en el buen diseño del programa, y muchos
enfoques que se han desarrollado para ayudar a los programadores a desarrollar
programas bien diseñados. Sin embargo, independientemente del enfoque detallado que
se utilice, hay una serie de principios subyacentes que siempre deben incorporarse en el
diseño de cualquier programa, de los cuales los siguientes son los más importantes:
• Entender completamente lo que se supone que debe lograr el programa. ¿Cuáles son
las entradas y salidas que se supone que son? Esto suena demasiado trivial para que
valga la pena mencionarlo, pero no lo es. Es muy fácil no tener todos los hechos
claramente entendidos antes de comenzar la programación. Esto conducirá a un rediseño
muy doloroso y costoso en una etapa posterior.
• Haga que la entrada y la salida sean claras para que el usuario del programa las
entienda. Haga que el formulario de entrada sea lo más fácil posible y que el formulario de
salida sea lo más claro y útil posible.
• Tenga un diseño claro para el método que se utilizará para resolver el problema.
Escríbelo. Ya hemos introducido una forma de hacer esto y ampliaremos esto en capítulos
posteriores. Sin embargo, hay otros enfoques, y debe elegir uno con el que se sienta
cómodo. Es sorprendente la frecuencia con la que esta etapa debe ser modificada hasta
que se encuentre una solución correcta.
• Mire para ver qué funcionalidad puede encontrar en las bibliotecas de procedimientos
existentes. Tendremos más que decir sobre esto en el Capítulo 4, pero ya hemos visto en
el Ejemplo 2.1 cómo se puede usar una subrutina para evitar la necesidad de escribir todo
el programa uno mismo. ¡Reinventar la rueda no es un uso económico de tu tiempo!
• Al escribir el programa, utilice un diseño modular. Discutiremos este tema con cierto
detalle en el Capítulo 4 y, por lo tanto, no diremos más aquí, excepto para señalar que
una buena regla general es que ningún bloque de código (o procedimiento, consulte el
Capítulo 4) debe ser más largo que aproximadamente 50 líneas, excluyendo cualquier
comentario.
• Utilice nombres descriptivos para variables y unidades de programa y sea generoso con
los comentarios. El código con pocos o ningún comentario suele ser imposible incluso
• el autor debe entender una vez que hayan pasado algunas semanas desde su creación.
• Realice la mayor cantidad de verificación de errores posible en la entrada. Además,
realice comprobaciones sobre el éxito de las etapas internas de un cálculo.
Incluya, como parte de la salida, cualquier problema que detecte el programa y cómo se
ve afectada la precisión de la respuesta. Este es realmente un tema complicado y solo se
pueden hacer algunos comentarios introductorios aquí.
Para la comprobación de errores de entrada, intente atrapar e informe claramente de
nuevo a
el usuario, cada error que puedan contener los datos de entrada. Por ejemplo, si uno de
los elementos de datos es el número de elementos a procesar, estos números deben
verificarse para ver que no son negativos, y también deben verificarse para ver que no
son tan grandes que se exceda la capacidad del programa. Este es un tipo obvio de
verificación para hacer. Una clase de controles menos obvia es la auto consistencia de los
datos. Por ejemplo, si se supone que un programa toma tres puntos como entrada y
calcula el radio
y el centro del círculo que los atraviesa, los puntos deben ser
comprobado para ver que no se encuentran en una línea recta. Si son exactamente
colineales, el radio es infinito y las coordenadas del centro se han vuelto indeterminadas.
Otra comprobación es comprobar que todos los puntos son distintos. Si no lo son,
entonces hay un número infinito de soluciones.
Para los errores que se pueden detectar mientras el programa se está ejecutando,
considere la posibilidad de verificar cuántas iteraciones se realizan al intentar converger a
una solución. Si esto se hace demasiado grande, el usuario debe ser
informado y dado una opción para terminar el proceso.
Volviendo al problema de determinar el círculo a través de tres
puntos, supongamos que los puntos son casi coliniales o casi coincidentes. Esto es más
difícil de detectar que la colinealidad exacta o la coincidencia. ¿Qué significa "casi" aquí?
¿Cómo se puede dar un valor numérico preciso para 'casi'? Hay una solución. El centro
del círculo se puede determinar como resultado de resolver un par de ecuaciones lineales
simultáneas. Existen técnicas matemáticas bien establecidas, que, sin embargo, están
fuera del alcance de este libro, para estimar el número de condición de tales sistemas
lineales de ecuaciones. Este análisis detectará la linealidad cercana o la coincidencia de
puntos y puede usarse para informar al usuario cuántos dígitos, si alguno, de la respuesta
son precisos.
• Finalmente, pruebe el programa utilizando casos que ejecuten cada parte del programa,
incluidas las pruebas de error de entrada y las pruebas de problemas de cálculo.
Aunque pueda parecer obvio, asegúrese de saber cuál es el correcto
La respuesta debe ser para aquellas pruebas que están diseñadas para ejecutarse hasta
su finalización.
¡El hecho de que su programa produzca una respuesta no significa que sea la correcta!
Estas técnicas no quitan el interés y el desafío de programación, por lo que es un proceso
mecánico. En cambio, hacen un programa más fácil de desarrollar y mantener, lo que
hace que el proceso sea más interesante y menos doloroso. Todos nosotros, en algún
momento de nuestras vidas, hemos tenido el problema de tratar de encontrar el error en
un programa mal escrito y mal documentado (¡escrito por otra persona, por supuesto!) Y
no lo recomendamos a nadie.
Volveremos a la cuestión de probar programas en el intermedio entre las partes I y II de
este libro, pero no podemos enfatizar demasiado la parte vitalmente importante del
proceso de programación. Incluso con programas aparentemente simples, como los que
escribirá en respuesta a los ejercicios en la primera parte de este libro, siempre debe
probarlos exhaustivamente para asegurarse de que produzcan las respuestas correctas a
partir de datos válidos y reaccionen de una manera predecible y útil. cuando se presenta
con datos no válidos.
2.6 Los viejos y nuevos formularios fuente Fortran 90
El breve programa escrito como parte del Ejemplo 2.1, y discutido en detalle en la Sección
2.2, está escrito de forma gratuita, en el que las declaraciones pueden escribirse en
cualquier parte de la línea, permitiendo así que el programador organice el diseño de un
programa para adaptarse cualquier preferencia de estilo particular. Existen relativamente
pocas restricciones en los programas escritos de esta manera, a saber:
• Los caracteres en blanco son significativos y deben usarse para separar nombres,
constantes o etiquetas de declaraciones de otros nombres, constantes o etiquetas de
declaraciones, y de palabras clave de Fortran
• Las líneas de comentarios se identifican al tener un signo de exclamación como su
primer carácter no en blanco.
• Los caracteres que siguen a un signo de exclamación, a menos que sea parte de una
cadena de caracteres, forman un comentario final
• Una línea puede contener un máximo de 132 caracteres.
• Una línea puede contener más de una declaración, en cuyo caso un punto y coma
separa cada par de declaraciones sucesivas
• Un signo "&" al final indica que la declaración continúa en la línea siguiente; si ocurre en
un contexto de caracteres, entonces el primer carácter no en blanco de la siguiente línea
también debe ser un signo y la cadena de caracteres continúa inmediatamente después
de ese signo.
• Una declaración puede tener un máximo de 39 líneas de continuación
• Una etiqueta de declaración, si se requiere, consta de hasta cinco dígitos consecutivos
que representan un número en el rango de 1 a 99999, que precede a la declaración, y
está separada de ella por al menos un espacio en blanco.

3.1 Los dos tipos fundamentales de números


Los dos tipos fundamentales de números
Cuando se desarrolló el primer procesador FORTRAN en 1954, introdujo dos formas
bastante diferentes de almacenar números y realizar operaciones aritméticas. Estos han
permanecido esencialmente inalterados en Fortran desde ese momento, y antes de
continuar debemos establecer qué son y en qué se diferencian.
Un número entero es un número entero y se almacena en la memoria de la computadora
sin ninguna parte decimal (o fraccional). Sin embargo, debido a la forma en que se
almacena, siempre hay límites para su tamaño. Estos límites varían de una computadora
a otra y dependen del diseño físico de la memoria de la computadora. Podemos ilustrar
esto considerando una computadora hipotética que (¡para facilitar la comprensión!)
Almacena sus datos en forma decimal en lugar del sistema binario (base 2) utilizado por
casi todas las computadoras. Esto significa que se registrará un solo dígito por medio de
algún dispositivo que tenga 10 estados (correspondientes a los 10 dígitos) en lugar de uno
con dos estados (por ejemplo, encendido y apagado) según sea necesario para los
números binarios. Cada ubicación en la memoria utilizada para almacenar números
enteros consistirá en un número fijo de estos dispositivos, digamos ocho con fines
ilustrativos, lo que impondrá un límite en el tamaño del número, en este caso al 99999999.
Queda la cuestión del signo de los números.
Supongamos que el dispositivo que almacenaba el número entero era un dispositivo
electrónico, equivalente a un milímetro u odómetro, como el que se ajusta a un automóvil
para registrar la distancia recorrida (consulte la Figura 3.1). Si la lectura es 00 000 000 y
el automóvil avanza 2 millas (es decir, suma 2) el milímetro leerá 00 000 002. Sin
embargo, si el ( :: arnow retrocede durante 3 millas (es decir, resta 3) la lectura
sucesivamente irá a t. () 00 000 001, 00 000 000 y finalmente 99999999. Por lo tanto, se
obtiene la misma lectura para un valor de -1 que para +99 999 999, y sumando 1 a 99 999
999 dará cero. Podríamos, por lo tanto, adopte una convención que diga que las lecturas
del 1 al 49 999 999 se considerarán positivas, mientras que 50 000 000 a 99 999 999 se
considerarán negativas y equivalentes a - 50 000 000
Lecturas de milímetros durante el viaje.

 0 0 0 0 0 0 0 0 lectura inicial del milímetro


 0 0 0 0 0 21 después de dos millas
 0 0 0 0 0 0 0 1 Después de retroceder una milla
 0 0 0 0 0 0 0 0 después de invertir una milla más
 9 9 9 9 9 9 9 9 después de invertir una milla más
Almacenamiento de enteros

 50000000 representa -50000000


 50000001 representa -49999999
 99999999 representa -1
 00000000 representa 0
 00000001 representa +1
 49999999 representa +49999999
Casi todas las computadoras funcionan de manera similar a esto, aunque cuando se usa
el sistema binario el efecto es que si el primer dígito binario (o bit) es uno, entonces el
número es negativo, mientras que si es cero, el número es positivo.
Usando la convención que acabamos de describir, nuestra ubicación de memoria de ocho
dígitos puede contener un número entero en el rango de -50 000 000 a +49 999 999,
como se muestra en la Figura 3.2.
El otro tipo de número se llama un número real. Se puede considerar que un número real
consiste en una parte entera y una cadena de dígitos que representan la parte
fraccionaria, y claramente una forma de almacenar dicho número en una ubicación de
memoria de ocho dígitos sería asumir que, por ejemplo, los primeros cuatro los dígitos
vienen antes del punto decimal y los segundos cuatro después. Sin embargo, esto
significaría que los números solo podrían estar entre -5000.0 y +4999.9999, usando la
misma convención que antes con respecto al signo, y que todos los números se
almacenarían con exactamente cuatro decimales. Claramente, esto es demasiado
restrictivo y se debe encontrar otra forma. Una solución podría ser permitir más dígitos,
pero el problema con este enfoque es que un gran número de ellos se desperdiciará en
muchas ocasiones. Por ejemplo, si se permitieron 16 dígitos, para dar el mismo rango que
para los enteros, pero con ocho lugares de decimales, entonces, por un lado, un número
como 100 000 000.0 no se puede almacenar porque necesita nueve dígitos antes del
decimal, a pesar de que ninguno de los siguientes es necesario, mientras que en el otro
un número como 0.000 000 004 debería tratarse como cero porque necesita nueve
decimales, aunque ninguno de los ocho antes del punto decimal es necesario.
Una solución para nuestra computadora hipotética sería considerar cualquier número real
distinto de cero como una fracción que se encuentra entre 0.1 y 1.0, llamada mantisa, que
se multiplica o se divide por 10 una cierta cantidad de veces, donde este número se llama
exponente.
Con este enfoque, podríamos definir un método de representación que diga, por ejemplo,
que los últimos seis dígitos representan la mantisa como una fracción de seis decimales
(siendo el primero distinto de cero), mientras que los dos primeros representan el
exponente; es decir, el número de veces que la fracción se multiplicará o dividirá por 10.
La misma técnica que se usó para los enteros para distinguir los números positivos y
negativos se usará tanto para la mantisa como para el exponente. La figura 3.3 ilustra
este método, que se conoce como representación de punto flotante. Este método de
representación tiene dos implicaciones principales. La primera es que todos los números,
cualquiera sea su tamaño, se mantienen con el mismo grado de precisión. En el ejemplo
utilizado, todos se almacenarán con una precisión de seis dígitos significativos.
Por lo tanto, el problema de los dígitos desperdiciados no surge. La segunda implicación
es que los límites para el tamaño de los números son mucho mayores que en el caso de
los enteros.
En nuestra computadora hipotética, por lo tanto, el número 03413702 representa el valor
real 413.702 o el valor entero 3413702, dependiendo de si se interpreta como un número
de coma flotante o como un entero. Tenga en cuenta que no hay nada en el número
03413702 en sí mismo que indique cuál de estos dos está destinado; En este ejemplo
hipotético, sería responsabilidad del programador recordar cuál fue la intención.
En una computadora real surge exactamente la misma situación y es esencial que los dos
métodos de representación numérica estén claramente definidos; veremos en la siguiente
sección cómo instruir a la computadora qué método usar. Sin embargo, ya podemos ver
que es extremadamente importante que la diferencia entre un número entero y un número
real se aprecie completamente:

 Un número entero es un número entero, siempre se mantiene exactamente en la


memoria de la computadora y tiene un rango (relativamente) limitado (entre
aproximadamente -2 X 10 ^ 9 y +2 x 10 ^ 9 en una computadora típica de 32 bits).
 Un número real, por otro lado, se almacena como un número de coma flotante, se
mantiene como una aproximación a un número fijo de dígitos significativos y tiene
un rango muy grande (típicamente entre aproximadamente -10 ^ 38 y + 10 ^ 38
para siete u ocho dígitos significativos en la misma computadora de 32 bits).
Variables REAL e INTEGER
Toda la cuestión del almacenamiento de diferentes tipos de información en una
computadora puede volverse bastante complicada, y volveremos a este tema varias
veces a medida que desarrollemos una comprensión más completa del poder y la
flexibilidad del lenguaje Fortran. En la última sección vimos la importancia de informar
a la computadora qué tipo de información se debe procesar, y la forma principal en
que lo hacemos es mediante una declaración variable. En su forma más simple, esto
toma la forma
TYPE::nombre
donde TYPE especifica el tipo de datos para el que se debe reservar espacio de
memoria, y nombre es un nombre elegido por el programador con el que hacer
referencia a la variable que se ha declarado.
En el Capítulo 1 usamos una analogía con una serie de cajas de vidrio para
representar la memoria de una computadora, y podemos extender esta analogía para
que la caja ahora contenga dos símbolos de identificación (ver Figura 3.4), uno de los
cuales es el nombre utilizado en el ejemplo anterior, mientras que el otro identifica el
tipo de información que puede almacenarse en la caja.
En general, habrá más de una variable del mismo tipo siendo declarado y así se
puede dar una lista de nombres:
TYPE :: nombre 1, nombre2 ,…….
Por lo tanto, podemos declarar tres variables reales mediante una declaración como
REAL :: a, b, c
o
REAL primer_real_variable, segunda_real_variable y
tercera_real_variable.
Tenga en cuenta que los valores reales se representan como números de punto
flotante.
De manera similar, las variables enteras se declaran de la siguiente manera:
INTEGER :: primer_inteqer, segundo_inteqer
Ya hemos cumplido las reglas para los nombres Fortran en la Sección 2.2, y en este
libro hemos adoptado la convención ampliamente utilizada de que las mayúsculas se
usarán para palabras clave de Fortran, como REAL e INTEGER, mientras que las
minúsculas se usarán para nombres creados por el programador, como
primer_real_variable, etc.
Sin embargo, hay un problema bastante serio que surge debido a la edad del lenguaje
Fortran y la necesidad de mantener la compatibilidad con versiones anteriores de. el
idioma. Esto se conoce como declaración implícita.
En los primeros días de la programación, a muchos programadores les molestaba
tener que declarar sus variables antes de usarlas, por lo que Fortran proporcionó una
forma alternativa de determinar el tipo de variable en función de su letra inicial. En
Fortran 90, por lo tanto, si omite declarar una variable, normalmente no dará lugar a
un error cuando se use por primera vez; en su lugar, se declarará implícitamente como
un número entero si la primera letra de sus nombres en el rango I-N, y de lo contrario
se declarará implícitamente como una variable realAfortunadamente, Fortran 90
proporciona los medios para evitar este problema al incluir al compilador que todas las
variables deben declararse antes de su uso, y que no se debe permitir la declaración
implícita. Esto se logra al incluir la declaración
IMPLÍCIT NONE
como la primera declaración después de la declaración inicial de PROGRAM.
Es extremadamente importante que esta declaración aparezca al comienzo de cada
programa para que las declaraciones implícitas de variables estén prohibidas. Hay
muchas historias, algunas apócrifas y otras verdaderas, sobre grandes catástrofes en
los programas de Fortran que nunca habrían sucedido si la declaración implícita no
hubiera enmascarado un error de programación.

Expresiones aritméticas y asignación.


Una vez que hemos declarado una o más variables, podemos comenzar a usarlas
para resolver problemas. Primero, sin embargo, debemos establecer cómo se
almacenan valores particulares en las ubicaciones de memoria asociadas con las
variables especificadas. De hecho, solo hay dos formas en que una variable puede
recibir un valor durante la ejecución de un programa: mediante asignación o mediante
una declaración READ. Cumplimos con la declaración READ en el Capítulo 2, y la
discutiremos con algún detalle en la siguiente sección; sin embargo, con mucho, el
medio más común para dar un valor a una variable es a través de una declaración de
asignación.
Entrada y salida de datos numéricos dirigida por lista
Ya hemos cumplido con las declaraciones de entrada / salida dirigidas a la lista en el
Capítulo 2, y con nuestro nuevo conocimiento sobre las variables y los tipos de datos
reales y enteros, ahora es apropiado definir el formato de estas declaraciones con
más detalle. En la forma en que los usaremos actualmente tienen una sintaxis casi
idéntica, como sigue:
READ*, var_1, var_2……
PRINT*, item_1, ítem_2……
La principal diferencia entre ellos es que la lista de elementos en una declaración
READ solo puede contener nombres de variables, mientras que la lista en una
declaración PRINT también puede contener constantes o expresiones. Estas listas de
nombres y / u otros elementos se denominan como una lista de entrada y una lista de
salida, respectivamente. El asterisco que sigue a LEER o IMPRIMIR indica que se
debe realizar el formateo dirigido a la lista. Veremos en el Capítulo 8 cómo se pueden
definir otras formas de formato de entrada y salida, pero la forma dirigida a la lista es
más que adecuada para el presente.
La instrucción READ dirigida por la lista tomará su entrada de una unidad de entrada
definida por el procesador conocida como la unidad de entrada predeterminada,
mientras que la declaración PRINT dirigida por la lista enviará su salida a una unidad
definida por el procesador conocida como la unidad de salida predeterminada. En la
mayoría de los sistemas, como estaciones de trabajo o computadoras personales,
estas unidades predeterminadas serán el teclado y la pantalla, respectivamente;
veremos en el Capítulo 8 cómo especificar otras unidades de entrada o salida cuando
sea necesario.
La declaración
READ *, real_var1, real_var2, int_var
por lo tanto, leerá tres valores de la unidad de entrada predeterminada, normalmente
el teclado, y los almacenará en las tres variables
real_ varl, real_ var2 yint_var.
Un valor que se ingresa a una variable real puede contener un punto decimal, o el
punto decimal puede omitirse, en cuyo caso se trata como si la lectura del valor entero
fuera seguida por un punto decimal. Un valor que se va a ingresar a una variable
entera no debe contener un punto decimal, y la aparición de uno causará un error.
El término "dirigido a la lista" se usa así porque la interpretación de la entrada de
datos, o la representación de la salida de datos, está determinada por la lista de
elementos en la declaración de entrada o salida. Veremos en el Capítulo 8 cómo
especificar el formato de salida en lugar del predeterminado provisto por el procesador
Fortran.
Un punto importante que debe considerarse con la entrada dirigida por la lista se
refiere a la terminación de cada valor de datos que se ingresa. La regla es que cada
número u otro elemento debe ir seguido de un separador de valores que consista en
una coma, un espacio, una barra diagonal (/) o el final de la línea; cualquiera de estos
separadores de valores puede ir precedido o seguido de cualquier cantidad de
espacios en blanco (o espacios) consecutivos. Si hay dos comas consecutivas,
entonces el efecto es leer un valor nulo, que resulta en el valor de la variable
correspondiente en la lista de entrada que no se modifica. ¡Tenga en cuenta que una
causa común de error es creer que el valor se situará en cero! Si el carácter de
terminación es una barra oblicua, no se leen más elementos de datos y finaliza el
procesamiento de la declaración de entrada. Si hay elementos restantes en la lista de
entrada, entonces el resultado es como si se les hubieran ingresado valores nulos; en
otras palabras, sus valores permanecen sin cambios.
Manejo de datos de CARACTERES
Después de haber usado las constantes CHARACTER en algunas de nuestras
declaraciones PRINT, ahora es apropiado considerar cómo podemos declarar las
variables CHARACTER y manipular los datos CHARACTER dentro de un programa.
Primero, sin embargo, debemos enfatizar que los caracteres y los números se almacenan
de manera muy diferente en cualquier computadora.
Como ya hemos visto, las variables REAL e INTEGER pueden contener una amplia gama
de números en una sola variable. Ahora debemos introducir el concepto de unidad de
almacenamiento numérico, que es esa parte de la memoria de la computadora en la que
se puede almacenar un solo número REAL o INTEGER. En la mayoría de las
computadoras modernas, una unidad de almacenamiento numérico consistirá en un área
contigua de memoria capaz de almacenar 16, 32, 48 o 64 bits, o dígitos binarios. Una
unidad de almacenamiento numérico de 32 bits es capaz de almacenar números enteros
en el rango de aproximadamente - 2 X 10 ^ 9 a + 2 X 10 ^ 9, o números reales en el rango
-1038 a + 1038 con una precisión de aproximadamente siete dígitos significativos.
Los caracteres, por otro lado, se almacenan en unidades de almacenamiento de
caracteres, que generalmente ocupan 8 o 16 bits, cada uno de los cuales puede contener
exactamente un carácter en forma codificada. Una variable de caracteres consiste en una
secuencia de una o más unidades de almacenamiento de caracteres consecutivas. No
existe una suposición sobre la relación, si la hay, entre las unidades de almacenamiento
numérico y de caracteres, aunque, en la práctica, la mayoría de las computadoras usarán
los mismos dispositivos de memoria física para ambos tipos, de modo que, por ejemplo,
cuatro unidades de almacenamiento de caracteres de 8 bits se puedan mantener juntas
en de lo contrario sería una sola unidad de almacenamiento numérico de 32 bits.
Los programas en el idioma Fortran se escriben usando caracteres tomados del Conjunto
de caracteres Fortran, que consta de las 26 letras del alfabeto latino, los diez dígitos
decimales, el carácter de subrayado y 21 caracteres especiales adicionales. Estos 58
caracteres se muestran en la Figura 3.11. Tenga en cuenta que las letras minúsculas se
tratan como letras mayúsculas idénticas cuando aparecen en palabras clave o
identificadores Fortran, aunque, por supuesto, se tratan como diferentes en los datos o en
una cadena de caracteres.

Valores iniciales y constantes


Hay otro método para dar un valor a una variable, a saber, proporcionar un valor inicial
para una variable como parte de la declaración de la variable. Esto se logra simplemente
siguiendo el nombre de la variable con un signo igual y el valor inicial:
REAL:: a = 0,0, b = 1,5, c, d, e=1E-6
INTEGER :: max = 100
CARÁCTER (LEN = 10) :: nombre = "Indefinido"
Estos valores iniciales serán asignados a las variables por el procesador Fortran antes de
que comience la ejecución del programa, evitando así la necesidad, cuando se ejecuta el
programa, de obedecer una serie de asignaciones iniciales o de leer un conjunto inicial de
valores. Al separar la inicialización de las variables de cualquier asignación durante la
ejecución, también es más fácil mantener estas dos fases de un programa más
claramente delineadas.
Cualquier valor inicial especificado debe ser una constante literal o una expresión
constante, es decir, una expresión cuyas partes componentes son todas constantes.
Un problema relacionado se refiere a crear y dar nombres a las constantes.
Con frecuencia, un programa usará ciertos valores constantes en muchos lugares, y no es
necesariamente obvio lo que representa una constante en particular. Por ejemplo, podría
ser necesario establecer un número máximo de elementos que podrían aparecer en un
conjunto de datos, pero el uso de la misma constante literal en todos los lugares a los que
debe referirse es propenso a errores tanto al escribir el programa como, aún más, cuando
posteriormente lo modifica, y es menos legible de lo que sería el caso si se usara un
nombre. Además, hay muchas ocasiones en que se requieren constantes físicas o
naturales, como el valor de 7f, en los programas, y claramente no hay intención de que se
alteren. Fortran nos permite un método conveniente para tratar estas situaciones
mediante la definición de lo que se denomina constantes nombradas mediante el uso del
atributo de parámetro en una declaración de declaración:
REAL, PARAMETER:: pi = 3.1415926, pi_by_2 = pi / 2.0
INTEGER, PARAMETER:: max_casos = 100
En este ejemplo, pi se define como una constante, y luego pi_by _2 se define mediante
una expresión constante que involucra pi. Dado que la declaración se procesa de
izquierda a derecha, esto es aceptable; si las dos constantes se enumeran en el orden
opuesto, entonces habría un error. Nunca habrá necesidad de cambiar los valores de
estas dos constantes, y su definición es puramente para que el programa sea más fácil de
leer y para evitar errores al escribir constantes largas ya que, en lugar de escribir, por
ejemplo
área = 3.1415926 * r * r
podemos escribir
área = pi * r * r
Por otro lado, la constante entera max_cases podría necesitar ser cambiado si el tamaño
del problema que se procesa cambiara. Este es un caso en el que puede haber muchos
lugares donde aparece el valor constante de 100, y no todos se refieren al número
máximo de casos. Modificar el programa para cambiar el máximo sería muy propenso a
errores. Al hacer que el valor máximo sea una constante con nombre, el programa es más
fácil de leer y cualquier cambio que se requiera posteriormente solo debe hacerse en un
lugar.
Finalmente, observamos que, dado que la razón completa para otorgar a una entidad el
atributo de parámetro es declarar una constante con nombre, no está permitido intentar
cambiar su valor en un punto posterior del programa. La única forma en que se puede
cambiar su valor es modificando la declaración de declaración en consecuencia y
volviendo a compilar el programa

Creando tus propios tipos de datos

Ahora hemos cumplido con los tres tipos principales de datos que pueden ser procesados
por los programas de Fortran, aunque hay tres más que veremos más adelante. Estos
seis tipos de datos se denominan tipos de datos intrínsecos, y fueron los únicos tipos de
datos en todas las versiones anteriores de Fortran. Sin embargo, Fortran 90 también
incluye la capacidad para que los programadores creen sus propios tipos de datos para
complementar los tipos intrínsecos proporcionados dentro del lenguaje Fortran. ¡Porque
estos nuevos tipos de datos deben derivarse de los tipos de datos intrínsecos y! o tipos de
datos nuevos previamente definidos se llaman tipos derivados.
Un tipo derivado se define mediante una secuencia especial de declaraciones, que en su
forma más simple son las siguientes:
TYPE new_type
definición_component
END TYPE new_type
Procedimientos, subprogramas y funciones.
Las declaraciones que conocimos en el último capítulo nos permiten escribir
programas que consisten en una serie de líneas de instrucciones que serán
obedecidas en secuencia para que se realicen las adiciones requeridas. Sin embargo,
esta no es siempre la forma en que hacemos las cosas en la vida real. Por ejemplo,
mire la Figura 4.1. Esta es una nota que tal vez se deje para enseñar a alguien cómo
preparar la cena. Es una secuencia de instrucciones pero con una diferencia
importante: no todas las instrucciones
hay. La parte principal de la preparación está cubierta en un libro de cocina (The
SilverPalate Cookbook, de Julee Rosso y Sheila Lukins), por lo que, en lugar de
escribirlo todo, el escritor simplemente se refirió a la página correspondiente del libro.
No tenía sentido copiarlo o describir qué hacer con diferentes palabras; fue mucho
más fácil hacer uso de lo que ya habían escrito los autores del libro.
La Figura 4.2 muestra parte de la receta adual para Pollo a la Frambuesa referida a la
nota en la Figura 4.1, y podemos ver que incluso aquí la receta completa no está
incluida. En este caso, los detalles de cómo preparar el caldo de pollo y el
CremeFraiche se encuentran en otra parte del libro, en las páginas 342 y 339, de
manera respetuosa, y sería un desperdicio seguir repitiéndolos en las muchas recetas
que usan uno o ambos. Una referencia cruzada a las otras recetas, por lo tanto,
ahorra espacio y, por cierto, también mantiene la receta principal menos abarrotada y,
por lo tanto, más fácil de seguir.
Ambas situaciones (el uso de procedimientos estándar y evitar la duplicación con las
consiguientes mejoras estructurales) también aparecen en la programación. Un seccion
especial de programa al que, de alguna manera, se hace referencia cuando se requiere
se conoce como un procedimiento.
Los procedimientos se dividen en dos grandes categorías, a saber, los que están escritos
por el programador (o por alguna otra persona que luego permite que el programa los
use) y los que forman parte del lenguaje Fortran. Hay una nueva categorización, basada
en su modo de uso, en lo que se llama subrutinas y funciones. Casi todos los
procedimientos que forman parte del lenguaje Fortran 90 son iones de fondos y se
denominan funciones intrínsecas. También hay cinco subrutinas intrínsecas.
El propósito de una función es tomar uno o más valores (argumentos) y crear un solo
resultado, y Fortran, por ejemplo, contiene una serie de funciones intrínsecas para
funciones matemáticas elementales, como:

SIN (x) que calcula el valor de sinx (donde x está en radianes)


LOG (x) que calcula el valor de log x

SQRT (x) que calcula el valor de √ x

Programas y unidades de programa


En la sección anterior, declaramos que un procedimiento puede ser parte del lenguaje
Fortran, en cuyo caso se llama un procedimiento intrínseco, o puede ser proporcionado
por el programador. En este último caso, normalmente se implementa mediante un
subprograma Fortran,
Nombre del programa
.
Declaraciones de especificaciones, etc.
.
Declaraciones ejecutables
.
FIN DEL PROGRAMA nombre
Funciones externas
Las funciones intrínsecas disponibles como parte del lenguaje Fortran 90 cubren muchas
de las principales funciones matemáticas, además de cumplir con otros requisitos
comunes. Sin embargo, cuando se desarrolla un programa, a menudo es necesario
escribir nuestros propios subprogramas de funciones, a menudo denominados funciones
externas para distinguirlos de las funciones intrínsecas.
Una función externa toma una forma muy similar a los programas que hemos escrito
hasta ahora, excepto que la primera declaración de la función no es una declaración
PROGRAM sino que es una declaración de FUNCIÓN especial que toma la forma donde
d1, d2, ... son argumentos ficticios que representa los argumentos reales que se usarán
cuando se use la función (o se haga referencia a ella), y type es el tipo del resultado de la
función. Por ejemplo, podríamos escribir una función para calcular la raíz cúbica de un
número real positivo de la siguiente manera:
Subrutinas
En la Sección 4.1 mencionamos que había dos tipos de procedimientos en Fortran
funciones y subrutinas. Ahora es el momento de examinar cómo una subrutina difiere de
una función.
La diferencia radica en cómo se hace referencia a una subrutina y cómo se devuelven los
resultados, si los hay.
Una función, como hemos visto, se referencia de la misma manera que una variable
simplemente escribiendo su nombre, seguido de cualquier argumento que pueda haber
encerrado entre paréntesis; dicha referencia de función provoca una transferencia de
control para que, en lugar de continuar procesando la declaración actual, la computadora
ejecute las declaraciones contenidas dentro de la función. La ejecución de la función
utiliza los valores proporcionados como argumentos para calcular un solo valor (el valor
de la función) que está disponible como el valor de la referencia de la función, al igual que
escribir el nombre de una variable en una expresión proporciona un valor: el valor
almacenado en una ubicación de memoria particular. Una referencia de función, por lo
tanto, no es una declaración completa, sino que es parte de una expresión, y puede
aparecer en cualquier lugar donde pueda aparecer una expresión (por ejemplo, en el lado
derecho de una declaración de asignación, en una lista de salida, como argumento en una
referencia de función, etc.). Ya hemos utilizado una serie de funciones intrínsecas, que se
definen dentro del lenguaje Fortran, y funciones externas que escribimos nosotros
mismos, pero ambos tipos están referenciados de la misma manera:
var = fun(arg1, arg2, ...)
PRINT *, funl1(arg1, arg2, ...)
var = fun2(a1, fun3 (arg1, arg2, ...), a2, a3, ...)
A una subrutina, por otro lado, como vimos en el ejemplo 2.1, se accede mediante una
instrucción CALL, que proporciona el nombre de la subrutina y una lista de
argumentos que se utilizarán para transmitir información entre la unidad del programa
llamando la subrutina:
CALL nombre (arg1, arg2, ...)
La instrucción CALL provoca una transferencia de control para que, en lugar de
ejecutar la siguiente instrucción en el programa, la computadora ejecute las
instrucciones contenidas en el nombre de la subrutina. Cuando la subrutina ha
completado su tarea, regresa a la unidad del programa de llamada y la ejecución
continúa con la siguiente instrucción.
A diferencia de una función, que siempre devuelve el resultado de su ejecución como
el valor de la función, una subrutina no necesita devolver nada a la unidad del
programa que realiza la llamada; sin embargo, si devuelve algún valor, se devuelve
mediante uno o más de sus argumentos.
Podemos ver cómo funciona esto escribiendo una subrutina, raíces, que calcula la raíz
cuadrada, la raíz cúbica, la cuarta raíz y la quinta raíz de un número real positivo.

Argumentos reales, argumentos ficticios y locales variables


"Hemos visto que, cuando se hace referencia a una función o subrutina, se le pasa
información a través de sus argumentos; en el caso de una subrutina, la información
también se puede devolver a la unidad del programa de llamada a través de sus
argumentos. La relación entre los argumentos reales en la unidad del programa de
llamada y los argumentos ficticios en la subrutina o función es de vital importancia en este
proceso.
El mecanismo real utilizado no es importante y puede variar de unosistema informático a
otro; Lo importante es darse cuenta de que los argumentos ficticios no existen como
entidades independientes: son simplemente un medio por el cual el procedimiento puede
identificar los argumentos reales en la unidad del programa que realiza la llamada. Un
punto muy importante a destacar es que el orden y los tipos de los argumentos reales
deben corresponder exactamente con el orden y los tipos de los argumentos ficticios
correspondientes.
Los procedimientos como ayuda a la estructura del programa.

Una de las grandes ventajas de los subprogramas es que nos permiten dividir el diseño
de un programa en varias secciones más pequeñas y manejables, y luego escribir y
probar cada una de estas secciones independientemente del resto del programa.
Esto allana el camino para un enfoque conocido como desarrollo de programas
modulares, que es un concepto clave de la ingeniería de software.
Este enfoque divide el problema en sus principales subproblemas o componentes, cada
uno de los cuales puede ser tratado independientemente de los demás.
En un proyecto grande, estos componentes pueden ser desarrollados por diferentes
personas. Si es necesario, un componente puede subdividirse en otros componentes,
como en cualquier otra pieza de diseño de ingeniería. Todo lo que es necesario es que la
interfaz entre cada componente y el resto del programa esté bien definida.
Un ejemplo de este enfoque en ingeniería mecánica es la fabricación del Airbus A-300.
Las alas de este avión se fabrican en el Reino Unido, mientras que parte del fuselaje se
fabrica en Italia y el resto en Francia. Para que las partes delantera y trasera del fuselaje
se unan correctamente, y que las alas se sujeten correctamente al fuselaje, solo es
necesario proporcionar una especificación detallada de cómo se unirán exactamente las
partes relevantes la interfaz entre estos subconjuntos.
La interfaz para un componente de un programa Fortran consta de dos partes:
El primero, la interfaz propiamente dicha, es la lista de argumentos suministrados al
componente (o más bien al subprograma que es, en efecto, la unidad principal del
programa del componente); Este es un concepto que ya hemos discutido en el contexto
de una interfaz de procedimiento. El segundo es la especificación de la acción del
componente.
Un plan de estructura brinda una gran ayuda en el desarrollo modular, ya que identifica,
de manera natural, los componentes principales del programa. En lugar de expandir estos
componentes dentro de un plan de estructura única, como lo hemos estado haciendo
hasta ahora, podemos tratar cada uno de estos componentes principales como un
subproblema separado cuya solución se debe desarrollar de forma independiente.
 Una vez desarrollados, se pueden integrar para formar el programa completo de acuerdo
con el plan de estructura de nivel superior. Desarrollaremos esta idea más adelante en
capítulos posteriores, pero por el momento simplemente combinaremos el concepto de un
plan de estructura con el de una estructura de programa modular.

Módulos
Como hemos visto, las funciones y subrutinas son muy similares en muchos aspectos y
representan dos tipos diferentes de procedimientos. Aunque conoceremos otras formas
de escribir procedimientos en el Capítulo 11, normalmente se escriben como unidades de
programas independientes en forma de subprogramas externos.
Otra forma de unidad de programa, que se utiliza para un propósito bastante diferente y
no existía en FORTRAN 77, es un módulo.
De manera similar a una función o una subrutina, un módulo comienza con una
declaración inicial del formulario.
Como de costumbre, recomendamos que siempre se use la primera forma.
El propósito de un módulo es bastante diferente de una función o una subrutina. En pocas
palabras, existe un módulo para hacer que algunas o todas las entidades declaradas
dentro de él sean accesibles para más de una unidad de programa. Se puede declarar
una amplia gama de elementos dentro de un módulo y hacerlos accesibles a otras partes
del programa de una manera que proporcione una funcionalidad extremadamente
poderosa. Sin embargo, antes de discutir la potencia total de los módulos, es necesario
comprender más acerca de algunas de las otras características de Fortran, por lo que la
discusión principal de los módulos se postergará hasta el Capítulo 12. Un uso muy
importante de los módulos que podemos presentar en este, Sin embargo, la etapa se
relaciona con la accesibilidad global de variables, constantes y definiciones de tipo
derivadas.
Como ya hemos señalado, los únicos elementos en un procedimiento que son accesibles
fuera del procedimiento son aquellos que se especifican como argumentos ficticios o
como la variable de resultado de una función. Del mismo modo, los únicos elementos en
una unidad de programa de llamada que son accesibles dentro de un procedimiento son
aquellos que se especifican como argumentos reales en la llamada de subrutina o
referencia de función. Un módulo permite que un conjunto definido de variables y / o
constantes esté disponible para cualquier unidad de programa que acceda a ellas
mediante una instrucción USE apropiada.
La declaración USE toma la forma
Use nombre
donde nombre es el nombre del módulo en el que se declaran las variables, constantes y /
o definiciones de tipo derivadas.

Módulos y tipos de datos derivados


Un uso particularmente importante de los módulos está relacionado con los tipos de datos
derivados.
Se recordará que en la Sección 4.5 se señaló que no era posible usar variables de tipo
derivado o constantes como argumentos para un procedimiento porque el procedimiento
no sería consciente del tipo de argumentos reales cuyo tipo se definió en el programa de
llamada unidad, y la unidad del programa de llamada no conocería el tipo de ningún
argumento ficticio cuyo tipo se definió en el procedimiento. Simplemente definir dos tipos
derivados con el mismo nombre y componentes idénticos no sería suficiente, ya que esto
definiría dos tipos de datos diferentes, cada uno local a la unidad de programa en la que
se definió.

Módulos e interfaces de procedimientos explícitos


Nos hemos referido varias veces a la interfaz de un procedimiento de una manera
relativamente informal, y hemos indicado que consiste en el nombre del procedimiento (y
su tipo si es una función), junto con el número y tipo de sus argumentos. Ahora debemos,
brevemente, examinar este concepto con un poco más de detalle.
¡Tradicionalmente, en FORTRAN 77 y versiones anteriores de FORTRAN, se realizó una
llamada a una subrutina o referencia a una función sin que la unidad del programa de
llamada supiera nada sobre el procedimiento que se estaba llamando! Una vez
compiladas todas las unidades del programa que constituían el programa completo, un
programa especial los uniría y garantizaría que, si en algún lugar del conjunto de unidades
del programa se unieran, hubiera una llamada o referencia al procedimiento MINE y luego
a un procedimiento llamado MINE estaba efectivamente disponible; Si no fuera así, se
generaría un error. Cuando se obedecía la llamada o referencia al procedimiento MINE,
los argumentos reales estarían disponibles, en el orden correcto, y el procedimiento MINE
los usaría, en el mismo orden, como sus argumentos ficticios.
Este proceso significó que la unidad del programa de llamada no sabía nada sobre el
procedimiento, y viceversa. En esta situación, se dice que el procedimiento llamado tiene
una interfaz implícita. Aunque esta forma de interfaz no proporciona la información
necesaria para verificar que los argumentos reales coincidan con los argumentos ficticios,
era un enfoque conveniente y tenía la gran ventaja de que los procedimientos se podían
escribir sin ningún conocimiento sobre otros procedimientos.
siendo utilizado en el mismo programa, aparte del conocimiento del programador de la
especificación de interfaz de cualquier procedimiento llamado.
Sin embargo, como vimos en la Sección 4.5, si las características adicionales
proporcionadas en Fortran 90 por motivos de seguridad y otros propósitos son para
funcionar correctamente, necesitan más información sobre cualquier procedimiento que
se esté utilizando que una interfaz implícita. Además, como veremos en capítulos
posteriores, algunas de las características más potentes de Fortran 90 solo pueden
funcionar si tienen un conocimiento completo de las interfaces de procedimientos
relevantes. Esto requiere que los procedimientos en cuestión tengan una interfaz explícita.
Investigaremos exactamente qué se entiende por una interfaz explícita en
Capítulo 11, y veremos cómo podemos especificar esto a una unidad de programa de
llamada.
Sin embargo, hay una forma en que siempre podemos hacer explícita la interfaz de un
procedimiento, es decir, colocando el procedimiento en un módulo. Las reglas relativas a
los módulos especifican que:
• las interfaces de todos los procedimientos definidos dentro de un solo módulo son
explícitas entre sí
• las interfaces de cualquier procedimiento puesto a disposición por la asociación USE son
explícitas en la unidad de programa que está utilizando el módulo, Aunque, como
veremos en el Capítulo 12, podemos incluir definiciones de procedimientos en los mismos
módulos que las declaraciones de tipo y variable, hay ciertas complicaciones que no es
apropiado discutir en esta etapa. Por el momento, por lo tanto, recomendamos que los
procedimientos estén contenidos en un módulo, o posiblemente más de uno, mientras que
otras entidades están contenidas en un módulo o módulos diferentes.
Hay una declaración adicional requerida en un módulo que contiene un procedimiento,
que es ocasionada por la moda de que un procedimiento en un módulo es una unidad de
programa anidada dentro de otra unidad de programa. Esta declaración consiste en una
sola palabra.
Módulos como ayuda para el diseño del programa.
Desde el Capítulo 2, hemos estado diseñando todos nuestros programas con la ayuda de
un plan de estructura como ayuda para planificar la lógica de nuestros programas. Otro
aspecto importante de la programación es el diseño de la estructura de datos del
programa.
Hasta ahora, todos los programas que hemos escrito, o de hecho que hemos sido
capaces de escribir, han tenido requisitos de datos muy simples, que consisten en poco
más que un puñado de variables. Sin embargo, en un entorno del mundo real, los
programas a menudo manipulan cientos o miles de elementos de información separados y
el diseño y control de estos datos es tan importante como el diseño y el control del
programa en sí. Los módulos son de gran ayuda en esto ya que permiten que un
programador agrupe los datos de tal manera que todos los procedimientos que requieren
acceso a un grupo en particular puedan hacerlo simplemente usando el módulo
apropiado.
Esto será particularmente relevante cuando aprendamos cómo procesar conjuntos de
datos similares en el Capítulo 7, pero puede ayudarnos en el diseño de programas incluso
ahora.

También podría gustarte