Esta es una descripción general de las funciones de idioma de Fortran 95 . Se incluyen las características adicionales de TR-15581: Instalaciones de tipo 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 . El estándar actual es Fortran 2018; muchas de sus nuevas características aún se están implementando en compiladores. [1] Metcalf, Reid y Cohen describen las características adicionales de Fortran 2003, Fortran 2008 y Fortran 2018. [2]
Elementos del lenguaje
Fortran no distingue entre mayúsculas y minúsculas . En este artículo se adopta la convención de escribir 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 en 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 del contexto de un carácter)
- los números 0 ... 9
- el subrayado _
- los personajes especiales
= : + blank - * / ( ) [ ] , . $ ' ! " % & ; < > ?
Los tokens que tienen un significado sintáctico para el compilador se crean a partir de esos componentes. Hay seis clases de tokens:
Etiqueta | 123 |
---|---|
Constante | 123.456789_long |
Palabra clave | ALLOCATABLE |
Operador | .add. |
Nombre | solve_equation (hasta 31 caracteres, incluido _) |
Separador | / ( ) (/ /) [ ] , = => : :: ; % |
A partir de los tokens, se construyen declaraciones . Estos se pueden codificar utilizando el nuevo formulario de fuente libre que no requiere posicionamiento en una estructura de columna rígida:
FUNCIÓN string_concat ( s1 , s2 ) ! Este es un comentario TYPE ( string ), INTENT ( IN ) :: s1 , s2 TYPE ( string ) 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 FUNCIÓN FINAL string_concat
Tenga en cuenta 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 importantes. Donde una constante de carácter o token se divide en dos líneas:
... inicio_de & & _ nombre ... 'una cadena & & muy larga '
&
También se requiere un adelanto en la línea continua.
La conversión automática del formato fuente para programas existentes se puede realizar mediante convert.f90 .
Sus opciones son
- manipulación significativa en blanco;
- sangría;
- CONTINUE reemplazado por END DO;
- nombre agregado a la instrucción END del subprograma; y
- Sintaxis INTEGER * 2 etc. convertida.
Tipos de datos intrínsecos
Fortran tiene cinco tipos de datos intrínsecos : INTEGER
, REAL
, COMPLEX
, LOGICAL
y CHARACTER
. Cada uno de esos tipos se puede caracterizar adicionalmente por un tipo . Kind, 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, los detalles de la representación de almacenamiento. Por 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 denota 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 utiliza si no se especifica explícitamente ningún tipo. Para cada tipo intrínseco, existe una forma correspondiente de constante literal . Los tipos numéricos INTEGER
y REAL
solo se pueden firmar (no existe el 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 + 10
El tipo se puede definir como una constante con nombre. Si el rango deseado es ± 10 tipo , la sintaxis portátil para definir el tipo apropiado two_bytes
es
INTEGER , PARAMETER :: two_bytes = SELECTED_INT_KIND ( 4 )
que permite la posterior definición de constantes de la forma
- 1234_dos_bytes + 1_dos_bytes
Aquí two_bytes
está el parámetro de tipo kind; también puede ser una constante literal entera predeterminada explícita, como
- 1234_2
pero tal uso no es portátil.
La función KIND proporciona el valor de un parámetro de tipo kind:
TIPO ( 1 ) TIPO ( 1_dos_bytes )
y la RANGE
función proporciona el rango decimal real (por lo que el usuario debe realizar la asignación real a bytes):
RANGO ( 1_dos_bytes )
Además, en DATA
declaraciones (de inicialización) , se pueden usar constantes binarias (B), octales (O) y hexadecimales (Z) (a menudo denominadas informalmente "constantes BOZ"):
B '01010101' O '01234567' Z '10fa'
VERDADERO
Hay al menos dos tipos reales: el predeterminado y uno con mayor precisión (esto reemplaza DOUBLE PRECISION
). SELECTED_REAL_KIND
las funciones devuelven el número de tipo para el rango y la precisión deseados; para al menos 9 dígitos decimales de precisión y un rango de 10 −99 a 10 99 , se puede especificar como:
INTEGER , PARAMETER :: long = SELECTED_REAL_KIND ( 9 , 99 )
y literales posteriormente especificados como
1.7_largo
Además, existen las funciones intrínsecas
TIPO ( 1.7_long ) PRECISIÓN ( 1.7_long ) ALCANCE ( 1.7_long )
que dan a su vez el valor del tipo de tipo, la precisión real (aquí al menos 9) y el rango real (aquí al menos 99).
COMPLEJO
COMPLEX
El tipo de datos se compone de dos componentes reales o enteros:
( 1 , 3,7_ de largo )
LÓGICO
Solo hay dos valores básicos de constantes lógicas: .TRUE.
y .FALSE.
. Aquí, también puede haber diferentes tipos. Los lógicos no tienen sus propias funciones de consulta de tipo, pero usan los tipos especificados para INTEGER
s; el tipo predeterminado LOGICAL
es el mismo que el de INTEGER.
. FALSO . . verdad . _ un_byte
y la KIND
función opera como se esperaba:
AMABLE (. VERDADERO .)
PERSONAJE
Las formas de las constantes literales para CHARACTER
el tipo de datos son
'Una cadena' "Otra" 'Una "cita"' '' '' '' '
(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 de tipo viene dado por la KIND
funció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 solo para proporcionar tipo). Estas funciones son importantes para el software numérico portátil:
DIGITS(X) | Número de dígitos significativos |
EPSILON(X) | Casi insignificante en comparación con uno (real) |
HUGE(X) | Mayor número |
MAXEXPONENT(X) | Exponente máximo del modelo (real) |
MINEXPONENT(X) | Exponente mínimo del modelo (real) |
PRECISION(X) | Precisión decimal (real, compleja) |
RADIX(X) | Base del modelo |
RANGE(X) | Rango de exponente decimal |
TINY(X) | Número positivo más pequeño (real) |
Variables escalares
Las variables escalares correspondientes a los cinco tipos intrínsecos se especifican de la siguiente manera:
INTEGER ( KIND = 2 ) :: i REAL ( KIND = long ) :: a COMPLEX :: current LOGICAL :: Pravda CHARACTER ( LEN = 20 ) :: word CHARACTER ( LEN = 2 , KIND = Kanji ) :: kanji_word
donde el KIND
parámetro opcional especifica un tipo no predeterminado, y la ::
notación delimita el tipo y los atributos de los nombres de variable y sus valores iniciales opcionales, lo que permite que la especificación e inicialización completa de la variable se escriba en una declaración (en estándares, atributos y los inicializadores tuvieron que ser declarados en varias declaraciones). Si bien no se requiere en los ejemplos anteriores (ya que no hay atributos adicionales ni inicialización), 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 CHARACTER
sy especifica la longitud de la cadena (reemplazando la *len
forma anterior ). Los especificadores explícitos KIND=
y LEN=
son opcionales:
CARÁCTER ( 2 , Kanji ) :: kanji_word
funciona igual de bien.
Hay algunas otras características interesantes de los personajes. Al igual que una subcadena como en
CARÁCTER ( 80 ) :: línea ... = línea ( i : i ) ! subcadena
anteriormente era posible, por lo que ahora es la subcadena
'0123456789' ( i : i )
Además, se permiten cadenas de longitud cero:
línea ( i : i - 1 ) ! cadena de longitud cero
Por último, hay un conjunto de funciones de carácter intrínsecas, siendo ejemplos
ACHAR | IACHAR (para conjunto ASCII) |
ADJUSTL | ADJUSTR |
LEN_TRIM | INDEX(s1, s2, BACK=.TRUE.) |
REPEAT | SCAN (para uno de un conjunto) |
TRIM | VERIFY (para todo un conjunto) |
Tipos de datos derivados
Para los tipos de datos derivados, primero se debe definir la forma del tipo:
TIPO persona CARÁCTER ( 10 ) nombre Edad REAL TIPO FINAL persona
y luego, se pueden definir variables de ese tipo:
TIPO ( persona ) tú , yo
Para seleccionar componentes de un tipo derivado, %
se usa el calificador:
tu % edad
Las constantes literales de tipos derivados tienen la forma TypeName(1stComponentLiteral, 2ndComponentLiteral, ...)
:
usted = persona ( 'Smith' , 2 3.5 )
que se conoce como constructor de estructuras . Las definiciones pueden referirse a un tipo definido previamente:
TIPO punto REAL x , y FIN TIPO punto TIPO triángulo TIPO ( punto ) a , b , c FIN TIPO triángulo
y para una variable de tipo triángulo, como en
TIPO ( triángulo ) t
point
se accede a cada componente de tipo como
t % a t % b t % c
que, a su vez, tienen componentes finales de tipo real:
t % un % x t % un % y t % b % x etc .
(Tenga en cuenta que %
se eligió el calificador en lugar de dot ( .
) debido a la posible ambigüedad con la notación del operador, como .OR.
).
Escritura implícita y explícita
A menos que se especifique lo contrario, todas las variables que comienzan con las letras I, J, K, L, M y N son predeterminadas INTEGER
y todas las demás son predeterminadas REAL
; otros tipos de datos deben declararse explícitamente. Esto se conoce como mecanografía implícita y es una herencia de los primeros días de FORTRAN. Esos valores predeterminados se pueden anular mediante IMPLICIT TypeName (CharacterRange)
declaraciones, como:
COMPLEJO IMPLÍCITO ( Z ) CARÁCTER IMPLÍCITO ( A - B ) REAL IMPLÍCITO ( C - H , N - Y )
Sin embargo, es una buena práctica escribir explícitamente todas las variables, y esto se puede forzar insertando la instrucción IMPLICIT NONE
al comienzo de cada unidad del programa.
Matrices
Las matrices se consideran variables por derecho propio. Cada matriz se caracteriza por su tipo , rango y forma (que define la extensión de cada dimensión). Los límites de cada dimensión son por defecto 1 y tamaño , pero los límites arbitrarios se pueden especificar explícitamente. DIMENSION
la palabra clave es opcional y se considera un atributo; si se omite, la forma de la matriz debe especificarse después del nombre de la variable de matriz. Por ejemplo,
REAL :: a ( 10 ) INTEGER , DIMENSION ( 0 : 100 , - 50 : 50 ) :: map
declara dos matrices, rank-1 y rank-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 de entero escalar.
Las secciones son partes de las variables de matriz y son matrices en sí mismas:
a ( i : j ) ! clasifica un mapa ( i : j , k : l : m ) ! rango dos a ( mapa ( i , k : l )) ! vector subíndice a ( 3 : 2 ) ! longitud cero
Las matrices completas y las secciones de matriz son objetos con valores de matriz. Las constantes con valores de matriz (constructores) están disponibles, incluidas en (/ ... /)
:
( / 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 ) / )
haciendo uso de una notación de bucle DO implícita. Fortran 2003 permite el uso de corchetes: [1, 2, 3, 4]
y en [([1,2,3], i=1,4)]
lugar de los dos primeros ejemplos anteriores, y muchos compiladores lo admiten ahora. Por supuesto, un tipo de datos derivado puede contener componentes de matriz:
TIPO triplete REAL , DIMENSIÓN ( 3 ) :: vértice TIPO FINAL triplete TIPO ( triplete ), DIMENSIÓN ( 4 ) :: t
así que eso
t(2)
es un escalar (una estructura)t(2)%vertex
es un componente de matriz de un escalar
Inicialización de datos
A las variables se les pueden dar valores iniciales como se especifica en una declaración de especificación:
REAL , DIMENSIÓN ( 3 ) :: a = ( / 0.1 , 0.2 , 0.3 / )
y se puede dar un valor inicial predeterminado al componente de un tipo de datos derivado:
TIPO triplete REAL , DIMENSIÓN ( 3 ) :: vértice = 0.0 FIN TIPO triplete
Cuando 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 , DIMENSION ( 3 ), SAVE :: point = ( / 0.0 , 1.0 , - 1.0 / )
para variables locales dentro de una subrutina o función. El atributo SAVE hace que las variables locales retengan su valor después de una llamada a un procedimiento y luego inicialicen la variable con el valor guardado al regresar al procedimiento.
Atributo PARAMETER
Una constante nombrada se puede especificar directamente agregando el PARAMETER
atributo y los valores constantes 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
La DATA
declaración se puede utilizar para escalares y también para matrices y variables de tipo derivado. También es la única forma de inicializar solo partes de dichos objetos, así como de inicializar a valores binarios, octales o hexadecimales:
TIPO ( triplete ) :: t1 , t2 DATA t1 / triplete ( ( / 0. , 1. , 2. / ) ) / , t2 % vértice ( 1 ) / 12 3. / matriz DATA ( 1 : 64 ) / 64 * 0 / DATOS i , j , k / B '01010101' , O '77' , Z 'ff' /
Expresiones de inicialización
Los valores usados en las declaraciones DATA
y 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 transformacionales REPEAT, SELECTED_INT_KIND, TRIM, SELECTED_REAL_KIND, RESHAPE
y TRANSFER
(ver Procedimientos intrínsecos ):
INTEGER , PARAMETER :: long = SELECTED_REAL_KIND ( 12 ), & array ( 3 ) = ( / 1 , 2 , 3 / )
Expresiones de especificación
Es posible especificar detalles de variables usando cualquier expresión entera, escalar, no constante que también puede incluir referencias a funciones de consulta:
SUBRUTINA s ( b , m , c ) USE mod ! contiene un REAL , DIMENSION (:, :) :: b REAL , DIMENSION ( UBOUND ( b , 1 ) + 5 ) :: x INTEGER :: m CHARACTER ( LEN = * ) :: c CHARACTER ( LEN = m + LEN ( c )) :: cc REAL ( TIPO_REAL_ SELECCIONADO ( 2 * PRECISIÓN ( a ))) :: z
Expresiones y asignaciones
Numérico escalar
Los operadores aritméticos habituales están disponibles +, -, *, /, **
(aquí se indican en orden de precedencia creciente).
Los paréntesis se utilizan para indicar el orden de evaluación cuando sea necesario:
a * b + c ! * primero a * ( b + c ) ! + primero
Las reglas para asignaciones y expresiones numéricas escalares se adaptan a los tipos no predeterminados. Por lo tanto, la expresión numérica de modo mixto y las reglas de asignación incorporan diferentes parámetros de tipo de tipo de la manera esperada:
real2 = entero0 + real1
se convierte integer0
en un valor real del mismo tipo que real1
; el resultado es del mismo tipo y se convierte en el tipo de real2
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 el resultado enteroANINT
: redondea al entero más cercano, devuelve el resultado realINT
: truncar (redondear hacia cero), devolver resultado enteroAINT
: truncar (redondear hacia cero), devolver el resultado realCEILING
: valor integral más pequeño no menor que argumento (redondeo hacia arriba) (Fortran-90)FLOOR
: mayor valor integral no mayor que argumento (redondeo hacia abajo) (Fortran-90)
Operaciones relacionales escalares
Para las operaciones relacionales escalares de tipos numéricos, hay un conjunto de operadores integrados:
<<= == / =>> =.LT. .LE. .EQ. .NORDESTE. .GT. .GE.
(los formularios anteriores son nuevos para Fortran-90, y los formularios equivalentes más antiguos se dan debajo de ellos). Expresiones de ejemplo:
a < b . Y . i / = j ! para variables numéricas flag = a == b ! para banderas de variables lógicas
Caracteres escalares
En el caso de caracteres escalares y dadoCHARACTER(8) result
es legal escribir
resultado ( 3 : 5 ) = resultado ( 1 : 3 ) ! superposición resultado permitido ( 3 : 3 ) = resultado ( 3 : 2 ) ! sin asignación de cadena nula
La concatenación la realiza 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 entre sí o con tipos intrínsecos. El significado de los operadores existentes o especificados por el usuario se puede (re) definir aunque:
TIPO string80 INTEGER longitud CARÁCTER ( 80 ) valor FIN TIPO string80 CARÁCTER :: char1 , char2 , char3 TIPO ( string80 ) :: str1 , str2 , str3
podemos escribir
str3 = str1 // str2 ! debe definir la operación str3 = str1 . concat . str2 ! debe definir la operación char3 = char2 // char3 ! operador intrínseco solo str3 = char1 ! debe definir la asignación
Note la " sobrecarga de uso" del símbolo intrínseca //
y el operador llamado, .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 binario. En
vector3 = matriz * vector1 + vector2 vector3 = ( matriz . veces . vector1 ) + vector2
las dos expresiones son equivalentes solo si se agregan los paréntesis apropiados como se muestra. En cada caso se deben definir, en un módulo , procedimientos que definan el operador y la asignación, y la asociación operador-procedimiento correspondiente, de la siguiente manera:
OPERADOR DE INTERFAZ ( // ) ! Sobrecarga el operador // como invocando el procedimiento string_concat MODULE PROCEDURE string_concat END INTERFACE
La función de concatenación de cadenas es una versión más elaborada de la que ya se muestra en Conceptos básicos . Tenga en cuenta que para manejar la condición de error que surge cuando las dos cadenas juntas exceden el límite preestablecido de 80 caracteres, sería más seguro usar una subrutina para realizar la concatenación (en este caso, la sobrecarga del operador no sería aplicable).
MÓDULO STRING_TYPE IMPLÍCITO NINGUNO TIPO string80 INTEGER longitud CARÁCTER ( LEN = 80 ) :: string_data FIN TIPO string80 INTERFACE ASIGNACIÓN ( = ) PROCEDIMIENTO DE MÓDULO c_to_s_assign , s_to_c_assign FIN INTERFACE INTERFACE OPERADOR ( // ) MÓDULO PROCEDIMIENTO string_concat interfaz de extremo CONTIENE SUBRUTINA c_to_s_assign ( s , c ) TIPO ( string80 ), INTENT ( OUT ) :: s CARÁCTER ( LEN = * ), INTENT ( IN ) :: c s % string_data = c s % longitud = LEN ( c ) FIN SUBRUTINA c_to_s_assign SUBRUTINA s_to_c_assign ( c , s ) TIPO ( string80 ), INTENT ( IN ) :: s CARÁCTER ( LEN = * ), INTENT ( OUT ) :: c c = s % string_data ( 1 : s % longitud ) FIN SUBRUTINA s_to_c_assign TIPO ( string80 ) FUNCIÓN string_concat ( s1 , s2 ) TIPO ( cadena80 ), INTENCIÓN ( ENTRADA ) :: s1 , s2 TIPO ( cadena80 ) :: s INTEGER :: n1 , n2 CARÁCTER ( 160 ) :: ctot n1 = LEN_TRIM ( s1 % cadena_datos ) n2 = LEN_TRIM ( s2 % string_data ) IF ( n1 + n2 <= 80 ) entonces s % string_data = s1 % string_data ( 1 : n1 ) // s2 % string_data ( 1 : n2 ) ELSE ! Esta es una condición de error que debe ser manejado - por ahora sólo truncado CTOT = s1 % string_data ( 1 : n1 ) // s2 % string_data ( 1 : n2 ) s % string_data = CTOT ( 1 : 80 ) END IF s % longitud = LEN_TRIM ( s % string_data ) string_concat = s END FUNCTION string_concat END MODULE string_type PROGRAMA main USE string_type TYPE ( string80 ) :: s1 , s2 , s3 CALL c_to_s_assign ( s1 , 'Mi nombre es' ) CALL c_to_s_assign ( s2 , 'Linus Torvalds' ) s3 = s1 // s2 WRITE ( * , * ) 'Resultado : ' , s3 % string_data WRITE ( * , * ) ' Longitud: ' , s3 % de longitud FIN DEL PROGRAMA
Los operadores definidos como estos son necesarios para las expresiones que también están permitidas en los constructores de estructura (consulte Tipos de datos derivados ):
str1 = cadena ( 2 , char1 // char2 ) ! constructor de estructura
Matrices
Entonces, en el caso de las matrices, siempre que tengan la misma forma (conformables), las operaciones y asignaciones se amplían de manera obvia, elemento por elemento. Por ejemplo, dadas declaraciones de
REAL , DIMENSION ( 10 , 20 ) :: a , b , c REAL , DIMENSION ( 5 ) :: v , w Bandera LÓGICA ( 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 toda la matriz al valor escalar w = 5 / v + a ( 1 : 5 , 5 ) ! división de matriz y adición a la sección flag = a == b ! array toda prueba relacional y asignación c ( 1 : 8 , 5 : 10 ) = una ( 2 : 9 , 5 : 10 ) + b ( 1 : 8 , 15 : 20 ) ! suma y asignación de secciones de matriz v ( 2 : 5 ) = v ( 1 : 4 ) ! asignación de sección superpuesta
El orden de evaluación de la expresión no se especifica para permitir la optimización en máquinas paralelas y vectoriales. Por supuesto, se debe definir cualquier operador para matrices de tipo derivado.
Algunas funciones intrínsecas reales que son útiles para cálculos numéricos son
MÓDULO DE PISO DE TECHO ( también entero ) FRACCIÓN EXPONENTE MÁS CERCANA ESPACIO RRS ESCALA SET_EXPONENT
Estos son valores de matriz para argumentos de matriz (elemental), como todas las funciones de FORTRAN 77 (excepto LEN):
INT REAL CMPLX AINT ANINT NINT ABS MOD SIGN DIM MAX MINSQRT EXP LOG LOG10 SIN COS TAN ASIN ACOS ATAN ATAN2 SINH COSH TANHAIMAG CONJGÍNDICE DE CARACTERÍSTICAS LGE LGT LLE LLT ICHAR
(los últimos siete son para personajes).
Declaraciones de control
Ramificación y condiciones
La GO TO
etiqueta simple existe, pero generalmente se evita; en la mayoría de los casos, una construcción de ramificación más específica logrará la misma lógica con más claridad.
La prueba condicional simple es la IF
declaración:IF (a > b) x = y
Una IF
construcción en toda regla se ilustra por
SI ( i < 0 ) ENTONCES SI ( j < 0 ) ENTONCES x = 0. ELSE z = 0. FIN SI ELSE SI ( k < 0 ) ENTONCES z = 1. ELSE x = 1. FIN SI
Construcción CASE
La CASE
construcción es un reemplazo de la calculada GOTO
, pero está mejor estructurada y no requiere el uso de etiquetas de declaración:
SELECCIONAR CASO ( número ) ! número de tipo entero CASE (: - 1 ) ! todos los valores por debajo de 0 n_sign = - 1 CASE ( 0 ) ! solo 0 n_sign = 0 CASE ( 1 :) ! todos los valores por encima de 0 n_sign = 1 END SELECT
Cada CASE
lista de selectores puede contener una lista y / o rango de enteros, caracteres o constantes lógicas, cuyos valores no pueden superponerse dentro o entre selectores:
CASO ( 1 , 2 , 7 , 10 : 17 , 23 )
Un valor predeterminado está disponible:
CASO POR DEFECTO
Solo hay una evaluación y solo una coincidencia.
CONSTRUIR
Una forma simplificada pero suficiente del DO
constructo se ilustra mediante
externo : DO interno : DO i = j , k , l ! de j a k en pasos de l (l es opcional) : SI (...) CICLO : SI (...) SALIR externo : FIN DO interno FIN DO externo
donde notamos que los bucles se pueden nombrar opcionalmente para que cualquier instrucción EXIT o CYCLE pueda especificar a qué bucle se refiere.
Muchos, pero no todos, los bucles simples pueden reemplazarse por expresiones y asignaciones de matriz, o por nuevas funciones intrínsecas. Por ejemplo
tot = 0. DO i = m , n tot = tot + a ( i ) END DO
se vuelve simple tot = SUM( a(m:n) )
Unidades y procedimientos del programa
Definiciones
Para discutir este tema necesitamos algunas definiciones. En términos lógicos, un programa ejecutable consta de un programa principal y cero o más subprogramas (o procedimientos ); estos hacen algo. Los subprogramas son funciones o subrutinas , que son subrutinas externas, internas o de módulo . (Las subrutinas externas son lo que sabíamos de FORTRAN 77).
Sin embargo, desde un punto de vista organizativo, un programa completo consta de unidades de programa . Estos son programas principales, subprogramas externos o módulos y se pueden compilar por separado.
Un ejemplo de un programa principal (y completo) es
PROGRAMA prueba IMPRESIÓN * , '¡Hola mundo!' Prueba FINALIZAR PROGRAMA
Un ejemplo de un programa principal y un subprograma externo, que forman un programa ejecutable, es
PROGRAMA prueba LLAMADA print_message poner fin al programa de pruebas SUBRUTINA print_message IMPRESIÓN * , '¡Hola mundo!' END SUBROUTINE print_message
La forma de una función es
Nombre de la FUNCIÓN ( arg1 , arg2 ) ! cero o más argumentos : nombre = ... : nombre de la FUNCIÓN FINAL
La forma de referencia de una función es x = name(a, b)
Procedimientos internos
Un subprograma interno está contenido en otro (a un máximo de un nivel de anidamiento) y proporciona un reemplazo para la función de instrucción:
SUBROUTINA exterior REAL x , y : CONTIENE SUBROUTINA interior REAL y y = x + 1 .: FIN SUBROUTINA interior ! SUBROUTINA obligatoria FINAL SUBROUTINA exterior
Decimos que outer
es el anfitrión de inner
, y que inner
obtiene acceso a las entidades outer
por asociación de anfitrión (por ejemplo, a x
), mientras que y
es una variable local a inner
.
El alcance de una entidad nombrada es una unidad de alcance , aquí outer
menos inner
, y inner
.
Los nombres de las unidades del programa y los procedimientos externos son globales , y los nombres de las variables de DO implícito tienen el alcance de la declaración que los contiene.
Módulos
Los módulos se utilizan para empaquetar
- datos globales (reemplaza a los DATOS COMUNES y EN BLOQUE de Fortran 77);
- definiciones de tipo (en sí mismas una unidad de alcance);
- subprogramas (que entre otras cosas reemplaza el uso de ENTRY de Fortran 77);
- bloques de interfaz (otra unidad de alcance, consulte Bloques de interfaz );
- grupos de listas de nombres (ver 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 funciones es
MODULE intervalo_aritmético TIPO intervalo REAL inferior , superior FIN TIPO intervalo INTERFAZ OPERADOR ( + ) MÓDULO PROCEDIMIENTO add_intervals INTERFAZ FINAL : CONTAINS FUNCTION add_intervals ( a , b ) TYPE ( intervalo ), INTENT ( IN ) :: a , b TYPE ( intervalo ) add_intervals add_intervals % inferior = a % inferior + b % inferior add_intervals % superior = a % superior + b % superior END FUNCTION add_intervals ! FUNCIÓN obligatoria : END MODULE interval_arithmetic
y la simple declaración
USE intervalo_aritmético
proporciona asociación de uso a todas las entidades del módulo. Los subprogramas de módulo pueden, a su vez, contener subprogramas internos.
Controlar la accesibilidad
Los atributos PUBLIC
y PRIVATE
se utilizan en las especificaciones de los módulos para limitar el alcance de las entidades. La forma de atributo es
REAL , PUBLICO :: x , y , z ! predeterminado INTEGER , PRIVATE :: u , v , w
y la forma de declaración es
PÚBLICO :: x , y , z , OPERADOR (. Add .) PRIVADO :: u , v , w , ASIGNACIÓN ( = ), OPERADOR ( * )
El formulario de declaración debe usarse para limitar el acceso a los operadores, y también se puede usar para cambiar el valor predeterminado general:
PRIVADO ! establece por defecto para el módulo PUBLIC :: only_this
Para los tipos derivados existen tres posibilidades: el tipo y sus componentes son todos PÚBLICOS, el tipo es PÚBLICO y sus componentes PRIVADOS (el tipo solo es visible y se pueden cambiar sus detalles fácilmente), o todo es PRIVADO (para uso interno solo en el módulo):
MÓDULO mío PRIVADA TIPO , PÚBLICA :: lista de REAL X , Y TIPO ( lista ), PUNTERO :: próxima FIN TIPO lista TIPO ( lista ) :: árbol : MÓDULO DE FIN mía
El USE
propósito de la declaración es obtener acceso a las entidades en un módulo. Tiene opciones para resolver conflictos de nombres si un nombre importado es el mismo que uno local:
USE el mío , local_list => lista
o para restringir las entidades utilizadas a un conjunto específico:
USE el mío , SOLAMENTE : lista
Estos pueden combinarse:
USE el mío , SOLAMENTE : local_list => list
Argumentos
Podemos especificar la intención de los argumentos ficticios:
SUBRUTINA de reproducción aleatoria ( Ncards , tarjetas ) INTEGER , INTENCIÓN ( EN ) :: Ncards INTEGER , INTENCIÓN ( OUT ), DIMENSION ( Ncards ) :: tarjetas
Además, INOUT es posible: aquí 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 , convexa , xstart ) VERDADERO , OPCIONAL , DIMENSIÓN :: superior , inferior : SI ( ACTUAL ( bajar )) ENTONCES ! prueba de presencia de argumento real :
nos permite llamar mincon
por
LLAMAR mincon ( n , f , x , upper )
Los argumentos pueden ser palabras clave en lugar de posicionales (que vienen primero):
LLAMADA mincon ( n , f , x , igualdades = 0 , xstart = x0 )
Los argumentos opcionales y de palabras clave se manejan 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 a través de una interfaz que es "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. Es una copia del encabezado, especificaciones y declaración FIN del procedimiento en cuestión, ya sea colocada en un módulo o insertada directamente:
FUNCIÓN REAL mínimo ( a , b , func ) ! devuelve el valor mínimo de la función func (x) ! en el intervalo (a, b) REAL , INTENCIÓN ( in ) :: a , b INTERFAZ REAL FUNCIÓN FUNC ( x ) REAL , INTENCIÓN ( IN ) :: x FIN FUNCIÓN FUNC FIN INTERFAZ REAL f , x : f = func ( x ) ! invocación de la función de usuario. : FUNCIÓN FINAL mínimo
Una interfaz explícita es obligatoria para
- argumentos opcionales y de palabras clave;
- Argumentos POINTER y TARGET (ver Punteros );
- Resultado de la función PUNTERO;
- Argumentos de matriz de nuevo estilo y funciones de matriz ( manejo de matrices ).
Permite verificaciones completas en tiempo de compilación entre argumentos reales y ficticios.
En general, la mejor manera de garantizar que una interfaz de 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 END FUNCTION dgamma ( X ) ! nombre específico REAL ( SELECTED_REAL_KIND ( 12 )) dgamma , x END END INTERFACE
donde un conjunto dado de nombres específicos correspondientes a un nombre genérico debe ser todos de funciones o todas de subrutinas. Si esta interfaz está dentro de un módulo, entonces es simplemente
INTERFAZ gamma PROCEDIMIENTO DEL MÓDULO sgamma , dgamma INTERFAZ FINAL
Podemos usar nombres existentes, por ejemplo, SIN, y el compilador clasifica la asociación correcta.
Ya hemos visto el uso de bloques de interfaz para operadores definidos y asignación (ver Módulos ).
Recursividad
La recursividad indirecta es útil para la integración multidimensional. Para
volumen = integrar ( fy , ybounds )
Podríamos tener
FUNCIÓN RECURSIVA integrar ( f , límites ) ! Integra f (x) desde los límites (1) a los límites (2) REAL integrar INTERFAZ FUNCIÓN f ( x ) REAL f , x FIN DE FUNCIÓN f INTERFAZ FINAL REAL , DIMENSIÓN ( 2 ), INTENTO ( IN ) :: límites : FIN DE FUNCIÓN integrar
e integrar f (x, y) sobre un rectángulo:
FUNCIÓN fy ( y ) USE func ! el módulo func contiene la función f REAL fy , y yval = y fy = integration ( f , xbounds ) END
La recursividad directa es cuando un procedimiento se llama a sí mismo, como en
FUNCIÓN RECURSIVA factorial ( n ) RESULTADO ( res ) INTEGER res , n IF ( n . EQ . 0 ) THEN res = 1 ELSE res = n * factorial ( n - 1 ) END IF END
Aquí, observamos la RESULT
cláusula y la prueba de terminación.
Procedimientos puros
Esta es una característica de 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 PURE
palabra clave a la declaración SUBROUTINE
o FUNCTION
, una afirmación de que el procedimiento (expresado simplemente):
- no altera ninguna variable global,
- no realiza E / S,
- no tiene variables guardadas (variables con el
SAVE
atributo que retiene valores entre invocaciones), y - para 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 está incluido en Fortran por dos razones principales:
- la conveniencia de notación que proporciona, acercando el código a la forma matemática subyacente;
- para las oportunidades de optimización adicionales que brinda a los compiladores (¡aunque también hay muchas oportunidades para degradar la optimización!).
Al mismo tiempo, se han agregado importantes extensiones de la funcionalidad en esta área. Ya nos hemos encontrado con arreglos completos arriba de #Arrays 1 y aquí #Arrays 2 - ahora desarrollamos el tema.
Matrices de tamaño cero
Fortran maneja una matriz de tamaño cero como un objeto legítimo, sin codificación especial por parte del programador. Así, en
HACER yo = 1 , norte x ( yo ) = segundo ( yo ) / a ( yo , yo ) segundo ( yo + 1 : norte ) = segundo ( yo + 1 : norte ) - una ( yo + 1 : norte , yo ) * x ( i ) FIN HACER
no se requiere un 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 conforme con una de forma (0,3), mientras que es una declaración válida de "no hacer nada".x(1:0) = 3
Matrices de formas asumidas
Se trata de una extensión y un reemplazo de las matrices de tamaño asumido. Dado un argumento real como:
REAL , DIMENSION ( 0 : 10 , 0 : 20 ) :: a : CALL sub ( a )
la especificación del argumento ficticio correspondiente define solo el tipo y rango de la matriz, no su forma. Esta información debe estar disponible mediante una interfaz explícita, a menudo mediante un bloque de interfaz (consulte Bloques de interfaz ). Así escribimos solo
SUBROUTINA sub ( da ) REAL , DIMENSION (:, :) :: da
y esto es como si da
estuvieran dimensionados (11,21). Sin embargo, podemos especificar cualquier límite inferior y los mapas de matriz en consecuencia.
REAL , DIMENSION ( 0 :, 0 :) :: da
Se 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 facilidad proporciona un reemplazo parcial para los usos que se le dio, útil para arreglos temporales locales, como en
SUBROUTINE swap ( a , b ) REAL , DIMENSION (:) :: a , b REAL , DIMENSION ( SIZE ( a )) :: work work = a a = b b = work FIN SUBROUTINE swap
El almacenamiento real generalmente se mantiene en una pila.
ASIGNABLE y ASIGNABLE
Fortran proporciona una asignación dinámica de almacenamiento; se basa en un mecanismo de almacenamiento dinámico (y reemplaza otro uso de EQUIVALENCE
). Un ejemplo para establecer una matriz de trabajo para un programa completo es
MODULE work_array INTEGER n REAL , DIMENSION (:,:, :), ASIGNABLE :: work END MODULE PROGRAM main USE work_array LEER ( entrada , * ) n ASIGNAR ( trabajo ( n , 2 * n , 3 * n ), STAT = estado ) : DEALLOCATE ( trabajo )
La matriz de trabajo se puede propagar a través de todo el programa mediante una USE
declaración en cada unidad del programa. Podemos especificar un límite inferior explícito y asignar varias entidades en una declaración. Para liberar el almacenamiento muerto escribimos, por ejemplo,
DESACTIVAR ( a , b )
La desasignación de matrices es automática cuando quedan fuera de alcance.
Operaciones, asignaciones y procedimientos elementales
Ya hemos cumplido con las asignaciones y operaciones de matrices completas:
REAL , DIMENSION ( 10 ) :: a , b a = 0. ! difusión escalar; asignación elemental b = SQRT ( a ) ! resultado de la función intrínseca como objeto de matriz
En la segunda asignación, una función intrínseca devuelve un resultado con valores de matriz para un argumento con valores de matriz. Podemos escribir funciones con valores de matriz nosotros mismos (requieren una interfaz explícita):
Prueba de PROGRAMA REAL , DIMENSION ( 3 ) :: a = ( / 1. , 2. , 3. / ), & b = ( / 2. , 2. , 2. / ), r r = f ( a , b ) PRINT * , r CONTIENE LA FUNCIÓN f ( c , d ) REAL , DIMENSION (:) :: c , d REAL , DIMENSION ( SIZE ( c )) :: f f = c * d ! (o alguna función más útil de c y d) END FUNCTION f PROGRAMA FIN prueba
Los procedimientos elementales se especifican con argumentos ficticios escalares que se pueden llamar con argumentos reales de matriz. En el caso de una función, la forma del resultado es la forma 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, proporcionando así el efecto de 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 es además una ayuda para la optimización en procesadores paralelos. Un procedimiento elemental debe ser puro.
ELEMENTAL SUBROUTINE swap ( a , b ) REAL , INTENT ( INOUT ) :: a , b REAL :: work work = a a = b b = work END SUBROUTINE swap
Los argumentos ficticios no se pueden utilizar en las expresiones de especificación (véase más arriba ), excepto como argumentos a ciertas funciones intrínsecas ( BIT_SIZE
, KIND
, LEN
, y los más investigación numérico, (ver a continuación ).
DÓNDE
A menudo, necesitamos enmascarar una tarea. Esto lo podemos hacer usando el 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 en toda la matriz), o como una construcción:
DONDE ( a / = 0.0 ) a = 1.0 / a b = a ! todas las matrices tienen la misma forma FIN DONDE
o
DONDE ( a / = 0.0 ) a = 1.0 / a EN OTRO LUGAR a = ENORME ( a ) FIN DONDE
Más:
- se permite enmascarar no solo el
WHERE
enunciado delWHERE
constructo, sino también cualquierELSEWHERE
enunciado que contenga; - una
WHERE
construcción puede contener cualquier número deELSEWHERE
declaraciones enmascaradas pero como máximo unaELSEWHERE
declaración sin máscara, y esa debe ser la última; WHERE
las construcciones pueden estar anidadas unas dentro de otras, soloFORALL
construcciones;WHERE
se permite que una declaración de asignación sea una asignación definida, siempre que sea elemental;- una
WHERE
construcción se puede nombrar de la misma manera que otras construcciones.
La declaración y la construcción de FORALL
Cuando DO
se ejecuta una construcción, cada iteración sucesiva se realiza en orden y una tras otra, 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 llevarse a cabo en cualquier orden, e incluso simultáneamente. Se FORALL
puede considerar que es una asignación de matriz expresada con la ayuda de í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.
La FORALL
construcción permite que se ejecuten en orden varias sentencias de asignación.
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
FORTODO ( 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 TODO
La FORALL
versión es más legible.
La asignación en a FORALL
es como una asignación de matriz: como si todas las expresiones se evaluaran en cualquier orden, se mantuvieran en un almacenamiento temporal y luego todas las asignaciones se realizaran en cualquier orden. La primera declaración debe completarse por completo antes de que pueda comenzar la segunda.
A FORALL
puede estar anidado y puede incluir a WHERE
. Los procedimientos a los que se hace referencia dentro de un FORALL
deben ser puros.
Elementos de matriz
Para un caso simple, dado
REAL , DIMENSIÓN ( 100 , 100 ) :: a
podemos hacer referencia a un solo elemento como, por ejemplo, a(1, 1)
. Para un tipo de datos derivados como
TYPE fun_del REAL u REAL , DIMENSION ( 3 ) :: du END TYPE fun_del
podemos declarar una matriz de ese tipo:
TYPE ( fun_del ), DIMENSION ( 10 , 20 ) :: tar
y una referencia como es un elemento (¡un escalar!) de tipo fun_del, pero es una matriz de tipo real y es un elemento del mismo. La regla básica para recordar es que un elemento de matriz siempre tiene un subíndice o subíndices que califican al menos el apellido.tar(n, 2)
tar(n, 2)%du
tar(n, 2)%du(2)
Subobjetos de matriz (secciones)
La forma general de subíndice para una sección de 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 de un ( i , : ) ! toda la fila 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 ) ! vector subíndice a ( 1 , 2 : 11 : 2 ) ! ¡11 es legal ya que no se hace referencia a (:, 1 : 7 ) ! rango dos sección
Tenga en cuenta que un subíndice de vector 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 del vector no debe ser suministrado como un argumento real a una OUT
o INOUT
ficticio argumento. No se permiten matrices de matrices:
tar % du ! ilegal
Observamos que se puede hacer referencia a un valor dado en una matriz como elemento y como sección:
a ( 1 , 1 ) ! escalar (rango cero) a ( 1 : 1 , 1 ) ! sección de matriz (rango uno)
dependiendo de las circunstancias o requerimientos. Al calificar objetos de tipo derivado, obtenemos elementos o secciones según la regla establecida anteriormente:
alquitrán % u ! sección de matriz (componente de estructura) tar ( 1 , 1 )% u ! componente de un elemento de matriz
Arrays funciones intrínsecas
Vector y matriz se multiplican
DOT_PRODUCT Producto escalar de 2 matrices de rango uno Multiplicación de matrices MATMUL
Reducción de matriz
TODOS Verdadero si todos los valores son verdaderos ANY Verdadero si algún valor es verdadero. Ejemplo: SI (CUALQUIER (a> b)) ENTONCES COUNT Número de elementos verdaderos en la matriz MAXVAL Valor máximo en una matriz MINVAL Valor mínimo en una matriz PRODUCTO Producto de elementos de matriz SUM Suma de elementos de la matriz
Consulta de matriz
Estado de asignación de matrices ALLOCATED LBOUND Límites de dimensión inferior de una matriz FORMA Forma de una matriz (o escalar) TAMAÑO Número total de elementos en una matriz UBOUND Límites de dimensión superior de una matriz
Construcción de matrices
MERGE Fusionar debajo de la máscara EMPAQUE Empaque una matriz en una matriz de rango uno debajo de una máscara SPREAD Replica la matriz agregando una dimensión DESEMBALAJE Desempaque una matriz de rango uno en una matriz debajo de la máscara
Remodelación de matriz
RESHAPE Remodelar una matriz
Manipulación de matrices
Desplazamiento circular CSHIFT EOSHIFT turno final TRANSPOSE Transponer una matriz de rango dos
Ubicación de la matriz
MAXLOC Ubicación del primer valor máximo en una matriz MINLOC Ubicación del primer valor mínimo en una matriz
Punteros
Lo esencial
Los punteros son variables con el POINTER
atributo; no son un tipo de datos distinto (por lo que no es posible una 'aritmética de puntero').
REAL , PUNTERO :: var
Son conceptualmente un descriptor que enumera los atributos de los objetos (objetivos) a los que el puntero puede apuntar, y la dirección, si la hay, de un objetivo. No tienen almacenamiento asociado hasta que se asigna o se asocia de otra manera (por asignación de puntero, ver más abajo ):
ASIGNAR ( var )
y se eliminan las referencias automáticamente, por lo que no se requiere ningún símbolo especial. En
var = var + 2.3
el valor del objetivo de var se usa y se modifica. Los punteros no se pueden transferir a través de E / S. La declaración
ESCRIBIR * , var
escribe el valor del objetivo de var y no el descriptor de puntero en sí.
Un puntero puede apuntar a otro puntero y, por lo tanto, a su objetivo, oa un objeto estático que tiene el TARGET
atributo:
REAL , POINTER :: objeto REAL , TARGET :: target_obj var => object ! asignación de puntero var => target_obj
pero están fuertemente tipados:
INTEGER , POINTER :: int_var var => int_var ! ilegal: los tipos deben coincidir
y, de manera similar, para las matrices, los rangos y el tipo deben coincidir.
Un puntero puede ser un componente de un tipo derivado:
TIPO de entrada ! tipo de matriz dispersa VERDADERO valor INTEGER índice TIPO ( entrada ), PUNTERO :: próxima ! nota recursividad END TYPE entrada
y podemos definir el comienzo de una cadena enlazada de tales entradas:
TIPO ( entrada ), PUNTERO :: cadena
Después de asignaciones y definiciones adecuadas, las dos primeras entradas podrían abordarse como
cadena % valor cadena % próximo % valor cadena % índice de cadena % próximo % índice de cadena % siguiente cadena % próximo % próximo
pero normalmente definiríamos punteros adicionales para apuntar, por ejemplo, a las entradas primera y 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 una asignación de puntero);
- disociado:
DESACTIVAR ( p , q ) ! para devolver el almacenamiento NULLIFY ( p , q ) ! para establecer en 'nulo'
Se debe tener cuidado de no dejar un puntero 'colgando' por el uso de DEALLOCATE
en su objetivo sin anular ningún otro puntero que se refiera a él.
La función intrínseca ASSOCIATED
puede probar el estado de asociación de un puntero definido:
SI ( ASOCIADO ( puntero )) ENTONCES
o entre un puntero definido y un objetivo definido (que puede, en sí mismo, ser un puntero):
SI ( ASOCIADO ( puntero , objetivo )) ENTONCES
Una forma alternativa de inicializar un puntero, también en una declaración de especificación, es usar la NULL
función:
REAL , PUNTERO , DIMENSION (:) :: vector => NULL () ! vector de tiempo de compilación => NULL () ! tiempo de ejecución
Punteros en expresiones y asignaciones
Para los tipos intrínsecos, podemos "barrer" 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 obtenerse 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 (:) INTEGER mult : DO mult = 1 , 2 IF ( mult == 1 ) THEN y => r ! sin movimiento de datos a => c x => z ELSE y => s ! sin movimiento de datos a => b x => r END IF y = MATMUL ( a , x ) ! cálculo común END DO
Para objetos de tipo derivado tenemos que distinguir entre puntero y asignación normal. En
TIPO ( entrada ), PUNTERO :: primero , actual : primero => actual
la asignación hace que el primero apunte a la corriente, mientras que
primero = actual
hace que la corriente se sobrescriba primero y es equivalente a
primer % valor = actual % valor primer % índice = actual % índice primero % siguiente => actual % siguiente
Argumentos de puntero
Si un argumento real es un puntero, si el argumento ficticio también es un puntero,
- debe tener el mismo rango,
- recibe su estado 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
INTENT
atributo (sería ambiguo), - requiere un bloque de interfaz.
Si el argumento ficticio no es un puntero, se asocia con el objetivo 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 POINTER
atributo; 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 contiene el módulo data_handler
FUNCIÓN compact ( x ) REAL , POINTER :: compact (:) REAL x (:) ! Un procedimiento para duplicados eliminar de la matriz x INTEGER n : ! Encontrar el número de valores distintos, n ASIGNAR ( compacto ( n )) : ! Copie los distintos valores en compact END FUNCTION compact
El resultado se puede usar en una expresión (pero debe estar asociado con un objetivo definido).
Matrices de punteros
Estos no existen como tales: dado
TIPO ( entrada ) :: filas ( n )
luego
filas % siguiente ! ilegal
sería tal objeto, 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 datos derivado con un puntero como único componente:
TIPO fila REAL , PUNTERO :: r (:) TIPO FIN
y luego definir matrices de este tipo de datos
TIPO ( fila ) :: s ( n ), t ( n )
donde el almacenamiento para las filas puede ser asignado por, por ejemplo,
HAGA i = 1 , n ASIGNAR ( t ( i )% r ( 1 : i )) ! Asignar fila i de longitud i END DO
La asignación de matriz es equivalente a las asignaciones de puntero para todos los componentes.s = t
s(i)%r => t(i)%r
Punteros como alias dinámicos
Dada una matriz
REAL , OBJETIVO :: tabla ( 100 , 100 )
al que se hace referencia con frecuencia con los subíndices fijos
tabla ( m : n , p : q )
estas referencias pueden ser reemplazadas por
REAL , DIMENSION (:, :), POINTER :: window : window => table ( m : n , p : q )
Los subíndices de ventana son . De manera similar, para (como ya se definió en ), podemos usar, digamos, para señalar todos los componentes u de tar, y subíndice como1:n-m+1, 1:q-p+1
tar%u
taru => tar%u
taru(1, 2)
Los subíndices son como los del propio tar. (Esto reemplaza aún más EQUIVALENCE
).
En la asociación de punteros
puntero => expresión_matriz
los límites inferiores para pointer
se determinan como si lbound
se aplicaran 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 predeterminados son 1.
Fortran 2003 permite especificar límites inferiores arbitrarios en la asociación de punteros, como
ventana ( r :, s :) => tabla ( m : n , p : q )
para que los límites se window
conviertan r:r+n-m,s:s+q-p
. Fortran 95 no tiene esta función; sin embargo, se puede simular usando el siguiente truco (basado en las reglas de asociación de punteros para argumentos ficticios de matriz de formas asumidos):
FUNCIÓN remap_bounds2 ( LB1 , LB2 , array ) RESULTADO ( ptr ) INTEGER , INTENT ( IN ) :: LB1 , LB2 VERDADERO , DIMENSION ( lb1 :, lb2 :), INTENT ( IN ), OBJETIVO :: array de REAL , DIMENSION (:, :), POINTER :: ptr ptr => array FUNCIÓN FINAL : ventana => remap_bounds2 ( r , s , table ( m : n , p : q ))
El código fuente de un ejemplo extendido del uso de punteros para soportar una estructura de datos está en pointer.f90 .
Procedimientos intrínsecos
La mayoría de las funciones intrínsecas ya se han mencionado. Aquí nos ocupamos únicamente de su clasificación general y de las que hasta ahora se han omitido. Todos los procedimientos intrínsecos se pueden utilizar con argumentos de palabras clave:
LLAME DATE_AND_TIME ( TIME = t )
y muchos tienen argumentos opcionales.
Los procedimientos intrínsecos se agrupan en cuatro categorías:
- elemental: trabaja en escalares o matrices, por ejemplo
ABS(a)
; - indagación - independiente del valor del argumento (que puede no estar definido), por ejemplo
PRECISION(a)
; - transformacional - argumento de matriz con resultado de matriz de diferente forma, por ejemplo
RESHAPE(a, b)
; - subrutinas, p
SYSTEM_CLOCK
. ej .
Los procedimientos que aún no se han introducido son
Consulta de bits
BIT_SIZE Número de bits en el modelo
Manipulación de bits
Prueba de bits BTEST IAND lógico y IBCLR Borrar bit Extracción de bits IBITS IBSET Establecer bit O exclusivo de IEOR IOR inclusivo O Cambio lógico ISHFT Desplazamiento circular ISHFTC NO Complemento lógico
Función de transferencia, como en
INTEGER :: i = TRANSFER ( 'abcd' , 0 )
(reemplaza parte de EQUIVALENCIA)
Subrutinas
DATE_AND_TIME Obtener fecha y / o hora MVBITS Copia bits RANDOM_NUMBER Devuelve números pseudoaleatorios RANDOM_SEED Acceso a semilla SYSTEM_CLOCK Acceso al reloj del sistema CPU_TIME Devuelve el tiempo del procesador en segundos
Transferencia de datos
(Este es un subconjunto solo de las características reales y, excepcionalmente, se usan minúsculas en los ejemplos de código).
Entrada / salida formateada
Estos ejemplos ilustran varias formas de listas de E / S con algunos formatos simples (ver a continuación ):
número entero :: i verdadero , dimensión ( 10 ) :: un carácter ( len = 20 ) :: palabra de impresión "(i10)" , i imprimir "(10f10.3)" , una impresión "(3f10.3)" , una ( 1 ), una ( 2 ), una ( 3 ) de impresión "(a10)" , palabra ( 5 : 14 ) de impresión "(3f10.3)" , un ( 1 ) * una ( 2 ) + i , sqrt ( una ( 3 : 4 ))
Las variables, pero no las expresiones, son igualmente válidas en las declaraciones de entrada que utilizan la read
declaración:
leer "(i10)" , yo
Si una matriz aparece como un elemento, se trata como si los elementos se hubieran especificado en el orden de los elementos de la matriz.
Cualquier puntero en una lista de E / S debe estar asociado con un destino, y la transferencia tiene lugar 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
leer "(8f10.5)" , p , t ! tipos punto y triangulo
tiene el mismo efecto que la declaració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 % y
No se permite que un objeto en una lista de E / S sea de un tipo derivado que tenga un componente puntero en cualquier 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. Un elemento de este tipo no corresponde a ninguna transferencia de datos real.
La especificación de formato también puede darse en forma de expresión de carácter:
carácter ( len = * ), parámetro :: formulario = "(f10.3)" : formulario de impresión , q
o como un asterisco: este es un tipo de E / S conocido como E / S dirigido por lista (ver más abajo ), en el que el formato lo define el sistema informático:
print * , "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 print
y una variante de read
no hacen referencia a ningún número de unidad: esto se conoce como E / S de terminal. De lo contrario, la forma es:
leer ( unidad = 4 , fmt = "(f10.3)" ) q leer ( unidad = nunidad , fmt = "(f10.3)" ) q leer ( unidad = 4 * i + j , fmt = "(f10. 3) " ) a
donde unit=
es opcional. El valor puede ser cualquier número entero no negativo permitido por el sistema para este propósito (pero 0, 5 y 6 a menudo denotan el error, teclado y terminal, respectivamente).
Un asterisco es una variante, nuevamente desde el teclado:
leer ( unidad = * , fmt = "(f10.3)" ) q
Una lectura con un especificador de unidad permite el manejo de excepciones :
leer ( unidad = nunidad , fmt = "(3f10.3)" , iostat = ios ) a , b , c si ( ios == 0 ) entonces ! Lectura exitosa: continuar con la ejecución. : más ! Condición de error: tome las medidas adecuadas. error de llamada ( ios ) finaliza si
Existe un segundo tipo de declaración de salida formateada, la write
declaración:
escribir ( unidad = nout , fmt = "(10f10.3)" , iostat = ios ) a
Archivos internos
Éstos permiten que el programa lleve a cabo la conversión de formato entre varias representaciones en un área de almacenamiento definida dentro del propio programa.
integer , dimension ( 30 ) :: ival integer :: key character ( len = 30 ) :: buffer character ( len = 6 ), dimension ( 3 ), parameter :: form = ( / "(30i1)" , "(15i2 ) " , " (10i3) " / ) leer ( unidad = * , fmt = " (a30, i1) " ) búfer , tecla leer ( unidad = búfer , fmt = formulario ( clave )) ival ( 1 : 30 / clave )
Si un archivo interno es un escalar, tiene un solo registro cuya longitud es la del escalar.
Si es una matriz, sus elementos, en el orden de los elementos de la matriz, se tratan como registros sucesivos del archivo y cada uno tiene la longitud de un elemento de la matriz.
Un ejemplo que usa una write
declaración es
número entero :: días verdadera :: efectivo personaje ( len = 50 ) :: línea : ! escriba en línea escriba ( unidad = línea , fmt = "(a, i2, a, f8.2, a)" ) "Recaudación por día" , día , "son" , efectivo , "dólares"
que podría escribir
Las recaudaciones del día 3 son 4329,15 dólares
E / S dirigida por lista
Un ejemplo de una lectura sin un formato especificado para la entrada es
entero :: i real :: un complejo , dimensión ( 2 ) :: campo lógico :: carácter de bandera ( len = 12 ) :: carácter de título ( len = 4 ) :: palabra : leer * , i , a , campo , bandera , título , palabra
Si esto lee el registro de entrada
10 6,4 ( 1,0 ; 0,0 ) ( 2,0 ; 0,0 ) prueba t /
(en la que los espacios en blanco se utilizan como separadores), entonces i
, a
, field
, flag
, y title
adquirirá los valores de 10, 6,4, (1.0,0.0) y (2.0,0.0), .true.
y test
respectivamente, mientras que word
se mantiene sin cambios.
Se requieren comillas o apóstrofos como delimitadores para una cadena que contiene un espacio en blanco.
E / S sin avance
Esta es una forma de leer y escribir sin siempre avanzar la posición del archivo por delante del siguiente registro. Mientras que una instrucción de E / S avanzada siempre reposiciona el archivo después del último registro al que se accedió, una instrucción de E / S que no avanza no realiza tal reposicionamiento y, por lo tanto, puede dejar el archivo colocado dentro de un registro.
character ( len = 3 ) :: key integer :: u , s , ios : read ( unit = u , fmt = "(a3)" , advance = "no" , size = s , iostat = ios ) key if ( ios == 0 ) entonces : si no ! la clave no está en un registro clave ( s + 1 :) = "" : finaliza si
Una lectura que no avanza puede leer los primeros caracteres de un registro y una lectura normal el resto.
Para escribir un mensaje en una pantalla de terminal y leer desde la siguiente posición de carácter en la pantalla sin un salto de línea intermedio, podemos escribir
write ( unit = * , fmt = "(a)" , advance = "no" ) "ingrese el siguiente número primo:" read ( unit = * , fmt = "(i10)" ) prime_number
La E / S sin avance es para archivos externos y no está disponible para E / S dirigida por lista.
Editar descriptores
Es posible especificar que un descriptor de edición se repita un número específico de veces, utilizando un recuento de repeticiones :10f12.3
El descriptor de edición de barra inclinada (ver a continuación ) puede tener un recuento de repeticiones, y un recuento de repeticiones también se puede aplicar 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 de formato:
imprimir "(10i8)" , ( / ( i ( j ), j = 1 , 200 ) / )
escribe 10 enteros, cada uno ocupando 8 posiciones de caracteres, en cada una de las 20 líneas (repitiendo la especificación de formato avanza a la siguiente línea).
Descriptores de edición de datos
- Entero:
iW iW.M
- Verdadero:
fW.D esW.D esW.DeE
- Complejo: pares de descriptores de edición
f
o dees
edición - Lógico:
lW
- Personaje:
a aW
- Tipos derivados: se editan mediante la secuencia apropiada de descriptores de edición correspondientes a los tipos intrínsecos de los componentes finales del tipo derivado.
tipo , públicos :: string entero :: longitud de caracteres ( len = 20 ) :: palabra tipo final de cadena tipo ( cadena ) :: texto leído ( unidad = * , fmt = "(i2, a)" ) de texto
Descriptores de edición de control
Controlar las condiciones de configuración de los descriptores de edición :
- El
ss
descriptor de edición (suprimir el signo) suprime los signos más iniciales. Para activar la impresión del signo más,sp
se utiliza el descriptor (impresión de signo). Els
descriptor de edición restaura la opción al procesador. - Este descriptor permanece vigente para el resto de la especificación de formato, a menos que se cumpla otro de ellos.
Controle los descriptores de edición para su procesamiento inmediato :
- Tabulación:
tN trN tlN
leer ( unidad = * , fmt = "(t3, i4, tl4, i1, i2)" ) i , j , k
- Nuevos registros:
/ N/
leer "(i5, i3, /, i5, i3, i2)" , i , j , k , l , m
Tenga en cuenta que
separa los dos valores por tres registros en blanco.imprimir "(i5,4 /, i5)" , i , j
- Edición de dos
:
puntos : finaliza el control de formato si no hay más elementos en una lista de E / S.detiene nuevos registros siimprimir "(i5,:, /, i5,:, /, i5)" , ( / ( l ( i ), i = 1 , n ) / )
n
es igual a 1 o 2.
E / S sin formato
Este tipo de E / S debe usarse solo en los casos en que los registros son generados por un programa en una computadora, para ser leídos en la misma computadora u otra computadora usando las mismas representaciones numéricas internas:
abrir ( unidad = 4 , archivo = 'prueba' , formulario = 'sin formato' ) leer ( unidad = 4 ) q escribir ( unidad = nout , iostat = ios ) a ! no fmt =
Archivos de acceso directo
Esta forma de E / S también se conoce como acceso aleatorio o E / S indexada. Aquí, todos los registros tienen la misma longitud y cada registro se identifica con un número de índice. Es posible escribir, leer o reescribir cualquier registro especificado sin importar la posición.
entero , parámetro :: nunit = 2 , longitud = 100 real , dimensión ( longitud ) :: a real , dimensión ( longitud + 1 : 2 * longitud ) :: b entero :: i , rec_length : inquire ( iolength = rec_length ) a abierta ( unidad = nunit , acceso = "directa" , ded = rec_length , estado = "cero" , la acción = "lectura-escritura" ) : ! Escritura matriz B para el archivo de acceso directo en el registro 14 de escritura ( unidad = nunit , rec = 14 ) b : ! ! Leer la matriz de nuevo en la matriz a read ( unit = nunit , rec = 14 ) a : do i = 1 , length / 2 a ( i ) = i end do ! ! Reemplazar escritura de registro modificado ( unidad = nunidad , rec = 14 ) a
El archivo debe ser un archivo externo y el formato dirigido por lista y las E / S que no avanzan no están disponibles.
Operaciones en archivos externos
Una vez más, esta es solo una descripción general.
Declaraciones de posicionamiento de archivos
- La
backspace
declaración:retroceso ( unidad = u [, iostat = ios ]) ! donde [] significa opcional
- La
rewind
declaración:rebobinar ( unidad = u [, iostat = ios ])
- La
endfile
declaración:endfile ( unidad = u [, iostat = ios ])
La open
declaración
La declaración se utiliza para conectar un archivo externo a una unidad, crear un archivo que esté preconectado o crear un archivo y conectarlo a una unidad. La sintaxis es
open ( unit = u , status = st , action = act [, olist ])
donde olist
es una lista de especificadores opcionales. Los especificadores pueden aparecer en cualquier orden.
open ( unit = 2 , iostat = ios , file = "cities" , status = "new" , access = "direct" , & action = "readwrite" , recl = 100 )
Otros especificadores son form
y position
.
La close
declaración
Se utiliza para desconectar un archivo de una unidad.
cerrar ( unidad = u [, iostat = ios ] [, estado = st ])
como en
cerrar ( unidad = 2 , iostat = ios , estado = "eliminar" )
La inquire
declaración
En cualquier momento durante la ejecución de un programa, es posible consultar el estado y los atributos de un archivo utilizando esta declaración.
Usando una variante de esta declaración, es igualmente posible determinar el estado de una unidad, por ejemplo, si el número de unidad existe para ese sistema.
Otra variante permite una consulta sobre la longitud de una lista de salida cuando se utiliza para escribir un registro sin formato.
Consultar por unidad
preguntar ( unidad = u , ilist )
o para consultar por archivo
preguntar ( archivo = fln , ilist )
o para consultar por lista de E / S
preguntar ( iolength = length ) olist
Como ejemplo
lógico :: ex , carácter op ( len = 11 ) :: nam , acc , seq , frm entero :: irec , nr inquire ( unidad = 2 , existe = ex , abierto = op , nombre = nam , acceso = acc , secuencial = seq , form = frm , & recl = irec , nextrec = nr )
rendimientos
ej . verdad . op . verdad . nam ciudades acc DIRECT seq NO frm UNFORMATTED irec 100 nr 1
(suponiendo que no intervengan operaciones de lectura o escritura).
Otros especificadores son iostat, opened, number, named, formatted, position, action, read, write, readwrite
.