Esta es una descripción general de las características del lenguaje Fortran 95 , basada en el documento de estándares [ 1 ] , que ha sido reemplazado por una versión más reciente. [ 2 ] Se incluyen las características adicionales de TR-15581: Instalaciones de tipos de datos mejoradas, que se han implementado universalmente. Las características antiguas que han sido reemplazadas por otras nuevas no se describen ; pocas de esas características históricas se utilizan en programas modernos, aunque la mayoría se han conservado en el lenguaje para mantener la compatibilidad con versiones anteriores . Las características adicionales de los estándares posteriores, hasta Fortran 2023, se describen en el documento estándar de Fortran 2023, ISO/IEC 1539-1:2023. [ 2 ] Algunas de sus nuevas características aún se están implementando en compiladores. [ 3 ] También se pueden encontrar detalles en una variedad de libros de texto, por ejemplo [ 4 ] [ 5 ] [ 6 ] y consulte la lista en Recursos de Fortran. [ 3 ] : 18 Las fuentes para la descripción en las secciones siguientes se pueden encontrar en los documentos de normas, [ 2 ] libros de texto [ 4 ] [ 5 ] [ 6 ] así como en la bibliografía .
Elementos del lenguaje
Fortran no distingue entre mayúsculas y minúsculas . En este artículo se adopta la convención de escribir las palabras clave de Fortran en mayúsculas y todos los demás nombres en minúsculas; excepto, a modo de contraste, en las descripciones de entrada/salida ( Transferencia de datos y Operaciones con archivos externos ).
Lo esencial
El componente básico del lenguaje Fortran es su conjunto de caracteres . Sus miembros son:
- las letras A ... Z y a ... z (que son equivalentes fuera de un contexto de caracteres)
- los números del 0 al 9
- el guion bajo _
- los personajes especiales
= : + blank - * / ( ) [ ] , . $ ' ! " % & ; <> ?
Los tokens que tienen un significado sintáctico para el compilador se construyen a partir de esos componentes. Hay seis clases de tokens:
A partir de los tokens, se construyen las declaraciones . Estas se pueden codificar utilizando el nuevo formato de código fuente libre que no requiere posicionamiento en una estructura de columna rígida:
FUNCIÓN string_concat ( s1 , s2 ) ! Este es un comentario TIPO ( cadena ), INTENCIÓN ( EN ) :: s1 , s2 TIPO ( cadena ) string_concat string_concat % string_data = s1 % string_data ( 1 : s1 % length ) // & s2 % string_data ( 1 : s2 % length ) ! Esta es una continuación string_concat % length = s1 % length + s2 % length FIN FUNCIÓN string_concatObserve los comentarios finales y la marca de continuación final. Puede haber 39 líneas de continuación y 132 caracteres por línea . Los espacios en blanco son significativos. Cuando un token o una constante de carácter se divide en dos líneas:
... inicio_de & & _ nombre ... 'una & &cadena muy larga'&También se requiere un paso adelante en la línea continua.
Tipos de datos intrínsecos
Fortran tiene cinco tipos de datos intrínsecos : INTEGER, REAL, COMPLEX, LOGICALy CHARACTER. Cada uno de esos tipos puede ser caracterizado adicionalmente por un tipo . El tipo, básicamente, define la representación interna del tipo: para los tres tipos numéricos, define la precisión y el rango, y para los otros dos, las especificidades de la representación de almacenamiento. Por lo tanto, es un concepto abstracto que modela los límites de la representación de los tipos de datos; se expresa como un miembro de un conjunto de números enteros (por ejemplo, puede ser {1, 2, 4, 8} para enteros, que denotan bytes de almacenamiento), pero esos valores no están especificados por el Estándar y no son portátiles. Para cada tipo, hay un tipo predeterminado , que se usa si no se especifica explícitamente ningún tipo. Para cada tipo intrínseco, hay una forma correspondiente de constante literal . Los tipos numéricos INTEGERy REALsolo pueden ser con signo (no hay concepto de signo para el tipo COMPLEX).
Constantes y tipos literales
ENTERO
Las constantes literales enteras del tipo predeterminado toman la forma
1 0 - 999 32767 + 10El tipo se puede definir como una constante con nombre. Si el rango deseado es ±10 tipos , la sintaxis portátil para definir el tipo apropiado two_byteses:
INTEGER,PARAMETER::two_bytes=SELECTED_INT_KIND(4)that allows subsequent definition of constants of the form
-1234_two_bytes+1_two_bytesHere, two_bytes is the kind type parameter; it can also be an explicit default integer literal constant, like
-1234_2but such use is non-portable.
The KIND function supplies the value of a kind type parameter:
KIND(1)KIND(1_two_bytes)and the RANGE function supplies the actual decimal range (so the user must make the actual mapping to bytes):
RANGE(1_two_bytes)Also, in DATA (initialization) statements, binary (B), octal (O) and hexadecimal (Z) constants may be used (often informally referred to as "BOZ constants"):
B'01010101'O'01234567'Z'10fa'REAL
There are at least two real kinds –the default and one with greater precision (this replaces DOUBLE PRECISION). SELECTED_REAL_KIND functions returns the kind number for desired range and precision; for at least 9 decimal digits of precision and a range of 10−99 to 1099, it can be specified as:
INTEGER,PARAMETER::long=SELECTED_REAL_KIND(9,99)and literals subsequently specified as
1.7_longAlso, there are the intrinsic functions
KIND(1.7_long)PRECISION(1.7_long)RANGE(1.7_long)that give in turn the kind type value, the actual precision (here at least 9), and the actual range (here at least 99).
COMPLEX
COMPLEX data type is built of two integer or real components:
(1,3.7_long)LOGICAL
There are only two basic values of logical constants: .TRUE. and .FALSE.. Here, there may also be different kinds. Logicals don't have their own kind inquiry functions, but use the kinds specified for INTEGERs; default kind of LOGICAL is the same as of INTEGER.
.FALSE..true._one_byteand the KIND function operates as expected:
KIND(.TRUE.)CHARACTER
The forms of literal constants for CHARACTER data type are
'A string'"Another"'A "quote"''''''''(el último es una cadena vacía ). Se permiten diferentes tipos (por ejemplo, para distinguir cadenas ASCII y UNICODE ), pero no son ampliamente compatibles con los compiladores. Nuevamente, el valor del tipo viene dado por la KINDfunción:
TIPO ( 'ASCII' )Modelo numérico y funciones intrínsecas
Los tipos numéricos se basan en modelos numéricos con funciones de consulta asociadas (cuyos valores son independientes de los valores de sus argumentos; los argumentos se utilizan únicamente para indicar el tipo). Estas funciones son importantes para el software numérico portátil:
Variables escalares
Las variables escalares correspondientes a los cinco tipos intrínsecos se especifican de la siguiente manera:
ENTERO ( TIPO = 2 ) :: i REAL ( TIPO = largo ) :: a COMPLEJO :: actual LÓGICO :: Pravda CARÁCTER ( LONGITUD = 20 ) :: palabra CARÁCTER ( LONGITUD = 2 , TIPO = Kanji ) :: palabra_kanjidonde el KINDparámetro opcional especifica un tipo distinto al predeterminado, y la ::notación delimita el tipo y los atributos de los nombres de las variables y sus valores iniciales opcionales, lo que permite especificar e inicializar completamente las variables en una sola instrucción (en estándares anteriores, los atributos e inicializadores debían declararse en varias instrucciones). Si bien no es necesario en los ejemplos anteriores (ya que no hay atributos ni inicialización adicionales), la mayoría de los programadores de Fortran-90 adquieren el hábito de usarlo en todas partes.
LEN=El especificador es aplicable solo a CHARACTERs y especifica la longitud de la cadena (reemplazando la *lenforma anterior). Los especificadores explícitos KIND=y LEN=son opcionales:
CARÁCTER ( 2 , Kanji ) :: palabra_kanjiFunciona igual de bien.
Hay otras características interesantes del carácter. Al igual que una subcadena como en
CARÁCTER ( 80 ) :: línea ... = línea ( i : i ) ! subcadenaAnteriormente era posible, por lo que ahora es la subcadena.
'0123456789' ( i : i )Además, se permiten cadenas de longitud cero:
line(i:i-1)! zero-length stringFinally, there is a set of intrinsic character functions, examples being
Derived data types
For derived data types, the form of the type must be defined first:
TYPE personCHARACTER(10)nameREAL ageEND TYPE personand then, variables of that type can be defined:
TYPE(person)you,meTo select components of a derived type, % qualifier is used:
you%ageLiteral constants of derived types have the form TypeName(1stComponentLiteral, 2ndComponentLiteral, ...):
you=person('Smith',23.5)which is known as a structure constructor. Definitions may refer to a previously defined type:
TYPE pointREAL x,yEND TYPE pointTYPE triangleTYPE(point)a,b,cEND TYPE triangleand for a variable of type triangle, as in
TYPE(triangle)teach component of type point is accessed as
t%at%bt%cwhich, in turn, have ultimate components of type real:
t%a%xt%a%yt%b%xetc.(Note that the % qualifier was chosen rather than dot (.) because of potential ambiguity with operator notation, like .OR.).
Implicit and explicit typing
Unless specified otherwise, all variables starting with letters I, J, K, L, M and N are default INTEGERs, and all others are default REAL; other data types must be explicitly declared. This is known as implicit typing and is a heritage of early FORTRAN days. Those defaults can be overridden by IMPLICIT TypeName (CharacterRange) statements, like:
IMPLICIT COMPLEX(Z)IMPLICIT CHARACTER(A-B)IMPLICIT REAL(C-H,N-Y)Sin embargo, es una buena práctica tipificar explícitamente todas las variables, y esto se puede forzar insertando la instrucción IMPLICIT NONE al principio de cada unidad de programa.
Matrices
Los arreglos se consideran variables por derecho propio. Cada arreglo se caracteriza por su tipo , rango y forma (que define los límites de cada dimensión). Los límites de cada dimensión son por defecto 1 y tamaño , pero se pueden especificar límites arbitrarios explícitamente. DIMENSIONLa palabra clave es opcional y se considera un atributo; si se omite, la forma del arreglo debe especificarse después del nombre de la variable del arreglo. Por ejemplo,
REAL :: a ( 10 ) ENTERO , DIMENSIÓN ( 0 : 100 , - 50 : 50 ) :: mapaDeclara dos arreglos, rango-1 y rango-2, cuyos elementos están en orden de columna principal . Los elementos son, por ejemplo,
a ( 1 ) a ( i * j )y son escalares. Los subíndices pueden ser cualquier expresión entera escalar.
Las secciones son partes de las variables de matriz y, a su vez, son matrices:
a ( i : j ) ! rango uno map ( i : j , k : l : m ) ! rango dos a ( map ( i , k : l )) ! vector subíndice a ( 3 : 2 ) ! longitud ceroLos arreglos completos y las secciones de arreglos son objetos con valores de arreglo. Las constantes con valores de arreglo (constructores) están disponibles y se encuentran encerradas entre (/ ... /):
( / 1 , 2 , 3 , 4 / ) ( / ( ( / 1 , 2 , 3 / ), i = 1 , 4 ) / ) ( / ( i , i = 1 , 9 , 2 ) / ) ( / ( 0 , i = 1 , 100 ) / ) ( / ( 0.1 * i , i = 1 , 10 ) / )utilizando una notación de bucle DO implícita. Fortran 2003 permite el uso de corchetes: [1, 2, 3, 4]y [([1,2,3], i=1,4)] en lugar de los dos primeros ejemplos anteriores, y muchos compiladores ahora lo admiten. Un tipo de datos derivado puede, por supuesto, contener componentes de matriz:
TIPO triplete REAL , DIMENSIÓN ( 3 ) :: vértice FIN TIPO triplete TIPO ( triplete ), DIMENSIÓN ( 4 ) :: tde modo que
t(2)es un escalar (una estructura)t(2)%vertexes un componente de matriz de un escalar
Inicialización de datos
Las variables pueden recibir valores iniciales según se especifique en una declaración de especificación:
REAL , DIMENSIÓN ( 3 ) :: a = ( / 0.1 , 0.2 , 0.3 / )y se puede asignar un valor inicial predeterminado al componente de un tipo de datos derivado:
TIPO triplete REAL , DIMENSIÓN ( 3 ) :: vértice = 0.0 FIN TIPO tripleteCuando las variables locales se inicializan dentro de un procedimiento, adquieren implícitamente el atributo SAVE:
REAL , DIMENSIÓN ( 3 ) :: punto = ( / 0.0 , 1.0 , -1.0 / )Esta declaración es equivalente a
REAL , DIMENSIÓN ( 3 ) , GUARDAR :: punto = ( / 0.0 , 1.0 , -1.0 / )Para variables locales dentro de una subrutina o función. El atributo SAVE hace que las variables locales conserven su valor después de una llamada a procedimiento y, posteriormente, que la variable se inicialice con el valor guardado al regresar al procedimiento.
atributo PARÁMETRO
Se puede especificar una constante con nombre directamente agregando el PARAMETERatributo y los valores de la constante a una declaración de tipo:
REAL , DIMENSIÓN ( 3 ), PARÁMETRO :: campo = ( / 0. , 1. , 2. / ) TIPO ( triplete ), PARÁMETRO :: t = triplete ( ( / 0. , 0. , 0. / ) )Declaración de datos
Esta DATAinstrucción se puede usar para escalares, así como para matrices y variables de tipo derivado. Además, es la única forma de inicializar solo partes de dichos objetos, así como de inicializarlos con valores binarios, octales o hexadecimales.
TIPO ( triplete ) :: t1 , t2 DATOS t1 / triplete ( ( / 0. , 1. , 2. / ) ) / , t2 % vértice ( 1 ) / 12 3. / DATOS matriz ( 1 : 64 ) / 64 * 0 / DATOS i , j , k / B '01010101' , O '77' , Z 'ff' /expresiones de inicialización
Los valores utilizados en las declaraciones DATAy PARAMETER, o con estos atributos, son expresiones constantes que pueden incluir referencias a: constructores de matrices y estructuras, funciones intrínsecas elementales con argumentos y resultados enteros o de caracteres, y las seis funciones de transformación REPEAT, SELECTED_INT_KIND, TRIM, SELECTED_REAL_KIND, RESHAPEy TRANSFER(véase Procedimientos intrínsecos ):
ENTERO , PARÁMETRO :: long = SELECTED_REAL_KIND ( 12 ), & array ( 3 ) = ( / 1 , 2 , 3 / )expresiones de especificación
Es posible especificar detalles de variables utilizando cualquier expresión escalar entera no constante que también puede incluir referencias a funciones de consulta:
SUBRUTINA s ( b , m , c ) USE mod ! contiene a REAL , DIMENSIÓN (:, :) :: b REAL , DIMENSIÓN ( UBOUND ( b , 1 ) + 5 ) :: x ENTERO :: m CARÁCTER ( LEN =* ) :: c CARÁCTER ( LEN = m + LEN ( c )) :: cc REAL ( SELECTED_REAL_KIND ( 2 * PRECISION ( a ))) :: zExpresiones y asignaciones
numérico escalar
Están disponibles los operadores aritméticos habituales ( presentados aquí en orden creciente de precedencia). +, -, *, /, **
Los paréntesis se utilizan para indicar el orden de evaluación cuando sea necesario:
a * b + c ! * primero a * ( b + c ) ! + primeroLas reglas para expresiones y asignaciones numéricas escalares admiten tipos no predeterminados. Por lo tanto, las reglas de expresiones y asignaciones numéricas de modo mixto incorporan diferentes parámetros de tipo de clase de la manera esperada:
real2 = entero0 + real1convierte integer0a un valor real del mismo tipo que real1; el resultado es del mismo tipo y se convierte al tipo de real2para la asignación.
Estas funciones están disponibles para el redondeo controlado de números reales a enteros:
NINT: redondear al entero más cercano, devolver resultado enteroANINT: redondear al entero más cercano, devolver el resultado realINT: truncar (redondear hacia cero), devolver resultado enteroAINT: truncar (redondear hacia cero), devolver el resultado realCEILING: valor entero más pequeño no menor que el argumento (redondeo hacia arriba) (Fortran-90)FLOOR: valor entero más grande no mayor que el argumento (redondeo hacia abajo) (Fortran-90)
Operaciones relacionales escalares
Para las operaciones relacionales escalares de tipos numéricos, existe un conjunto de operadores integrados:
< <= == /= > >= .LT. .LE. .EQ. .NE. .GT. .GE.
(Las formas anteriores son nuevas en Fortran-90, y debajo se proporcionan formas equivalentes más antiguas). Ejemplos de expresiones:
a < b . Y . i /= j ! para variables numéricas flag = a == b ! para variables lógicas flagscaracteres escalares
En el caso de caracteres escalares y dadoCHARACTER(8)result
Es legal escribir
resultado ( 3 : 5 ) = resultado ( 1 : 3 ) ! superposición permitida resultado ( 3 : 3 ) = resultado ( 3 : 2 ) ! no se permite la asignación de cadena nulaLa concatenación se realiza mediante el operador '//'.
resultado = 'abcde' // '123' nombre de archivo = resultado // '.dat'Tipos de datos derivados
No existen operaciones integradas (excepto la asignación, definida componente por componente) entre tipos de datos derivados, ya sea entre sí o con tipos intrínsecos. Sin embargo, el significado de los operadores existentes o especificados por el usuario puede (re)definirse:
TIPO string80 ENTERO longitud CARÁCTER ( 80 ) valor FIN TIPO string80 CARÁCTER :: char1 , char2 , char3 TIPO ( string80 ) :: str1 , str2 , str3podemos escribir
str3 = str1 // str2 ! debe definir la operación str3 = str1 . concat . str2 ! debe definir la operación char3 = char2 // char3 ! operador intrínseco solamente str3 = char1 ! debe definir la asignaciónNótese el uso " sobrecargado " del símbolo intrínseco //y del operador con nombre, .concat.. Una diferencia entre los dos casos es que, para un token de operador intrínseco, se aplican las reglas de precedencia habituales, mientras que para los operadores con nombre, la precedencia es la más alta como operador unario o la más baja como operador binario. En
vector3 = matriz * vector1 + vector2 vector3 = ( matriz . veces . vector1 ) + vector2Las dos expresiones son equivalentes solo si se añaden los paréntesis apropiados, como se muestra. En cada caso, debe haber procedimientos definidos, en un módulo , que definan el operador y la asignación, y la asociación operador-procedimiento correspondiente, como sigue:
OPERADOR DE INTERFAZ ( // ) !Sobrecarga el operador // como procedimiento de invocación string_concat MÓDULO PROCEDIMIENTO string_concat FIN DE INTERFAZLa función de concatenación de cadenas es una versión más elaborada de la que ya se mostró en la sección de Conceptos básicos . Cabe destacar que, para gestionar el error que se produce cuando las dos cadenas juntas superan el límite preestablecido de 80 caracteres, sería más seguro utilizar una subrutina para realizar la concatenación (en este caso, no sería aplicable la sobrecarga de operadores).
MÓDULO string_type IMPLICIT NONE TYPE string80 INTEGER length CHARACTER ( LEN = 80 ) :: string_data END TYPE string80 INTERFACE ASSIGNMENT ( = ) MODULE PROCEDURE c_to_s_assign , s_to_c_assign END INTERFACE INTERFACE OPERATOR ( // ) MODULE PROCEDURE string_concat END INTERFACE CONTAINS SUBROUTINE c_to_s_assign ( s , c ) TYPE ( string80 ), INTENT ( OUT ) :: s CHARACTER ( LEN =* ), INTENT ( IN ) :: c s % string_data = c s % length = LEN ( c ) END SUBROUTINE c_to_s_assign SUBROUTINE s_to_c_assign ( c , s ) TYPE ( string80 ), INTENT ( IN ) :: s CHARACTER ( LEN =* ), INTENCIÓN ( SALIDA ) :: c c = s % string_data ( 1 : s % longitud ) FIN SUBRUTINA s_to_c_assign TIPO ( cadena80 ) FUNCIÓN string_concat ( s1 , s2 ) TIPO ( cadena80 ), INTENCIÓN ( ENTRADA ) :: s1 , s2 TIPO ( cadena80 ) :: s ENTERO :: n1 , n2 CARÁCTER ( 160 ) :: ctot n1 = LEN_TRIM ( s1 % string_data ) n2 = LEN_TRIM ( s2 %string_data ) SI ( n1 + n2 <= 80 ) entonces s % string_data = s1 % string_data ( 1 : n1 ) // s2 % string_data ( 1 : n2 ) SINO ! Esta es una condición de error que debe manejarse; por ahora, simplemente trunca ctot = s1 % string_data ( 1 : n1 ) // s2 % string_data ( 1 : n2 ) s % string_data = ctot ( 1 : 80 ) FIN SI s % length = LEN_TRIM ( s % string_data ) string_concat = s FIN FUNCIÓN string_concat FIN MÓDULO string_typePROGRAMA principal USAR string_type TIPO ( string80 ) :: s1 , s2 , s3 LLAMAR c_to_s_assign ( s1 , 'Mi nombre es' ) LLAMAR c_to_s_assign ( s2 , ' Linus Torvalds' ) s3 = s1 // s2 ESCRIBIR ( * , * ) 'Resultado: ' , s3 % string_data ESCRIBIR ( * , * ) 'Longitud: ' , s3 % length FIN DEL PROGRAMASe requieren operadores definidos como estos para las expresiones que también están permitidas en los constructores de estructuras (ver Tipos de datos derivados ):
str1 = string ( 2 , char1 // char2 ) ! constructor de estructuraMatrices
En el caso de los arreglos, siempre que tengan la misma forma (conformables), las operaciones y asignaciones se extienden de manera obvia, elemento por elemento. Por ejemplo, dadas las declaraciones de
REAL , DIMENSIÓN ( 10 , 20 ) :: a , b , c REAL , DIMENSIÓN ( 5 ) :: v , w LOGICAL flag ( 10 , 20 )Se puede escribir:
a = b ! asignación de matriz completa c = a / b ! división y asignación de matriz completa c = 0. ! asignación de matriz completa del valor escalar w = v + 1. ! suma de matriz completa al valor escalar w = 5 / v + a ( 1 : 5 , 5 ) ! división de matriz y suma al indicador de sección = a == b ! prueba relacional y asignación de matriz completa c ( 1 : 8 , 5 : 10 ) = a ( 2 : 9 , 5 : 10 ) + b ( 1 : 8 , 15 : 20 ) ! suma y asignación de sección de matriz v ( 2 : 5 ) = v ( 1 : 4 ) ! asignación de sección superpuestaEl orden de evaluación de las expresiones no se especifica para permitir la optimización en máquinas paralelas y vectoriales. Por supuesto, cualquier operador para matrices de tipo derivado debe estar definido.
Algunas funciones intrínsecas reales que son útiles para los cálculos numéricos son:
CEILINGFLOORMODULO(también entero)EXPONENTFRACTIONNEARESTRRSPACINGSPACINGSCALESET_EXPONENT
Estos son valores de matriz para argumentos de matriz (elementales), como todas las funciones de FORTRAN 77 (excepto LEN):
INTREALCMPLXAINTANINTNINTABSMODSIGNDIMMAXMIN
Potencias, logaritmos y funciones trigonométricas
SQRTEXPLOGLOG10SINCOSTANASINACOSATANATAN2SINHCOSHTANH
Números complejos:
AIMAGCONJG
Lo siguiente se refiere a los personajes:
LGELGTLLELLTICHARCHARINDEX
Declaraciones de control
Ramificación y condiciones
La GO TOetiqueta simple existe, pero generalmente se evita ; en la mayoría de los casos, una estructura de ramificación más específica logrará la misma lógica con mayor claridad.
La prueba condicional simple es la IFsiguiente:IF(a>b)x=y
Una construcción completa IFse ilustra mediante
SI ( i < 0 ) ENTONCES SI ( j < 0 ) ENTONCES x = 0. SINO z = 0. FIN SI SINO SI ( k < 0 ) ENTONCES z = 1. SINO x = 1. FIN SIConstrucción CASE
Esta CASEconstrucción reemplaza a la calculada GOTO, pero está mejor estructurada y no requiere el uso de etiquetas de sentencia:
SELECCIONAR CASO ( número ) ! número de tipo entero CASO (: - 1 ) ! todos los valores menores que 0 n_sign = - 1 CASO ( 0 ) ! solo 0 n_sign = 0 CASO ( 1 :) ! todos los valores mayores que 0 n_sign = 1 FIN SELECCIONARCada CASElista de selección puede contener una lista y/o un rango de números enteros, caracteres o constantes lógicas, cuyos valores no pueden superponerse dentro de los selectores ni entre ellos:
CASO ( 1 , 2 , 7 , 10 : 17 , 23 )Hay una opción predeterminada disponible:
CASO INCOMPETENTESolo hay una evaluación y solo un partido.
Construir
Una forma simplificada pero suficiente de la DOconstrucción se ilustra mediante:
exterior : HACER interior : HACER i = j , k , l ! de j a k en pasos de l (l es opcional) : SI (...) CICLO : SI (...) SALIR exterior : FIN HACER interior FIN HACER exteriordonde observamos que los bucles pueden tener nombres opcionales, de modo que cualquier instrucción EXIT o CYCLE puede especificar a qué bucle se refiere.
Muchos, aunque no todos, los bucles simples pueden reemplazarse por expresiones y asignaciones de matrices, o por nuevas funciones intrínsecas. Por ejemplo
tot = 0. HACER i = m , n tot = tot + a ( i ) FIN HACERse convierte simplementetot=SUM(a(m:n))
Unidades y procedimientos del programa
Definiciones
Para abordar este tema, necesitamos algunas definiciones. En términos lógicos, un programa ejecutable consta de un programa principal y uno o más subprogramas (o procedimientos ), que realizan alguna función. Los subprogramas pueden ser funciones o subrutinas , ya sean externas, internas o de módulo . (Las subrutinas externas son las que ya conocíamos de FORTRAN 77).
Desde un punto de vista organizativo, sin embargo, un programa completo consta de unidades de programa . Estas pueden ser programas principales, subprogramas externos o módulos , y pueden compilarse por separado.
Un ejemplo de un programa principal (y completo) es
PROGRAMA test IMPRIMIR * , '¡Hola mundo!' FIN DEL PROGRAMA testUn ejemplo de un programa principal y un subprograma externo que forman un programa ejecutable es:
PROGRAMA test LLAMAR print_message FIN PROGRAMA test SUBRUTINA print_message IMPRIMIR * , '¡Hola mundo!' FIN SUBRUTINA print_messageLa forma de una función es
FUNCIÓN nombre ( arg1 , arg2 ) ! cero o más argumentos : nombre = ... : FIN FUNCIÓN nombreLa forma de referencia de una función esx=name(a,b)
Procedimientos internos
Un subprograma interno es aquel que está contenido dentro de otro (con un máximo de un nivel de anidamiento) y proporciona un reemplazo para la función de instrucción:
SUBRUTINA exterior REAL x , y : CONTIENE SUBRUTINA interior REAL y y = x + 1 .: FIN SUBRUTINA interior ! SUBRUTINA obligatoria FIN SUBRUTINA exteriorDecimos que outeres el anfitrión de inner, y que innerobtiene acceso a entidades en outermediante asociación de anfitrión (por ejemplo, a x), mientras que yes una variable localinner de .
El alcance de una entidad nombrada es una unidad de alcance , aquí outerless inner, y inner.
Los nombres de las unidades de programa y los procedimientos externos son globales , y los nombres de las variables DO implícitas tienen un ámbito limitado a la instrucción que las contiene.
Módulos
Los módulos se utilizan para empaquetar
- Datos globales (sustituye a COMMON y BLOCK DATA de Fortran 77);
- definiciones de tipo (que constituyen en sí mismas una unidad de alcance);
- subprogramas (que entre otras cosas reemplazan el uso de ENTRY de Fortran 77);
- bloques de interfaz (otra unidad de alcance, véase Bloques de interfaz );
- grupos de nombres (consulte cualquier libro de texto).
Un ejemplo de un módulo que contiene una definición de tipo, un bloque de interfaz y un subprograma de función es:
MÓDULO interval_arithmetic TIPO interval REAL lower , upper FIN TIPO interval INTERFACE OPERATOR ( + ) MÓDULO PROCEDIMIENTO add_intervals FIN INTERFACE : CONTIENE FUNCIÓN add_intervals ( a , b ) TIPO ( interval ), INTENCIÓN ( IN ) :: a , b TIPO ( interval ) add_intervals add_intervals % lower = a % lower + b % lower add_intervals % upper = a % upper + b % upper FIN FUNCIÓN add_intervals ! FUNCIÓN mandatory : FIN MÓDULO interval_arithmeticy la simple declaración
USE interval_arithmeticProporciona asociación de uso a todas las entidades del módulo. Los subprogramas del módulo pueden, a su vez, contener subprogramas internos.
Controlar la accesibilidad
Los atributos PUBLICy PRIVATEse utilizan en las especificaciones de los módulos para limitar el alcance de las entidades. La forma del atributo es
REAL , PÚBLICO :: x , y , z ! predeterminado ENTERO , PRIVADO :: u , v , wy el formulario de declaración es
PÚBLICO :: x , y , z , OPERADOR (. add .) PRIVADO :: u , v , w , ASIGNACIÓN ( = ), OPERADOR ( * )El formulario de declaración debe utilizarse para limitar el acceso a los operadores y también puede utilizarse para cambiar la configuración predeterminada general:
PRIVADO ! establece el valor predeterminado para el módulo PÚBLICO :: only_thisPara los tipos derivados existen tres posibilidades: el tipo y sus componentes son todos PÚBLICOS, el tipo es PÚBLICO y sus componentes PRIVADOS (solo el tipo es visible y se pueden cambiar sus detalles fácilmente), o todo es PRIVADO (solo para uso interno en el módulo):
MÓDULO mine TIPO PRIVADO , PÚBLICO :: lista REAL x , y TIPO ( lista ), PUNTERO :: siguiente FIN TIPO lista TIPO ( lista ) :: árbol : FIN MÓDULO mineEl USEpropósito de esta instrucción es obtener acceso a entidades en un módulo. Tiene opciones para resolver conflictos de nombres si un nombre importado es igual a uno local:
USE mine , local_list => listo restringir las entidades utilizadas a un conjunto específico:
USA el mío , SOLAMENTE : listaEstos se pueden combinar:
USE mine , ONLY : local_list => listArgumentos
Podemos especificar la intención de los argumentos ficticios:
SUBRUTINA barajar ( ncards , cards ) ENTERO , INTENCIÓN ( ENTRADA ) :: ncards ENTERO , INTENCIÓN ( SALIDA ), DIMENSIÓN ( ncards ) :: cardsAdemás, es posible usar INOUT: en este caso, el argumento real debe ser una variable (a diferencia del caso predeterminado, donde puede ser una constante).
Los argumentos pueden ser opcionales:
SUBRUTINA mincon ( n , f , x , superior , inferior , igualdades , desigualdades , convexo , xinicio ) REAL , OPCIONAL , DIMENSIÓN :: superior , inferior : SI ( PRESENTE ( inferior )) ENTONCES ! comprobar la presencia del argumento real :nos permite llamar minconpor
LLAMAR mincon ( n , f , x , upper )Los argumentos pueden ser palabras clave en lugar de argumentos posicionales (que van primero):
LLAMAR mincon ( n , f , x , equalities = 0 , xstart = x0 )Los argumentos opcionales y con nombre se gestionan mediante interfaces explícitas, es decir, con procedimientos internos o de módulo o con bloques de interfaz.
Bloques de interfaz
Cualquier referencia a un subprograma interno o de módulo se realiza mediante una interfaz explícita (es decir, el compilador puede ver todos los detalles). Una referencia a un procedimiento externo (o ficticio) suele ser implícita (el compilador asume los detalles). Sin embargo, también podemos proporcionar una interfaz explícita en este caso. Se trata de una copia del encabezado, las especificaciones y la instrucción END del procedimiento en cuestión, ya sea ubicada en un módulo o insertada directamente.
REAL FUNCTION minimum ( a , b , func ) ! devuelve el valor mínimo de la función func(x) ! en el intervalo (a,b) REAL , INTENT ( in ) :: a , b INTERFACE REAL FUNCTION func ( x ) REAL , INTENT ( IN ) :: x END FUNCTION func END INTERFACE REAL f , x : f = func ( x ) ! invocación de la función de usuario. : END FUNCTION minimumUna interfaz explícita es obligatoria para
- argumentos opcionales y con nombre;
- Argumentos POINTER y TARGET (véase Punteros );
- Resultado de la función PUNTERO;
- Nuevo estilo de argumentos y funciones de matrices ( Manejo de matrices ).
Permite realizar comprobaciones completas en tiempo de compilación entre argumentos reales y ficticios.
En general, la mejor manera de garantizar que la interfaz de un procedimiento sea explícita es colocar el procedimiento en cuestión en un módulo o utilizarlo como un procedimiento interno.
Sobrecarga e interfaces genéricas
Los bloques de interfaz proporcionan el mecanismo mediante el cual podemos definir nombres genéricos para procedimientos específicos:
INTERFAZ gamma ! nombre genérico FUNCIÓN sgamma ( X ) ! nombre específico REAL ( SELECTED_REAL_KIND ( 6 )) sgamma , x FIN FUNCIÓN dgamma ( X ) ! nombre específico REAL ( SELECTED_REAL_KIND ( 12 )) dgamma , x FIN FIN INTERFAZdonde un conjunto dado de nombres específicos que corresponden a un nombre genérico deben ser todos de funciones o todos de subrutinas. Si esta interfaz está dentro de un módulo, entonces es simplemente
INTERFAZ gamma PROCEDIMIENTO DEL MÓDULO sgamma , dgamma INTERFAZ FINALPodemos usar nombres existentes, por ejemplo SIN, y el compilador se encarga de establecer la asociación correcta.
Ya hemos visto el uso de bloques de interfaz para operadores definidos y asignación (ver Módulos ).
Recursión
La recursión indirecta es útil para la integración multidimensional. Para
volumen = integrar ( fy , límites y )Podríamos tener
FUNCIÓN RECURSIVA integrar ( f , límites ) ! Integrar f(x) desde límites(1) hasta límites(2) REAL integrar INTERFAZ FUNCIÓN f ( x ) REAL f , x FIN FUNCIÓN f FIN INTERFAZ REAL , DIMENSIÓN ( 2 ), INTENCIÓN ( EN ) :: límites : FIN FUNCIÓN integrary para integrar f(x, y) sobre un rectángulo:
FUNCIÓN fy ( y ) USAR func ! el módulo func contiene la función f REAL fy , y yval = y fy = integrar ( f , xbounds ) FINLa recursión directa es cuando un procedimiento se llama a sí mismo, como en
FUNCIÓN RECURSIVA factorial ( n ) RESULTADO ( res ) ENTERO res , n SI ( n . EQ . 0 ) ENTONCES res = 1 SINO res = n * factorial ( n - 1 ) FIN SI FINAquí, destacamos la RESULTcláusula y la prueba de terminación.
Procedimientos puros
Esta es una característica para la computación paralela .
En la instrucción y construcción FORALL , cualquier efecto secundario en una función puede impedir la optimización en un procesador paralelo ; el orden de ejecución de las asignaciones podría afectar los resultados. Para controlar esta situación, agregamos la palabra clave a la instrucción OR , una afirmación de que el procedimiento (expresado simplemente): PURESUBROUTINE FUNCTION
- no altera ninguna variable global ,
- no realiza ninguna E/S,
- no tiene variables guardadas (variables con el
SAVEatributo que conserva valores entre invocaciones), y - Para las funciones, no altera ninguno de sus argumentos.
Un compilador puede comprobar que este es el caso, como en
FUNCIÓN PURA calcular ( x )Todas las funciones intrínsecas son puras.
Manejo de matrices
El manejo de matrices se incluye en Fortran por dos razones principales:
- la conveniencia notacional que proporciona, acercando el código a la forma matemática subyacente;
- por las oportunidades de optimización adicionales que ofrece a los compiladores (¡aunque también hay muchas oportunidades para degradar la optimización!).
Al mismo tiempo, se han añadido importantes extensiones de la funcionalidad en esta área. Ya hemos visto matrices completas arriba #Arrays 1 y aquí #Arrays 2 ; ahora desarrollamos el tema.
Matrices de tamaño cero
Fortran maneja un array de tamaño cero como un objeto legítimo, sin necesidad de codificación especial por parte del programador. Por lo tanto, en
HACER i = 1 , n x ( i ) = b ( i ) / a ( i , i ) b ( i + 1 : n ) = b ( i + 1 : n ) - a ( i + 1 : n , i ) * x ( i ) FIN HACERNo se requiere ningún código especial para la iteración final donde i = n. Observamos que una matriz de tamaño cero se considera definida; sin embargo, una matriz de forma (0,2) no es compatible con una de forma (0,3), mientras que es una instrucción válida de 'no hacer nada'.x(1:0)=3
Matrices con forma supuesta
Estas son una extensión y un reemplazo para los arreglos de tamaño asumido. Dado un argumento real como:
REAL , DIMENSIÓN ( 0:10 , 0:20 ) :: a : CALL sub ( a )La especificación del argumento ficticio correspondiente define solo el tipo y el rango de la matriz, no su forma. Esta información debe estar disponible mediante una interfaz explícita, a menudo utilizando un bloque de interfaz (véase Bloques de interfaz ). Por lo tanto, escribimos simplemente
SUBRUTINA sub ( da ) REAL , DIMENSIÓN (:, :) :: day esto es como si datuviera dimensiones (11,21). Sin embargo, podemos especificar cualquier límite inferior y la matriz se adaptará en consecuencia.
REAL , DIMENSIÓN ( 0 :, 0 :) :: daSe pasa la forma, no los límites, donde el límite inferior predeterminado es 1 y el límite superior predeterminado es la extensión correspondiente.
matrices automáticas
EQUIVALENCE Esta instalación proporciona un reemplazo parcial para los usos a los que se destinaba, útil para arreglos locales y temporales, como en
SUBRUTINA swap ( a , b ) REAL , DIMENSION (:) :: a , b REAL , DIMENSION ( SIZE ( a )) :: work work = a a = b b = work FIN DE SUBRUTINA swapEl almacenamiento propiamente dicho se mantiene normalmente en una pila.
ASIGNABLE y ASIGNAR
Fortran proporciona asignación dinámica de almacenamiento; se basa en un mecanismo de almacenamiento de montón (y reemplaza otro uso de EQUIVALENCE). Un ejemplo para establecer un arreglo de trabajo para todo un programa es
MÓDULO work_array ENTERO n REAL , DIMENSIÓN (:,:,:), ASIGNABLE :: work FIN DEL MÓDULO PROGRAMA principal USAR work_array LEER ( entrada , * ) n ASIGNAR ( work ( n , 2 * n , 3 * n ), ESTADO = estado ) : DESASIGNAR ( work )El arreglo de trabajo se puede propagar a través de todo el programa mediante una USE instrucción en cada unidad de programa. Podemos especificar un límite inferior explícito y asignar varias entidades en una sola instrucción. Para liberar almacenamiento muerto escribimos, por ejemplo,
DESALOJAR ( a , b )La desasignación de matrices es automática cuando salen del ámbito.
Operaciones, asignaciones y procedimientos elementales
Ya hemos realizado todas las asignaciones y operaciones de matrices:
REAL , DIMENSIÓN ( 10 ) :: a , b a = 0. ! difusión escalar; asignación elemental b = SQRT ( a ) ! resultado de la función intrínseca como objeto de matrizEn la segunda tarea, una función intrínseca devuelve un resultado con valores de matriz para un argumento con valores de matriz. Podemos escribir nosotros mismos funciones con valores de matriz (requieren una interfaz explícita):
PROGRAMA test REAL , DIMENSIÓN ( 3 ) :: a = ( / 1. , 2. , 3. / ), & b = ( / 2. , 2. , 2. / ), r r = f ( a , b ) PRINT * , r CONTIENE FUNCIÓN f ( c , d ) REAL , DIMENSIÓN (:) :: c , d REAL , DIMENSIÓN ( SIZE ( c )) :: f f = c * d ! (o alguna función más útil de c y d) FIN FUNCIÓN f FIN PROGRAMA testLos procedimientos elementales se especifican con argumentos ficticios escalares que pueden llamarse con argumentos reales en forma de matriz. En el caso de una función, la forma del resultado es la misma que la de los argumentos de la matriz.
La mayoría de las funciones intrínsecas son elementales, y Fortran 95 extiende esta característica a los procedimientos no intrínsecos, lo que permite escribir, en Fortran 90, 22 versiones diferentes para los rangos 0-0, 0-1, 1-0, 1-1, 0-2, 2-0, 2-2, ... 7-7, y además facilita la optimización en procesadores paralelos. Un procedimiento elemental debe ser puro.
SUBRUTINA ELEMENTAL swap ( a , b ) REAL , INTENCIÓN ( ENTRADA/SALIDA ) :: a , b REAL :: trabajo trabajo = a a = b b = trabajo FIN DE LA SUBRUTINA swapLos argumentos ficticios no se pueden usar en expresiones de especificación (ver arriba ) excepto como argumentos para ciertas funciones intrínsecas ( BIT_SIZE, KIND, LEN, y las de consulta numérica, (ver abajo ).
DÓNDE
A menudo, necesitamos enmascarar una asignación. Esto podemos hacerlo usando WHERE, ya sea como una declaración:
DONDE ( a /= 0.0 ) a = 1.0 / a ! evitar la división por 0(nota: la prueba es elemento por elemento, no sobre todo el array), o como una construcción:
DONDE ( a /= 0.0 ) a = 1.0 / a b = a ! todos los arreglos tienen la misma forma FIN DONDEo
DONDE ( a /= 0.0 ) a = 1.0 / a EN OTRO LUGAR a = ENORME ( a ) FIN DONDEMás:
- Está permitido enmascarar no solo la
WHEREdeclaración de laWHEREconstrucción, sino también cualquierELSEWHEREdeclaración que contenga; - Una
WHEREestructura puede contener cualquier número deELSEWHEREdeclaraciones enmascaradas, pero como máximo unaELSEWHEREdeclaración sin máscara, y esa debe ser la última; WHERELas construcciones pueden estar anidadas unas dentro de otras, simplementeFORALLconstrucciones;- Una
WHEREdeclaración de asignación puede ser una asignación definida, siempre que sea elemental; - Una
WHEREconstrucción puede nombrarse de la misma manera que otras construcciones.
La declaración y construcción de FORALL
Cuando DOse ejecuta una construcción, cada iteración sucesiva se realiza en orden y una tras otra , lo que supone un impedimento para la optimización en un procesador paralelo.
PARA TODOS ( i = 1 : n ) a ( i , i ) = x ( i )donde las asignaciones individuales pueden realizarse en cualquier orden, e incluso simultáneamente. Esto FORALLpuede considerarse una asignación de matriz expresada mediante índices.
PARA TODOS ( i = 1 : n , j = 1 : n , y ( i , j ) /= 0. ) x ( j , i ) = 1.0 / y ( i , j )con condición de enmascaramiento.
Esta FORALLestructura permite ejecutar varias sentencias de asignación en orden.
a ( 2 : n - 1 , 2 : n - 1 ) = a ( 2 : n - 1 , 1 : n - 2 ) + a ( 2 : n - 1 , 3 : n ) + a ( 1 : n - 2 , 2 : n - 1 ) + a ( 3 : n , 2 : n - 1 ) b ( 2 : n - 1 , 2 : n - 1 ) = a ( 2 : n - 1 , 2 : n - 1 )es equivalente a las asignaciones de matrices
PARA TODOS ( i = 2 : n - 1 , j = 2 : n - 1 ) a ( i , j ) = a ( i , j - 1 ) + a ( i , j + 1 ) + a ( i - 1 , j ) + a ( i + 1 , j ) b ( i , j ) = a ( i , j ) FIN PARA TODOSEsta FORALLversión es más legible.
La asignación en una función FORALLes similar a la asignación de un array: como si todas las expresiones se evaluaran en cualquier orden, se almacenaran temporalmente y, a continuación, se ejecutaran todas las asignaciones en cualquier orden. La primera instrucción debe completarse por completo antes de que pueda comenzar la segunda.
Un FORALLpuede estar anidado y puede incluir un WHERE. Los procedimientos a los que se hace referencia dentro de un FORALLdeben ser puros.
Elementos de matriz
Para un caso simple, dado
REAL , DIMENSIÓN ( 100 , 100 ) :: aPodemos hacer referencia a un único elemento como, por ejemplo, a(1, 1). Para un tipo de datos derivado como
TIPO fun_del REAL u REAL , DIMENSIÓN ( 3 ) :: du FIN TIPO fun_delPodemos declarar un array de ese tipo:
TIPO ( fun_del ), DIMENSIÓN ( 10 , 20 ) :: tary una referencia como es un elemento (¡un escalar!) de tipo fun_del, pero es un array de tipo real, y es un elemento de este. La regla básica que hay que recordar es que un elemento de un array siempre tiene un subíndice o subíndices que califican al menos el último nombre.tar(n,2)tar(n,2)%dutar(n,2)%du(2)
Subobjetos de matriz (secciones)
La forma general del subíndice para la sección de la matriz es
[ inferior ]: [ superior ] [: zancada ]
(donde [ ] indica un elemento opcional) como en
REAL a ( 10 , 10 ) a ( i , 1 : n ) ! parte de una fila a ( 1 : m , j ) ! parte de una columna a ( i , : ) ! fila completa a ( i , 1 : n : 3 ) ! cada tercer elemento de la fila a ( i , 10 : 1 : - 1 ) ! fila en orden inverso a ( ( / 1 , 7 , 3 , 2 / ), 1 ) ! subíndice de vector a ( 1 , 2 : 11 : 2 ) ! 11 es válido ya que no está referenciado a (:, 1 : 7 ) ! sección de rango dosTenga en cuenta que un subíndice vectorial con valores duplicados no puede aparecer en el lado izquierdo de una asignación, ya que sería ambiguo. Por lo tanto,
b ( ( / 1 , 7 , 3 , 7 / ) ) = ( / 1 , 2 , 3 , 4 / )es ilegal. Además, una sección con un subíndice vectorial no debe proporcionarse como argumento real a un argumento OUTficticio INOUT. No se permiten matrices de matrices:
alquitrán % du ! ilegalObservamos que un valor determinado en una matriz puede referenciarse tanto como un elemento como una sección:
a ( 1 , 1 ) ! escalar (rango cero) a ( 1 : 1 , 1 ) ! sección de matriz (rango uno)dependiendo de las circunstancias o requisitos. Al calificar objetos de tipo derivado, obtenemos elementos o secciones según la regla indicada anteriormente:
tar % u ! sección de matriz (componente de estructura) tar ( 1 , 1 )% u ! componente de un elemento de matrizFunciones intrínsecas de los arreglos
Multiplicación de vectores y matrices
Reducción de matrices
Consulta de matriz
Construcción de matrices
Remodelación de la matriz
Manipulación de matrices
Ubicación de la matriz
Consejos
Lo esencial
Los punteros son variables con el POINTERatributo; no son un tipo de dato distinto (y por lo tanto no es posible la "aritmética de punteros").
REAL , PUNTERO :: varConceptualmente, son un descriptor que enumera los atributos de los objetos (objetivos) a los que puede apuntar el puntero, y la dirección, si la hay, de un objetivo. No tienen almacenamiento asociado hasta que se asigna o se asocia de otra manera (mediante asignación de puntero, véase más abajo ):
ASIGNAR ( var )y se desreferencian automáticamente, por lo que no se requiere ningún símbolo especial. En
var = var + 2.3El valor del destino de var se usa y se modifica. Los punteros no se pueden transferir a través de E/S. La instrucción
ESCRIBIR * , varescribe el valor del destino de var y no el descriptor del puntero en sí.
Un puntero puede apuntar a otro puntero y, por lo tanto, a su destino, o a un objeto estático que tenga el TARGETatributo:
REAL , PUNTERO :: objeto REAL , OBJETIVO :: objeto_objetivo var => objeto ! asignación de puntero var => objeto_objetivopero están fuertemente tipificados:
ENTERO , PUNTERO :: int_var var => int_var ! ilegal: los tipos deben coincidirY, de forma similar, para los arreglos, tanto los rangos como el tipo deben coincidir.
Un puntero puede ser un componente de un tipo derivado:
TIPO entrada ! tipo para matriz dispersa REAL :: valor ENTERO :: índice TIPO ( entrada ), PUNTERO :: siguiente ! nota recursión FIN TIPO entraday podemos definir el comienzo de una cadena enlazada de dichas entradas:
TIPO ( entrada ), PUNTERO :: cadenaDespués de las asignaciones y definiciones adecuadas, las dos primeras entradas podrían ser tratadas como
cadena % cadena de valor % siguiente % cadena de valor % cadena de índice % siguiente % cadena de índice % siguiente cadena % siguiente % siguientepero normalmente definiríamos punteros adicionales para apuntar, por ejemplo, a la primera y a la entrada actual de la lista.
Asociación
El estado de asociación de un puntero es uno de
- indefinido (estado inicial);
- asociado (después de la asignación o la asignación de un puntero);
- disociado:
DEALLOCATE ( p , q ) ! para devolver almacenamiento NULLIFY ( p , q ) ! para establecer en 'null'
Hay que tener cuidado de no dejar un puntero "colgante" al usarlo DEALLOCATEen su destino sin anular ningún otro puntero que haga referencia a él.
La función intrínseca ASSOCIATEDpuede comprobar el estado de asociación de un puntero definido:
SI ( ASOCIADO ( ptr )) ENTONCESo entre un puntero definido y un destino definido (que, a su vez, puede ser un puntero):
SI ( ASOCIADO ( ptr , objetivo )) ENTONCESUna forma alternativa de inicializar un puntero, también en una declaración de especificación, es utilizar la NULLfunción:
REAL , PUNTERO , DIMENSIÓN (:) :: vector => NULL () ! tiempo de compilación vector => NULL () ! tiempo de ejecuciónPunteros en expresiones y asignaciones
Para tipos intrínsecos podemos "recorrer" punteros sobre diferentes conjuntos de datos de destino utilizando el mismo código sin ningún movimiento de datos. Dada la manipulación de la matriz y = BC z , podemos escribir el siguiente código (aunque, en este caso, el mismo resultado podría lograrse de forma más sencilla por otros medios):
REAL , OBJETIVO :: b ( 10 , 10 ), c ( 10 , 10 ), r ( 10 ), s ( 10 ), z ( 10 ) REAL , PUNTERO :: a (:,:), x (:), y (:) ENTERO mult : HACER mult = 1 , 2 SI ( mult == 1 ) ENTONCES y => r ! sin movimiento de datos a => c x => z SINO y => s ! sin movimiento de datos a => b x => r FIN SI y = MATMUL ( a , x ) ! cálculo común FIN HACERPara objetos de tipo derivado tenemos que distinguir entre asignación de puntero y asignación normal. En
TIPO ( entrada ), PUNTERO :: primero , actual : primero => actualla asignación hace primero apuntar a la corriente, mientras que
primero = actualhace que la corriente sobrescriba primero y es equivalente a
primer % valor = valor % actual primero % índice = índice % actual primero % siguiente => actual % siguienteargumentos de puntero
Si un argumento real es un puntero, entonces, si el argumento ficticio también es un puntero,
- debe tener el mismo rango,
- Recibe su estatus de asociación del argumento real,
- devuelve su estado de asociación final al argumento real (nota: ¡el objetivo puede no estar definido!),
- puede que no tenga el
INTENTatributo (sería ambiguo), - Requiere un bloque de interfaz.
Si el argumento ficticio no es un puntero, se asocia con el destino del argumento real:
REAL , PUNTERO :: a (:,:) : ASIGNAR ( a ( 80 , 80 )) : LLAMAR sub ( a ) : SUBRUTINA sub ( c ) REAL c (:, :)funciones de puntero
Los resultados de la función también pueden tener el POINTERatributo; esto es útil si el tamaño del resultado depende de los cálculos realizados en la función, como en
USE data_handler REAL x ( 100 ) REAL , POINTER :: y (:) : y => compact ( x )donde el módulo data_handler contiene
FUNCIÓN compact ( x ) REAL , PUNTERO :: compact (:) REAL x (:) ! Un procedimiento para eliminar duplicados del array x ENTERO n : ! Encuentra el número de valores distintos, n ASIGNAR ( compact ( n )) : ! Copia los valores distintos en compact FIN FUNCIÓN compactEl resultado se puede utilizar en una expresión (pero debe estar asociado a un objetivo definido).
Matrices de punteros
Estos no existen como tales: dado
TIPO ( entrada ) :: filas ( n )entonces
filas % siguiente ! ilegalSería un objeto de este tipo, pero con un patrón de almacenamiento irregular. Por esta razón, no están permitidos. Sin embargo, podemos lograr el mismo efecto definiendo un tipo de dato derivado con un puntero como único componente:
TIPO fila REAL , PUNTERO :: r (:) FIN TIPOy luego definiendo matrices de este tipo de datos.
TIPO ( fila ) :: s ( n ), t ( n )donde el almacenamiento para las filas se puede asignar, por ejemplo,
HACER i = 1 , n ASIGNAR ( t ( i )% r ( 1 : i )) ! Asignar fila i de longitud i FIN HACERLa asignación de la matriz es entonces equivalente a las asignaciones de punteros para todos los componentes.s=ts(i)%r=>t(i)%r
Punteros como alias dinámicos
Dado un array
REAL , OBJETIVO :: tabla ( 100 , 100 )que se referencia frecuentemente con subíndices fijos
tabla ( m : n , p : q )Estas referencias pueden ser reemplazadas por
REAL , DIMENSIÓN (:, :), PUNTERO :: ventana : ventana => tabla ( m : n , p : q )Los subíndices de window son . De manera similar, para (como se define ya en ), podemos usar, por ejemplo, para apuntar a todos los componentes u de tar, y subíndicerlo como1:n-m+1,1:q-p+1tar%utaru=>tar%utaru(1,2)
Los subíndices son los mismos que los del alquitrán. (Esto reemplaza aún más de EQUIVALENCE.)
En la asociación de punteros
puntero => expresión_de_matrizLos límites inferiores para pointerse determinan como si lboundse aplicara a array_expression. Por lo tanto, cuando se asigna un puntero a una variable de matriz completa, hereda los límites inferiores de la variable; de lo contrario, los límites inferiores se establecen por defecto en 1.
Fortran 2003 permite especificar límites inferiores arbitrarios en la asociación de punteros, como
ventana ( r :, s :) => tabla ( m : n , p : q )de modo que los límites de windowse conviertan en r:r+n-m,s:s+q-p. Fortran 95 no tiene esta característica; sin embargo, se puede simular utilizando el siguiente truco (basado en las reglas de asociación de punteros para argumentos ficticios de matriz de forma supuesta):
FUNCIÓN remap_bounds2 ( lb1 , lb2 , array ) RESULTADO ( ptr ) ENTERO , INTENCIÓN ( IN ) :: lb1 , lb2 REAL , DIMENSIÓN ( lb1 :, lb2 :), INTENCIÓN ( IN ), DESTINO :: array REAL , DIMENSIÓN (:,:), PUNTERO :: ptr ptr => array FIN DE LA FUNCIÓN : ventana => remap_bounds2 ( r , s , tabla ( m : n , p : q ))El código fuente de un ejemplo extendido del uso de punteros para admitir una estructura de datos se encuentra en pointer.f90..
procedimientos intrínsecos
La mayoría de las funciones intrínsecas ya se han mencionado. Aquí, nos ocuparemos únicamente de su clasificación general y de aquellas que hasta ahora se han omitido. Todos los procedimientos intrínsecos pueden utilizarse con argumentos de palabra clave:
LLAMAR FECHA_Y_HORA ( HORA = t )y muchos tienen argumentos opcionales.
Los procedimientos intrínsecos se agrupan en cuatro categorías:
- elemental - trabajar con escalares o matrices, por ejemplo
ABS(a); - investigación - independiente del valor del argumento (que puede no estar definido), por ejemplo
PRECISION(a); - transformacional: argumento de matriz con resultado de matriz de forma diferente, por ejemplo
RESHAPE(a, b); - subrutinas, por ejemplo
SYSTEM_CLOCK.
Los procedimientos que aún no se han introducido son:
Consulta de bit
Manipulación de bits
Función de transferencia, como en
ENTERO :: i = TRANSFERIR ( 'abcd' , 0 )(sustituye parte de EQUIVALENCIA)
Subrutinas
Transferencia de datos
Entrada/salida formateada
Estos ejemplos ilustran diversas formas de listas de E/S con algunos formatos sencillos (véase más abajo ):
ENTERO :: i REAL , DIMENSIÓN ( 10 ) :: a CARÁCTER ( len = 20 ) :: palabra IMPRIMIR "(i10)" , i IMPRIMIR "(10f10.3)" , a IMPRIMIR "(3f10.3)" , a ( 1 ), a ( 2 ), a ( 3 ) IMPRIMIR "(a10)" , palabra ( 5 : 14 ) IMPRIMIR "(3f10.3)" , a ( 1 ) * a ( 2 ) + i , RAÍZ CUADRADA ( a ( 3 : 4 ))Las variables, pero no las expresiones, son igualmente válidas en las instrucciones de entrada que utilizan la READinstrucción:
LEER "(i10)" , iSi una matriz aparece como un elemento, se trata como si los elementos se especificaran en el orden en que se encuentran los elementos de la matriz.
Todos los punteros de una lista de E/S deben estar asociados a un destino, y la transferencia se realiza entre el archivo y los destinos.
Un elemento de tipo derivado se trata como si los componentes se especificaran en el mismo orden que en la declaración de tipo, por lo que
lee "(8f10.5)" , p , t ! tipos punto y triángulotiene el mismo efecto que la afirmación
LEER "(8f10.5)" , p % x , p % y , t % a % x , t % a % y , t % b % x , & t % b % y , t % c % x , t % c % yUn objeto en una lista de E/S no puede ser de un tipo derivado que tenga un componente de puntero en ningún nivel de selección de componentes.
Tenga en cuenta que una matriz de tamaño cero puede aparecer como un elemento en una lista de E/S. Dicho elemento corresponde a la ausencia de transferencia de datos real.
La especificación del formato también puede darse en forma de expresión de caracteres:
CARÁCTER ( len =* ), parámetro :: formulario = "(f10.3)" : IMPRIMIR formulario , qo como un asterisco : este es un tipo de E/S conocido como E/S dirigida por lista (ver más abajo ), en el que el formato lo define el sistema informático:
IMPRIMIR * , "Raíz cuadrada de q = " , SQRT ( q )Las operaciones de entrada/salida se utilizan para transferir datos entre el almacenamiento de un programa en ejecución y un medio externo, especificado por un número de unidad . Sin embargo, dos instrucciones de E/S, PRINTy una variante de READ, no hacen referencia a ningún número de unidad: esto se denomina E/S de terminal. De lo contrario, la forma es:
LEER ( UNIDAD = 4 , FMT = "(f10.3)" ) q LEER ( UNIDAD = nunit , FMT = "(f10.3)" ) q LEER ( UNIDAD = 4 * i + j , FMT = "(f10.3)" ) adonde UNIT=es opcional. El valor puede ser cualquier entero no negativo permitido por el sistema para este propósito (pero 0, 5 y 6 suelen indicar el error, el teclado y la terminal, respectivamente).
Un asterisco es una variante , de nuevo desde el teclado:
LEER ( UNIDAD =* , FMT = "(f10.3)" ) qUna lectura con un especificador de unidad permite el manejo de excepciones :
LEER ( UNIDAD = NUNIT , FMT = "(3f10.3)" , IOSTAT = ios ) a , b , c SI ( ios == 0 ) ENTONCES ¡Lectura exitosa: continuar la ejecución! : SINO ¡Condición de error: tomar las medidas apropiadas! LLAMAR error ( ios ) FIN SIExiste un segundo tipo de instrucción de salida formateada, la WRITEinstrucción:
ESCRIBIR ( UNIDAD = nout , FMT = "(10f10.3)" , IOSTAT = ios ) aArchivos internos
Estas funciones permiten que el programa realice la conversión de formato entre diversas representaciones en un área de almacenamiento definida dentro del propio programa.
ENTERO , DIMENSIÓN ( 30 ) :: ival ENTERO :: clave CARÁCTER ( LEN = 30 ) :: buffer CARÁCTER ( LEN = 6 ), DIMENSIÓN ( 3 ), PARÁMETRO :: forma = ( / "(30i1)" , "(15i2)" , "(10i3)" / ) LEER ( UNIDAD = * , FMT = "(a30,i1)" ) buffer , clave LEER ( UNIDAD = buffer , FMT = forma ( clave )) ival ( 1 : 30 / clave )Si un archivo interno es un escalar, tiene un único registro cuya longitud es igual a la del escalar.
Si se trata de una matriz, sus elementos, en el orden en que se encuentran, se tratan como registros sucesivos del archivo y cada uno tiene la longitud de un elemento de la matriz.
Un ejemplo que utiliza una WRITEdeclaración es
ENTERO :: día REAL :: efectivo CARÁCTER ( LEN = 50 ) :: línea : ! escribir en línea ESCRIBIR ( UNIDAD = línea , FMT = "(a, i2, a, f8.2, a)" ) "Ingresos del día " , día , " son " , efectivo , " dólares"que podría escribir
La recaudación del tercer día asciende a 4329,15 dólares.
E/S dirigida por lista
Un ejemplo de lectura sin formato de entrada especificado es
ENTERO :: i REAL :: a COMPLEJO , DIMENSIÓN ( 2 ) :: campo LÓGICO :: bandera CARÁCTER ( LEN = 12 ) :: título CARÁCTER ( LEN = 4 ) :: palabra : LEER * , i , a , campo , bandera , título , palabraSi esto lee el registro de entrada
10 6.4 ( 1.0 , 0.0 ) ( 2.0 , 0.0 ) prueba t /(en el que se utilizan espacios en blanco como separadores), entonces i, a, field, flag, y titleadquirirán los valores 10, 6.4, (1.0,0.0) y (2.0,0.0), .true. y testrespectivamente, mientras que wordpermanece sin cambios.
Se requieren comillas o apóstrofes como delimitadores para una cadena que contiene un espacio en blanco.
E/S sin avance
Esta es una forma de lectura y escritura que no siempre desplaza el archivo a la posición anterior al siguiente registro. Mientras que una instrucción de E/S con avance siempre reposiciona el archivo después del último registro accedido, una instrucción de E/S sin avance no realiza dicho reposicionamiento y, por lo tanto, puede dejar el archivo posicionado dentro de un registro.
CARÁCTER ( LEN = 3 ) :: clave ENTERO :: u , s , ios : LEER ( UNIDAD = u , FMT = "(a3)" , AVANCE = "no" , TAMAÑO = s , IOSTAT = ios ) clave SI ( ios == 0 ) ENTONCES : SINO ! la clave no está en un registro clave ( s + 1 :) = "" : FIN SIUna lectura sin avance podría leer los primeros caracteres de un registro y una lectura normal el resto.
Para escribir un mensaje en la pantalla de un terminal y leer desde la siguiente posición de carácter en la pantalla sin un salto de línea intermedio, podemos escribir
ESCRIBIR ( UNIDAD =* , FMT = "(a)" , AVANZAR = "no" ) "Ingrese el siguiente número primo:" LEER ( UNIDAD =* , FMT = "(i10)" ) número_primoLa E/S sin avance es para archivos externos y no está disponible para la E/S dirigida por lista.
Editar descriptores
Es posible especificar que un descriptor de edición se repita un número determinado de veces, utilizando un contador de repeticiones :10f12.3
El descriptor de edición de barra diagonal (ver más abajo ) puede tener un contador de repeticiones, y este contador también puede aplicarse a un grupo de descriptores de edición, encerrados entre paréntesis, con anidamiento:
IMPRIMIR "(2(2i5,2f8.2))" , i ( 1 ), i ( 2 ), a ( 1 ), a ( 2 ), i ( 3 ), i ( 4 ), a ( 3 ), a ( 4 )Se pueden repetir todas las especificaciones del formato:
IMPRIMIR "(10i8)" , ( / ( i ( j ), j = 1 , 200 ) / )Escribe 10 números enteros, cada uno ocupando 8 posiciones de caracteres, en cada una de las 20 líneas (la repetición de la especificación de formato avanza a la siguiente línea).
descriptores de edición de datos
- Entero:
iW iW.M - Real:
fW.D esW.D esW.DeE - Complejo: pares de descriptores
foesedición de descriptores - Lógico:
lW - Personaje:
a aW - Tipos derivados: se editan mediante la secuencia apropiada de descriptores de edición que corresponden a los tipos intrínsecos de los componentes últimos del tipo derivado.
TIPO , PÚBLICO :: cadena ENTERO :: longitud CARÁCTER ( LEN = 20 ) :: palabra FIN TIPO cadena TIPO ( cadena ) :: texto LEER ( UNIDAD =* , FMT = "(i2, a)" ) texto
Controlar la edición de descriptores
Controlar la edición de descriptores y establecer condiciones :
- El
ssdescriptor de edición (sign suppress) suprime los signos de suma iniciales. Para activar la impresión de signos de suma,spse utiliza el descriptor (sign print). Elsdescriptor de edición devuelve la opción al procesador. - Este descriptor seguirá vigente durante el resto de la especificación del formato, a menos que se cumpla otro de ellos.
Controlar los descriptores de edición para su procesamiento inmediato :
- Tabulación:
tN trN tlNLEER ( UNIDAD =* , FMT = "(t3,i4, tl4,i1, i2)" ) i , j , k
- Nuevos récords:
/ N/LEER "(i5,i3,/,i5,i3,i2)" , i , j , k , l , m
Tenga en cuenta que
separa los dos valores mediante tres registros en blanco.IMPRIMIR "(i5,4/,i5)" , i , j
- Edición con dos puntos:
:finaliza el control de formato si no hay más elementos en una lista de E/S.Detiene los nuevos registros siIMPRIMIR "( i5, :, /, i5, :, /, i5)" , ( / ( l ( i ), i = 1 , n ) / )
nes igual a 1 o 2.
E/S sin formato
Este tipo de E/S solo debe utilizarse en los casos en que los registros sean generados por un programa en un ordenador, para ser leídos posteriormente en el mismo ordenador o en otro ordenador utilizando las mismas representaciones numéricas internas:
ABRIR ( UNIDAD = 4 , ARCHIVO = 'prueba' , FORMATO = 'sin formato' ) LEER ( UNIDAD = 4 ) q ESCRIBIR ( UNIDAD = nout , IOSTAT = ios ) a ! sin fmt=Archivos de acceso directo
Esta forma de E/S también se conoce como acceso aleatorio o E/S indexada. En este caso, todos los registros tienen la misma longitud y cada uno se identifica mediante un número de índice. Es posible escribir, leer o reescribir cualquier registro especificado sin importar su posición.
ENTERO , PARÁMETRO :: nunit = 2 , longitud = 100 REAL , DIMENSIÓN ( longitud ) :: a REAL , DIMENSIÓN ( longitud + 1 : 2 * longitud ) :: b ENTERO :: i , longitud_rec : CONSULTAR ( IOLENGTH = longitud_rec ) a ABRIR ( UNIDAD = nunit , ACCESO = "directo" , RECL = longitud_rec , ESTADO = "scratch" , ACCIÓN = "lectura/escritura" ) : ! Escribir la matriz b en el archivo de acceso directo en el registro 14 ESCRIBIR ( UNIDAD = nunit , REC = 14 ) b : ! ! Leer la matriz de nuevo en la matriz a LEER ( UNIDAD = nunit , REC = 14 ) a : HACER i = 1 , longitud / 2 a ( i ) = i FIN HACER ! ! Reemplazar registro modificado WRITE ( UNIT = nunit , REC = 14 ) aEl archivo debe ser externo y no están disponibles el formato dirigido por lista ni la E/S sin avance.
Operaciones en archivos externos
Una vez más, esto es solo una descripción general.
Declaraciones de posicionamiento de archivos
- La
BACKSPACEdeclaración:RETROCESO ( UNIDAD = u [, IOSTAT = ios ]) ! donde [ ] significa opcional
- La
REWINDdeclaración:REBOBINAR ( UNIDAD = u [, ESTADO DE E/S = ios ])
- La
endfiledeclaración:FIN DEL ARCHIVO ( unidad = u [, iostat = ios ])
La OPENdeclaración
La instrucción se utiliza para conectar un archivo externo a una unidad, crear un archivo que ya está conectado o crear un archivo y conectarlo a una unidad. La sintaxis es
ABRIR ( UNIDAD = u , ESTADO = st , ACCIÓN = act [, olist ])donde olistes una lista de especificadores opcionales. Los especificadores pueden aparecer en cualquier orden.
ABRIR ( UNIDAD = 2 , ESTADO = ios , ARCHIVO = "ciudades" , ESTADO = "nuevo" , ACCESO = "directo" , y ACCIÓN = "lectura/escritura" , RECL = 100 )Otros especificadores son FORMy POSITION.
La CLOSEdeclaración
Esto se utiliza para desconectar un archivo de una unidad.
CERRAR ( UNIDAD = u [, IOSTAT = ios ] [, ESTADO = st ])como en
CERRAR ( UNIDAD = 2 , ESTADO = ios , ESTADO = "eliminar" )La inquiredeclaración
En cualquier momento durante la ejecución de un programa es posible consultar el estado y los atributos de un archivo mediante esta instrucción.
Utilizando una variante de esta afirmación, es posible determinar de manera similar el estado de una unidad, por ejemplo, si existe el número de unidad para ese sistema.
Otra variante permite consultar la longitud de una lista de salida cuando se utiliza para escribir un registro sin formato.
Para consultas por unidad
CONSULTAR ( UNIDAD = u , ilist )o para consultas por archivo
CONSULTAR ( ARCHIVO = fln , ilist )o para consultas por lista de E/S
CONSULTAR ( IOLENGTH = longitud ) listaPor ejemplo
LÓGICO :: ex , op CARÁCTER ( LEN = 11 ) :: nam , acc , seq , frm ENTERO :: irec , nr CONSULTA ( UNIDAD = 2 , EXISTE = ex , ABIERTO = op , NOMBRE = nam , ACCESO = acc , SECUENCIAL = seq , & FORMULARIO = frm , RECL = irec , SIGUIENTE REC = nr )rendimientos
ex . verdadero . op . verdadero . nam ciudades acc DIRECT seq NO de SIN FORMATO irec 100 nr 1(suponiendo que no haya operaciones de lectura o escritura intermedias).
Otros especificadores son IOSTAT, OPENED, NUMBER, NAMED, FORMATTED, POSITION, ACTION, READ, WRITE, READWRITE.
Referencias
- ↑ "ISO/IEC 1539-1:1997" . ISO . Consultado el 25 de febrero de 2025 .
- 1 2 3 "ISO/IEC 1539-1:2023" . ISO . Consultado el 25 de febrero de 2025 .
- 1 2 "Fortranplus | Información sobre Fortran" .
- 1 2 "Características de los lenguajes de programación" , Programación orientada a objetos mediante Fortran 90/95 , Cambridge University Press, 13 de enero de 2003, págs. 56-118 , doi : 10.1017/cbo9780511530111.005 , ISBN 978-0-521-52408-7, consultado el 25 de febrero de 2025
- 1 2 "Conceptos de programación orientada a objetos" , Programación orientada a objetos mediante Fortran 90/95 , Cambridge University Press, 13 de enero de 2003, págs. 36-55 , doi : 10.1017/cbo9780511530111.004 , ISBN 978-0-521-52408-7, consultado el 25 de febrero de 2025
- 1 2 Chapman, Stephen J. (2004). Fortran 90/95 para científicos e ingenieros (2.ª ed.). Boston: McGraw-Hill Higher Education. ISBN 978-0-07-282575-6OCLC 52465017
Bibliografía
- Metcalf, Michael; Reid, John; Cohen, Malcolm (17 de junio de 2004), "¿De dónde viene Fortran?" , Fortran 95/2003 Explained , Oxford University Press, Oxford, pp. 1–8 , doi : 10.1093/oso/9780198526926.003.0001 , ISBN 978-0-19-852692-6, consultado el 25 de febrero de 2025
- Introducción a Fortran moderno , Estadística e Informática, Nueva York: Springer-Verlag, 2005, págs.13-53,doi:10.1007/0-387-28123-1_2,ISBN 0-387-23817-4, consultado el 25 de febrero de 2025
- Gehrke, Wilhelm (1996). Guía de idiomas Fortran 95 . doi : 10.1007/978-1-4471-1025-5 . ISBN 978-3-540-76062-7.
- Chivers, Ian; Sleightholme, Jane (2000), "Fortran 2000 y varios dialectos de Fortran" , Introducing Fortran 95 , Londres: Springer London, pp. 377–388 , doi : 10.1007/978-1-4471-0403-2_29 , ISBN 978-1-85233-276-1, consultado el 25 de febrero de 2025
- Counihan, Martin (2006). Fortran 95 (2.ª ed.). CRC Press. ISBN 9780203978467.
- Ramaraman, V. (1997). Programación informática en FORTRAN 90 y 95. PHI Learning Pvt. Ltd. ISBN 9788120311817.
- Metcalf, Michael; Reid, John; Cohen, Malcolm; Bader, Reinhold (2024). Modern Fortran Explained: Incorporating Fortran 2023 (6.ª ed.). Oxford University Press. ISBN 9780198876595.
- Joshi, Yogendra Prasad. Introducción a Fortran 90/95: Sintaxis y programación . Allied Publishers. ISBN 9788177644746.
- Fortran