Está en la página 1de 12

Hemos visto en el capítulo anterior cómo podemos construir las "palabras" de Fortran (las

constantes, palabras clave y nombres) a partir de los elementos básicos del conjunto de
caracteres. En este capítulo descubriremos cómo estas entidades pueden combinarse aún más
en "frases" o expresiones, y cómo, a su vez, pueden combinarse en "oraciones" o
declaraciones. En una expresión, describimos un cálculo que debe realizar la computadora. El
resultado del cálculo puede asignarse a una variable. Una secuencia de tareas es la forma en
que especificamos, paso a paso, la serie de cálculos individuales que se llevarán a cabo para
llegar al resultado deseado. Hay conjuntos separados de reglas para expresiones y
asignaciones, dependiendo de si los operandos en cuestión son numéricos, lógicos, de
caracteres o derivados, y si son escalares o matrices. También hay reglas separadas para las
asignaciones de puntero. Discutiremos cada conjunto de reglas a su vez, incluida una
descripción de las expresiones relacionales que producen un resultado de tipo lógico y son
necesarias en las declaraciones de control (ver el próximo capítulo). Para simplificar la
discusión inicial, comenzamos considerando expresiones y asignaciones que están
intrínsecamente definidas y que no involucran matrices ni entidades de tipos de datos
derivados. Una expresión en Fortran está formada por operandos y operadores, combinados
de una manera que sigue las reglas de la sintaxis de Fortran. Una expresión simple que
involucra un operador diádico (o binario) tiene el operador operando de forma operando, un
ejemplo es x + y, y aunaryormonadicoperator tiene el operador operando de forma un ejemplo
siendo -y El tipo y tipo del resultado están determinados por el tipo y tipo de los operandos y
no dependen de sus valores. Los operandos pueden ser constantes, variables o funciones
(consulte el Capítulo 5), y una expresión puede utilizarse como un operando. De esta manera,
podemos construir expresiones más complicadas como operand operator operand operator
operand ModernFortranExplained, 2ndEdition. MichaelMetcalf, JohnReid y MalcolmCohen.
Oxford University Press (2018). C

Michael Metcalf, John Reid y Malcolm Cohen 2018. DOI 10.1093 / oso /
9780198811893.001.0001

34 Fortran moderno explicado

donde los operandos consecutivos están separados por un solo operador. Cada operando debe
tener un valor definido. Las reglas de Fortran establecen que las partes de las expresiones sin
paréntesis se evalúan sucesivamente de izquierda a derecha para operadores de igual
precedencia, con la excepción de ** (exponenciación, ver Sección 3.2). Si es necesario evaluar
una parte de una expresión, o subexpresión, antes de otra, se pueden usar paréntesis para
indicar qué subexpresión se debe evaluar primero. En el operador de operando (operador de
operador de operando) se evaluará la subexpresión entre paréntesis, y el resultado se usará
como un operando para el primer operador. Si la expresión de expresión de lubricación no
tiene paréntesis, el procesador está permitido para evaluar una expresión equivalente; es
decir, una expresión que siempre tiene el mismo valor, posiblemente, de los efectos del
redondeo numérico. Por ejemplo, si a, byc son variables reales, la expresión a / b / c podría
evaluarse como a / (b * c) en un procesador que puede multiplicarse mucho más rápido de lo
que puede dividirse. Por lo general, dichos cambios son bienvenidos para el programador, ya
que el programa se ejecuta más rápido, pero cuando no son (por ejemplo, porque deberían
dejar entre paréntesis) se deberían insertar paréntesis porque el procesador debe respetarlos.
Si dos operadores se siguen inmediatamente, como en el operador de operador de operando,
la única interpretación posible es que el segundo operador es unario. Por lo tanto, hay una
regla general que un operador binario no debe seguir inmediatamente después de otro
operador.

3.2 Expresiones numéricas escalares Expresión anumérica es una expresión de quién opera y
está uno de los tres tipos numéricos verdes - entero, real y complejo - y cuyos operadores son
** exponenciación * / multiplicación, división + - suma, resta Estos operadores se conocen
como operadores intrínsecos numéricos, y se enumeran aquí en su orden de precedencia. En
ausencia de paréntesis, las exponenciaciones se llevarán a cabo antes de las multiplicaciones y
divisiones, y estas antes de las sumas y restas. Observamos que el signo menos (-) y el signo
más (+) se pueden usar como operadores unarios, como en -tax Debido a que no se permite la
notación matemática ordinaria, no se debe seguir inmediatamente a un operador menor.
Cuando esto sea necesario, como para x − y, los paréntesis deben colocarse alrededor del
operador y su operando:

x ** (- y) El tipo y parámetro de tipo amable del resultado de una operación unaria son los del
operando. La excepción a la regla de izquierda a derecha señalada en la Sección 3.1 se refiere a
exponenciaciones. Mientras que la expresión -a + b + c se evaluará de izquierda a derecha
como ((-a) + b) + c, la expresión a ** b ** c se evaluará como a ** (b ** c) para datos enteros,
el resultado de cualquier división se truncará hacia cero, es decir, al valor entero cuya
magnitud es igual o menor que la magnitud del resultado exacto. Por lo tanto, el resultado de
6/3 es 2 8/3 es 2 -8/3 es −2. Este hecho siempre se transmite en mente cuando la división de
dedos se escribe de nuevo. Del mismo modo, el resultado de 2 ** 3 es 8, mientras que el
resultado de 2 ** (- 3) es 1 / (2 ** 3) que es cero. Las reglas de Fortran permiten que una
expresión numérica contenga operandos numéricos de diferentes tipos o parámetros de tipo
amable. Esto se conoce como una expresión de modo mixto. Excepto cuando se eleva un valor
real o complejo a una potencia entera, el objeto del más débil (o más simple) de los dos tipos
de datos se convertirá, o coaccionará, en el tipo del más fuerte. El resultado también será el
del tipo más fuerte. Si, por ejemplo, escribimos un * i cuando a es de tipo real e i es de tipo
entero, entonces se convertirá a un tipo de datos real antes de que se realice la multiplicación,
y el resultado del cálculo también será de tipo real. Las reglas se resumen para cada
combinación posible para las operaciones +, -, * y / en la Tabla 3.1, y para la operación ** en la
Tabla 3.2. Las funciones real y cmplx que hacen referencia se definen en la Sección 9.3.1. En
ambas tablas, significa entero, R para real y C para complejo. Si ambos operandos son de tipo
entero, el parámetro de tipo amable del resultado es el del operando con el rango de
componente más amplio o más dependiente del proceso o dependiente del tipo de cambio.

Tabla 3.1. Tipo de resultado de un .op. b, donde .op. es +, -, * o /. Tipo Tipo Valor de Valor de
Tipo de a de ba usado b resultado usado II ab IIR real (a, tipo (b)) b RIC cmplx (a, 0, tipo (b)) b
CRI a real (b, tipo (a)) RRR ab RRC cmplx (a, 0, tipo (b)) b CCI a cmplx (b, 0, tipo (a)) CCR a cmplx
(b, 0, tipo (a)) CCC ab C

Tabla 3.2. Tipo de resultado de a ** b. Tipo Tipo Valor de Valor de Tipo de a de ba usado b
resultado usado II ab IIR real (a, tipo (b)) b RIC cmplx (a, 0, tipo (b)) b CRI ab RRR ab RRC cmplx
(a, 0, tipo (b)) b CCI ab CCR a cmplx (b, 0, tipo (a)) CCC ab C

pero los rangos de exponente decimal son los mismos. Si ambos operandos son de tipo real o
complejo, el tipo de parámetro del tipo es el resultado de la operación y la precisión decimal
mayor, o depende del procesador si los tipos difieren pero las precisiones decimales son las
mismas. Si un operando es de tipo entero y el otro es real o complejo, el parámetro de tipo del
resultado es el del operando real o complejo. Tenga en cuenta que una constante literal en
una expresión de modo mixto se mantiene con su propia precisión, que puede ser menor que
la de la expresión. Por ejemplo, dada una variable a de tipo largo (Sección 2.6.2), el resultado
de a / 1.7 será menos preciso que el de a / 1.7_long. En el caso de elevar un valor complejo a
una potencia compleja, se toma el valor principal1. No está permitido elevar un valor real
negativo a una potencia real ya que el resultado exacto probablemente tenga una parte
imaginaria distinta de cero

3.3 Variables definidas y definidas

En el curso de las explicaciones en este y en los siguientes capítulos, a menudo nos referiremos
a una variable que se vuelve de fi nida o indefinida. En el capítulo anterior, mostramos cómo
una variable escalar puede ser creada por una declaración como real :: speed. En este caso
simple, la velocidad variable no tiene, al comienzo de la ejecución del programa, ningún valor
definido. No está definido. No se debe intentar hacer referencia a su valor ya que no tiene
ninguno. Una forma común en la que podría definirse es que se le asigne un valor: velocidad =
2.997 Después de la ejecución de dicha declaración de asignación, tiene un valor, y ese valor
puede ser referenciado, por ejemplo, en una expresión: velocidad * 0.5 Para un objeto
compuesto, todos sus subobjetos que no son punteros deben definirse individualmente antes
de que el objeto como un todo sea considerado como definido. Por lo tanto, se dice que una
matriz se define solo cuando se define cada uno de sus elementos, un objeto de un tipo de
datos derivado se define solo cuando cada uno de sus componentes no punteros se define y
una variable de caracteres se define solo cuando cada uno de sus elementos los caracteres
están definidos. Una variable que se define no necesariamente conserva su estado de
definición a lo largo de la ejecución de un programa. Como veremos en el Capítulo 5, una
variable que es local para un solo subprograma generalmente queda indefinida cuando el
control se devuelve desde ese subprograma. En ciertas circunstancias, incluso es posible que
un solo elemento de la matriz se vuelva indefinido y esto haga que la matriz considerada como
un todo se vuelva indefinida; una regla similar es válida para entidades de tipo de datos
derivados y para variables de caracteres. En la Sección 8.5 se explica un medio para especificar
el valor inicial de una variable. En el caso de un puntero, el estado de asociación del puntero
puede estar indefinido o definido al estar asociado con un objetivo o al estar disociado, lo que
significa que no está asociado con un objetivo pero tiene un estado definido que puede ser
probado por la función asociada ( Sección 9.2). Aunque un puntero esté asociado con un
objetivo, el objetivo en sí puede estar definido o no definido. Se proporcionan los medios para
especificar el estado inicial de disociado (ver Sección 8.5.3).

3.4 Asignación escalarnumerica

La forma general de una asignación numérica escalar es variable = expr donde variable es una
variable numérica escalar y expr es una expresión numérica escalar. Si expr no es del mismo
tipo o tipo que la variable, se convertirá a ese tipo y tipo antes de que se lleve a cabo la
asignación, de acuerdo con el conjunto de reglas que figuran en la Tabla 3.3 (las funciones int,
real y cmplx se definen en la Sección 9.3.1). Cuando se menciona que el tipo de variable es un
número entero de texto no es así, entonces la asignación resultará en una pérdida de precisión
única en la sexualidad que probablemente tenga un valor integral. Del mismo modo,
asignando

Tabla 3.3. Conversión numérica para la declaración de asignación variable = expr. Tipo de
variable Valor entero asignado int (expr, kind (variable)) real real (expr, kind (variable))
complejo cmplx (expr, kind = kind (variable))
la expresión a una variable constante de la humanidad sin precisión, también puede causar la
pérdida de precisión, y la asignación de una cantidad compleja a una variable no compleja
implica la pérdida de la parte imaginaria. Por lo tanto, los valores en i y a siguiendo las
asignaciones i = 7.3! i de tipo entero predeterminado a = (4.01935, 2.12372)! Un tipo real
predeterminado es 7 y 4.01935, respectivamente. Además, si se asigna una constante literal a
una variable de mayor precisión, el resultado tendrá la precisión de la constante. Por ejemplo,
dada una variable a de tipo largo (Sección 2.6.2), el resultado de a = 1.7 será menos preciso
que el de a = 1.7_long

3.5 Operadores relacionales escalares

Es posible en Fortran probar si el valor de una expresión numérica guarda una cierta relación
con la de otra, y de manera similar para las expresiones de caracteres. Los operadores
relacionales son <menos que <= menos que o igual == igual / = no igual> mayor que> = mayor
que o igual Si cualquiera de las expresiones o ambas son complejas, solo están disponibles los
operadores == y / =. El resultado de tal comparación es uno de los valores lógicos
predeterminados .true. o .false., y veremos en el próximo capítulo cómo tales pruebas son
importantes para controlar la ejecución de un programa. Ejemplos de expresiones relacionales
(para i y j del tipo de letra, a y b del tipo real, y char1 del tipo de carácter predeterminado) son
i <0 expresión relacional entera a <b expresión real relacional a + b> ij expresión relacional de
modo mixto char1 == 'Z' expresión relacional de personajes

Expresiones y tareas 39

En la tercera expresión anterior, observamos que los dos componentes son de diferentes tipos
numéricos. En este caso, y siempre que uno o ambos de los dos componentes consistan en
expresiones numéricas, las reglas establecen que los componentes se evaluarán por separado
y se convertirán en el tipo y la especie de su número antes de realizar la comparación. Por lo
tanto, una expresión relacional como a + b <= i-j se evaluará convirtiendo el resultado de (i-j)
en tipo real. Para las comparaciones de caracteres, los tipos deben ser los mismos y las letras
se comparan desde la izquierda hasta que se encuentre una diferencia o las cadenas sean
idénticas. El resultado de la comparación está determinado por las posiciones en la secuencia
de clasificación (ver Sección 2.6.4) de los primeros caracteres diferentes. Si las longitudes
difieren, se considera que la más corta está rellenada con espacios en blanco2 a la derecha.
Dos cadenas de tamaño cero se consideran idénticas. El efecto es como el orden de las
palabras en un diccionario. Por ejemplo, la relación "ab" <"ace" es verdadera. Ninguna otra
forma de operador relacional de modo mixto está intrínsecamente disponible, aunque dicho
operador puede estar definido (Sección 3.9). Los operadores numéricos tienen prioridad sobre
los operadores relacionales.

.not.k.and.j y .not.l serán evaluados y comparados por no equivalencia. El resultado de la


comparación, .true. o .false., se combinará con i. El tipo de tipo de parámetro del resultado es
el que opera y no., Y para los demás es el de los operandos si tienen el mismo tipo o el
procesador depende de lo contrario. Notamos que el .or. operador es un operador inclusivo; el
.neqv. El operador proporciona un lógico exclusivo o (a.and..not.b .or. .not.a.and.b). El
resultado de cualquier expresión lógica es el valor verdadero o falso, y este valor puede
asignarse a una variable lógica como el elemento 3 del indicador de matriz lógica en el
indicador de ejemplo (3) = (.not. K .eqv. L ) .or. j Los valores de los parámetros de tipo amable
de la variable y la expresión no necesitan ser idénticos. Una variable lógica puede establecerse
en un valor predeterminado mediante una instrucción de asignación: flag (1) = .true. bandera
(2) = .false. Antes de pasar a los ejemplos, todas las operaciones y resultados fueron de tipo
lógico; ningún otro tipo de datos puede participar en una operación o asignación lógica
intrínseca. Los resultados de varias expresiones relacionales pueden combinarse en una
expresión lógica y asignarse, como en real :: a, b, x, y logical :: cond. . . cond = a> b. o. x <0.0. y.
y> 1.0 donde notamos la precedencia de los operadores relacionales sobre los operadores
lógicos. Si el valor de dicha expresión lógica se puede determinar sin evaluar una subexpresión,
se permite que un procesador no evalúe la subexpresión. Un ejemplo es i <= 10. Y. ary (i) == 0!
para una matriz real ary (10) cuando tiene el valor 11. Sin embargo, el programador no debe
tener apenas un subíndice de comportamiento fuera de los límites si el procesador elige
evaluar la subexpresión de la derecha antes que la de la izquierda. Volvemos a este tema en la
Sección 5.10.1.

3.7 Expresiones de caracteres escalares y expresiones como el único operador intrínseco para
las expresiones de caracteres en el operador de concatenación //, que tiene el efecto de
combinar dos operaciones de caracteres en un solo resultado de carácter. Por ejemplo, el
resultado de concatenar las dos constantes de caracteres AB y CD, escritas como 'AB' // // 'CD'
es la cadena de caracteres ABCD. Las operaciones deben tener los mismos valores de
parámetros de la especie, pero pueden ser variables de caracteres, constantes o funciones. Por
ejemplo, si word1 y word2 son del tipo predeterminado y de la longitud 4, y contienen las
cadenas de caracteres LOOP y HOLE, respectivamente, la cadena POLE es el resultado de
word1 (4: 4) // word2 (2: 4)

Expresiones y tareas 41

El resultado de una concatenación es la suma de las longitudes de los operandos. Por lo tanto,
la longitud del resultado de word1 // word2 // 'S' es 9, que es la longitud de la cadena
LOOPHOLES. El resultado de una expresión de caracteres puede asignarse a una variable de
caracteres del mismo tipo. Suponiendo el carácter de declaraciones (len = 4) :: char1, carácter
char2 (len = 8) :: resultado, podemos escribir char1 = 'any' char2 = 'book' result = char1 //
char2 En este caso, el resultado ahora contendrá la cadena de cualquier libro. Observamos en
estos ejemplos que las longitudes de los lados izquierdo y derecho de las tres asignaciones son
en cada caso iguales. Sin embargo, si la longitud del resultado del lado derecho es más corta
que la longitud del lado izquierdo, entonces el resultado se coloca en la parte más a la
izquierda del lado izquierdo y el resto se llena con caracteres en blanco Por lo tanto, en el
carácter (len = 5) :: fill fill (1: 4) ='’ AB '' fill (1: 4) tendrá el valor ABbb (donde b representa un
carácter en blanco). El valor de relleno (5: 5) permanece indefinido, es decir, no contiene
ningún valor específico y no debe usarse en una expresión. Como consecuencia, el relleno
también está indefinido. Por otro lado, cuando el lado izquierdo es más corto que el resultado
del lado derecho, el extremo derecho del resultado se trunca. El resultado del carácter (len = 5)
:: trunc8 trunc8 = 'TRUNCATE' es colocar en trunc8 la cadena de caracteres TRUNC. Si un lado
izquierdo es de longitud cero, no se realiza ninguna asignación. Los lados izquierdo y derecho
de una tarea pueden superponerse. En tal caso, siempre se usan los valores antiguos en la
expresión del lado derecho. Por ejemplo, el resultado de la asignación (3: 5) = resultado (1: 3)
es válido y si el resultado comenzó con el valor ABCDEFGH, quedaría con el valor ABABCFGH.
Otros medios para manipular caracteres y cadenas de caracteres, a través de funciones
intrínsecas, se describen en las Secciones 9.6 y 9.7.

3.7.1 Conjunto de caracteres ASCII


Si el juego de caracteres predeterminado para un procesador no es ASCII, pero ASCII es
compatible con ese procesador, la asignación intrínseca se define entre ellos para convertir los
caracteres adecuadamente. Por ejemplo, en una máquina EBCDIC, en entero, parámetro ::
ascii = selected_char_kind ('ASCII') carácter :: carácter ce (ascii) :: ca ce = ascii_'X 'ca =' X 'la
primera declaración de asignación convertirá el ASCIIupper-caseXtoanEBCDICupper-case X, y la
segunda declaración de asignación hará el marcha atrás.

3.7.2 Conjunto de caracteres ISO10646

ISO / IEC 10646 UCS-4 es un conjunto de caracteres de cuatro bytes diseñado para poder
representar cada carácter en cada idioma en el mundo, incluidos todos los caracteres
especiales en los conjuntos de caracteres codificados. Es un superconjunto estricto de ASCII de
siete bits; es decir, sus primeros 128 caracteres son los mismos que los de ASCII. Se permite la
asignación de caracteres predeterminados o caracteres ASCII a ISO 10646, y los caracteres se
convierten adecuadamente. La asignación de caracteres ISO 10646 a los caracteres
predeterminados o ASCII también está permitida; sin embargo, si algún carácter ISO 10646 no
es representable en el juego de caracteres de destino, el resultado depende del procesador (se
perderá información). Por ejemplo, en entero, parámetro :: ascii = selected_char_kind ('ASCII')
entero, parámetro :: iso10646 = selected_char_kind ('ISO_10646') carácter (ascii) :: x = ascii_'X
'carácter (iso10646) :: yy = x la variable de caracteres ISO10646 y se establecerá en el valor
correcto para el boletín de mayúsculas y minúsculas X.

3.8 Constructores de estructuras

Una estructura puede construirse a partir de expresiones para sus componentes, así como una
estructura constante puede construirse a partir de constantes (Sección 2.9). La forma general
de un constructor de estructura es derivado-tipo-especificación ([componente-especificación-
lista]) donde derivado-tipo-especificación es el nombre de un tipo derivado3 y cada
componente-especificación es [palabra clave =] expr o [palabra clave =] target donde palabra
clave es el nombre de un componente del tipo, expr es un valor para un componente sin
puntero y target es un objetivo para un componente puntero. En un caso simple, las
especificaciones del componente no tienen palabras clave y proporcionan valores para los
componentes en el orden en que aparecen en la declaración de tipo. Por ejemplo, dado el tipo
3A, se discutirá una forma más general en la Sección 13.2.

Expresiones y tareas 43

type char10 integer :: length character (len = 10) :: value end type char10 y the variables
character (len = 4) :: char1, char2 el siguiente es un valor de type char10: char10 (8, char1 //
char2) Si se usan palabras clave, deben aparecer después de cualquier especificación de
componente sin palabras clave, pero pueden estar en cualquier orden. Ningún componente
puede aparecer más de una vez. Un componente puede estar ausente solo si tiene una
inicialización predeterminada (Sección 8.5.5). Los componentes sin puntero se tratan como si
se hubiera ejecutado la instrucción de asignación intrínseca derivada-tipo-especificación%
palabra clave = expr, y los componentes de puntero se han creado como desviación de la
declaración de asignación de tipo derivado-palabra-clave% palabra clave => objetivo
ejecutado. En ambos casos, se aplican las reglas para la asignación intrínseca y la asignación de
puntero.

3.9 Operadores fi nales Scalarde


No hay operadores para los tipos derivados que estén automáticamente disponibles. Si un
programador define un tipo derivado y desea que los operadores estén disponibles, él o ella
también deben definir a los operadores. Para una órtesis de operación binaria realizada
escribiendo una función, con dos argumentos intencionados, que especifica cómo el resultado
depende de los operandos, y un bloque de interfaz que asocia la función con el token del
operador (las funciones, la intención y los bloques de interfaz se explicarán completamente en
el Capítulo 5). Por ejemplo, dado el intervalo de tipo de tipo real :: menor, intervalo de tipo de
extremo superior que representa intervalos de números entre un límite inferior y uno
superior, podemos definir la suma por un módulo (Sección 5.5) que contiene la función de
procedimiento add_interval (a, b ) type (intervalo) :: add_interval type (intervalo), intent (in) ::
a, b add_interval% lower = a% lower + b% lower! ¡El código de producción
agregaría_intervalo% superior = a% superior + b% superior! permitir el redondeo. función final
add_interval.

Operador de interfaz (+) procedimiento de módulo add_interval end interface Esta función se
invocaría en una expresión como y + z para realizar esta operación de adición definida por el
programador para las variables escalares y y z de intervalo de tipo. Un operador unario está
definido por un bloque de interfaz y una función con una intención en el argumento. El token
del operador puede ser cualquiera de los tokens utilizados para los operadores intrínsecos o
puede ser una secuencia de hasta 63 letras encerradas en puntos decimales distintos de. o
.false .. Un ejemplo es .sum. En este caso, la línea de encabezado del bloque de interfaz se
escribiría como operador de interfaz (.sum.) Y la expresión como y.sum.z Si se usa un token
intrínseco, el número de argumentos debe ser el mismo que para el intrínseco. operación, la
precedencia de la operación es como para la operación intrínseca, y no debe seguirse un signo
de menos o más unario inmediatamente después de otro operador. De lo contrario, es de
mayor prioridad para operadores unarios definidos y de menor prioridad para operadores
binarios definidos. El conjunto completo de precedencia se da en la Tabla 3.4. Cuando se
requiere otra precedencia dentro de una expresión, se deben usar paréntesis.

Tabla 3.4. Precedencia relativa de los operadores (en orden decreciente). Tipo de operación
cuando operador intrínseco

- operador definido monádico (unario) Numérico ** Numérico * o / Numérico monádico + o


Numérico diádico + o Carácter // Relacional == / = <<=>> = Lógico .not. Lógico. Y. Lógico. O.
Lógico .eqv. o .neqv. - operador definido diádico (binario)

Expresiones y tareas 45

Retener las precedencia intrínsecas es útil tanto para la legibilidad de las expresiones como
para la eficiencia con la que un compilador puede interpretarlas. Por ejemplo, si + se usa para
la unión de conjuntos y * para la intersección de conjuntos, podemos interpretar la expresión i
* j + k para los conjuntos i, j y k sin dificultad. Ifeitheroftheintrinsictokens == y .eq. Cuando se
utiliza, la definición se aplica a ambas fichas para que siempre sean equivalentes. Lo mismo es
cierto para los otros pares equivalentes de operadores relacionales. Tenga en cuenta que un
operador unario definido que no utiliza un token intrínseco puede seguir inmediatamente
después de otro operador, como en y .sum. .inverso. x Los operadores se pueden definir para
cualquier tipo de operandos, excepto cuando hay una operación intrínseca para el operador y
los tipos. Por ejemplo, podríamos desear poder agregar un número de intervalo a un real
ordinario, lo que se puede hacer con la función de procedimiento adicional add_interval_real
(a, b) type (intervalo) :: add_interval_real type (intervalo), intent (in) :: a real, intent (in) :: b
add_interval_real% lower = a% lower + b! ¡El código de producción agregaría_interval_real%
upper = a% upper + b! permitir el redondeo. función final add_interval_real cambiando el
bloque de interfaz al procedimiento del módulo del operador de interfaz (+) add_interval,
add_interval_real end interface El resultado de una operación definida de este tipo puede
tener cualquier tipo. El tipo de resultado, así como su valor, deben ser especificados por la
función. Tenga en cuenta que una operación que se define intrínsecamente no se puede
redefinir; así en real :: a, b, c. . . c = a + b el significado de la operación siempre es inequívoco.

3.10 Scalarde fi nadas asignaciones

La asignación de una expresión de tipo derivado a una variable del mismo tipo está disponible
automáticamente y toma el componente por componente. Por ejemplo, si hay un intervalo de
tipo definido al comienzo de la Sección 3.9, podemos escribir.

Sin embargo, en otras circunstancias, podríamos desear definir una acción diferente para una
asignación que involucre un objeto de tipo derivado, y de hecho esto es posible. Una
asignación puede ser definida para hacer una asignación puede ser definida por una subrutina
con dos argumentos, el primero teniendo intención o intención dentro y correspondiente a la
variable, y el segundo teniendo intencionalmente y correspondiendo a la expresión (las
subrutinas también serán definitivas en el Capítulo 5). En el caso de una asignación que
involucre un objeto de tipo derivado y un objeto de un tipo diferente, se debe proporcionar
dicha definición. Por ejemplo, la asignación de reales a intervalos y viceversa podría definirse
mediante un módulo que contiene las subrutinas subrutina real_from_interval (a, b) real,
intent (out) :: a type (intervalo), intent (in) :: ba = ( b% más bajo + b% más alto) / subrutina final
2 real_from_interval e intervalo de subrutina_de_real (a, b) tipo (intervalo), intento (fuera) :: a
real, intento (adentro) :: ba% más bajo = ba% superior = b subrutina final intervalo_de_real y la
interfaz de bloque de interfaz asignación (=) procedimiento del módulo real_de_intervalo,
intervalo_de_real interfaz final Dado esto, podemos escribir type (intervalo) :: aa = 0.0 Una
asignación definida no debe redefinir el significado de una asignación intrínseca para tipos
intrínsecos, es decir, una asignación entre dos objetos de tipo numérico, de tipo lógico o de
tipo de carácter con el mismo parámetro de tipo, pero puede redefinir el significado de una
alineación intrínseca para dos objetos del mismo tipo derivado. Por ejemplo, para una
asignación entre dos variables del tipo char10 (Sección 3.9) que copia solo la parte relevante
del componente de caracteres, podríamos escribir la subrutina asignar_cadena (izquierda,
derecha) tipo (char10), intento (fuera) :: left type (char10 ), intent (in) :: right left% length =
right% length left% value (1: left% length) = right% value (1: right% length) end subroutine
asignar_cadena La asignación intrínseca para un objeto de tipo derivado siempre implica
asignación intrínseca para todos sus componentes sin puntero, incluso si un componente es de
un tipo derivado para el que se ha redefinido la asignación.

Expresiones y tareas 47

3.11 Expresiones de arrays

Hasta ahora en este capítulo hemos asumido que todas las entidades en una expresión son
escalares. Sin embargo, cualquiera de las operaciones intrínsecas unitarias también se puede
aplicar a una matriz para producir otra matriz de la misma forma (rango y extensión idénticos,
ver Sección 2.10) y que cada valor de elemento sea igual al de la operación aplicada al
elemento correspondiente de El operando. De manera similar, las operaciones intrínsecas
binarias se pueden aplicar a un par de matrices de la misma forma para producir una matriz de
esa forma, con un valor de valor igual al de la operación aplicada para corresponder elementos
de las operaciones. Una de las operaciones de operación abinaria puede ser un escalar, en
cuyo caso el resultado es como si el escalar se hubiera transmitido a una matriz de la misma
forma que el operando de la matriz. Dadas las declaraciones de matriz real, dimension (10,20)
:: a, b real, dimension (5) :: v los siguientes son ejemplos de expresiones de matriz: a / b!
Matriz de forma [10,20], con elementos a (i, j) / b (i, j) v + 1. ! Matriz de forma [5], con
elementos v (i) +1.0 5 / v + a (1: 5,5)! Matriz de forma [5], con elementos 5 / v (i) + a (i, 5) a ==
b! Matriz lógica de forma [10,20], con elemento (i, j)! .cierto. si a (i, j) == b (i, j), y .false. de lo
contrario, se dice que dos conjuntos de la misma forma son conformes, y un escalar es
compatible con cualquier conjunto. Tenga en cuenta que la correspondencia es por posición
en la extensión y no por valor de subíndice. Por ejemplo, a (2: 9,5: 10) + b (1: 8,15: 20) tiene
valores de elemento a (i + 1, j + 4) + b (i, j + 14) donde i = 1 , 2, ..., 8, j = 1, 2, ..., 6 Esto puede
representarse gráficamente como en la Figura 3.1. El orden en que se ejecutan las operaciones
escalares en cualquier expresión de matriz no está especificado en el estándar, lo que permite
que un compilador organice una ejecución eficiente en una computadora vectorial o paralela.
Cualquier operador intrínseco escalar puede aplicarse de esta manera a matrices y pares
matriz-escalares. Para operadores derivados, el programador puede definir un procedimiento
elemental con estas propiedades (ver Sección 7.9). Él o ella también puede definir operadores
directamente para ciertos rangos o pares de rangos. Por ejemplo, la matriz de tipo de tipo real
:: matriz de tipo final de elemento podría definirse para tener operaciones escalares que sean
idénticas a las operaciones para reales, pero para las matrices de los rangos uno y dos, el
operador * se define como multiplicación matricial media. Por lo tanto, la matriz tipo sería
adecuada para la aritmética matricial, mientras que los reales no son adecuados porque la
multiplicación para matrices reales se realiza elemento por elemento. Esto se discute más en la
Sección 7.5

3.12 Asignación de matriz

Por asignación intrínseca, se puede asignar una expresión de matriz a una variable de matriz
de la misma forma, 5 que se interpreta como si cada elemento de la expresión se asignara al
elemento correspondiente de la variable. Por ejemplo, con las declaraciones del comienzo de
la última sección, la asignación a = a + 1.0 reemplaza a (i, j) por a (i, j) +1.0 para i = 1, 2, ..., 10 y
j = 1, 2, ..., 20. Tenga en cuenta que, en cuanto a las expresiones, la correspondencia del
elemento es por posición dentro de la extensión en lugar de por valor de subíndice. Esto se
ilustra con el ejemplo a (1,11: 15) = v! a (1, j + 10) se asigna desde! v (j), j = 1, 2, ..., 5
Ascalarexpression puede asignarse a una matriz, en la que se establece un valor de escala
variable para todos los elementos de la matriz. Si la expresión incluye una referencia a la
variable de matriz o a una parte de ella, la expresión se interpreta como completamente
evaluada antes de que comience la asignación. Por ejemplo, la declaración v (2: 5) = v (1: 4) 5
Para las matrices asignables, las formas pueden diferir, consulte la Sección 6.7.

+ = resultado 8x6

a (1,1) a (1,20)

a (2,5) a (2,10)

a (9,5) a (9,10)

a (10,1) a (10,20)

) 51,1 (b) 1,1 (b


b (1,20)

b (8,15) b (8,20)

b (10,1) b (10,20)

Expresiones y tareas 49

da como resultado que cada elemento v (i) para i = 2, 3, 4, 5 tenga el valor que v (i-1) tenía
antes del comienzo de la asignación. Esta regla es exactamente paralela a la regla para las
subcadenas que se explicó en la Sección 3.7. El orden en el que se asignan los elementos de la
matriz no está especificado por el estándar, para permitir optimizaciones. Los conjuntos de
funciones intrínsecas numéricas y matemáticas, cuyos resultados pueden usarse como
operandos en expresiones escalares o de matriz y en asignaciones, se describen en las
Secciones 9.3 y 9.4. Si una asignación definida (Sección 3.10) se define mediante una subrutina
elemental (Sección 7.9), se puede usar para asignar un valor escalar a una matriz o un valor de
matriz a una matriz de la misma forma. Se puede proporcionar una subrutina separada para
cualquier combinación particular de rangos y anulará la asignación elemental. Si no hay una
asignación definida elemental, la asignación intrínseca todavía está disponible para aquellas
combinaciones de rangos para los que no hay una asignación definida correspondiente. En la
Sección 7.6 se describe una forma de asignación de matriz bajo una máscara y la asignación se
expresa con la ayuda de índices en el Apéndice B.3.1.

3.13 Indicadores de expresiones del seno y designaciones

Un puntero puede aparecer como una variable en las expresiones y tareas que hemos
considerado hasta ahora en este capítulo, siempre que tenga una asociación válida con un
objetivo. El objetivo se accede sin ninguna necesidad a un símbolo de referencia explícito. En
particular, si ambos lados de una instrucción de asignación son punteros, los datos se copian
de un objetivo al otro objetivo. A veces surge la necesidad de otro tipo de tarea. Es posible que
deseemos que el punto de la izquierda apunte a un objetivo, más que eso, que su objetivo
actual adquiera datos nuevos. Es decir, queremos que se modifique el descriptor. Esto se llama
asignación de puntero y tiene lugar en una declaración de asignación de puntero: puntero =>
destino donde puntero es el nombre de un puntero o el designador de un componente de
estructura que es un puntero, y el objetivo suele ser una variable, pero también puede ser una
referencia a una función con valor de puntero (consulte la Sección 5.10). Por ejemplo, las
declaraciones x => z a => c tienen variables como objetivos y son necesarias para la primera
multiplicación matricial de la Sección 2.12, para hacer que x se refiera a z y a para referirse a c.
La sentencia x => null () (la función null se describe en la Sección 9.17) nulli fi es x. La
asignación de puntero también tiene lugar para un componente de puntero de una estructura
cuando la estructura aparece en el lado izquierdo de una asignación ordinaria. Por ejemplo,
supongamos que hemos utilizado la entrada de tipo de la Figura 2.3 de la Sección 2.12 para
construir una cadena de entradas y deseamos agregar una nueva entrada al frente. Si first
apunta a la primera entrada y current es un puntero escalar de entrada de tipo, las
instrucciones asignan (current) current = entry (new_value, new_index, first) first => current

asignar una nueva entrada y vincularla a la parte superior de la cadena. La declaración de


asignación tiene el efecto current% next => first y establece el enlace. La instrucción de
asignación de puntero da primero la nueva entrada como su objetivo sin alterar la primera
entrada anterior. La asignación ordinaria first = current sería incorrecta porque el objetivo se
copiaría, destruyendo la primera entrada anterior, correspondiente a las asignaciones de
componentes first% value = current% value! Componentes del primer% index = current%
index! los viejos primero se pierden. first% next => current% next! En el caso en que la cadena
comenzó con longitud dos y consistió en primero: (1.0, 10, asociado) primero% siguiente: (2.0,
15, nulo) después de la ejecución del primer conjunto de declaraciones tendría tres longitudes
y consistiría en primero: (4.0, 16, asociado) primero% siguiente: (1.0, 10, asociado) primero%
siguiente% siguiente: (2.0, 15, nulo) Si el objetivo en una instrucción de asignación de puntero
es una variable que no es en sí misma un puntero o un subobjeto de un objetivo de puntero,
debe tener el atributo objetivo. Por ejemplo, la declaración real, dimension (10), target :: y
declara que y tiene el atributo target. Cualquier subobjeto sin puntero de un objeto con el
atributo de destino también tiene el atributo de destino. El atributo de destino es necesario
para que el compilador optimice el código. Es muy útil para el compilador saber que un
objetivo de puntero no puede acceder a una variable que no sea un puntero o un objetivo. El
objetivo en una declaración de asignación de puntero puede ser un subobjeto de un objetivo
de puntero. Por ejemplo, dado el carácter de declaración (len = 80), dimensión (:), puntero ::
página y una asociación apropiada, los siguientes son todos los objetivos permitidos: página,
página (10), página (2: 4), página ( 2) (3:15) Tenga en cuenta que es insuficiente para el punto
de alcanzar un nivel de selección de componentes. Por ejemplo, dado el tipo de declaración
(entrada) :: nodo que tiene un componente puntero a continuación (ver Sección 2.12) y una
asociación apropiada, el nodo% siguiente% valor es un objetivo permitido. Si el objetivo en una
declaración de asignación de puntero es en sí mismo un objetivo de puntero, entonces tiene
lugar una copia directa del descriptor. Si el estado de asociación del puntero es indefinido o
desasociado, este estado se copia. Si el objetivo es un puntero o un subobjeto de un objetivo
de puntero, la nueva asociación es con la estrella de ese puntero y no se ve afectada por
ningún cambio posterior a su estado de asociación. Esto se ilustra en el siguiente ejemplo. La
secuencia

Expresiones y asignaciones 51

b => c! c tiene el atributo de destino a => b nullify (b) dejará un punto fijo hacia c. El tipo, los
parámetros de tipo y el rango del puntero y el destino en una declaración de asignación de
puntero deben ser iguales. Si el puntero es una matriz, toma su forma y límites desde el
objetivo. Los límites son como serían devueltos por las funciones lbound y ubound (Sección
9.14.2) para el objetivo, lo que significa que una sección de matriz para una expresión en arco
generalmente toma el valor 1 para un límite inferior y la extensión correspondiente al límite
superior (pero veremos más adelante cómo se puede especificar un límite inferior, ver Sección
7.15). Fortran es inusual en que no requiere un personaje especial para una referencia a un
objetivo de puntero, sino que requiere una tarea difícil de asignar a una asignación ordinaria.
Por lo tanto, esta elección es la expectativa de que la ingeniería y los programas científicos se
referirán a los datos del objetivo con mucha más frecuencia de la que cambian los objetivos.

3.14 Luego, declarar

Un puntero puede desasociarse explícitamente de su objetivo ejecutando una declaración


nula. Su forma general es anular (pointer-object-list). No debe haber dependencias entre los
objetos, para permitir que el procesador anule los objetos uno por uno en cualquier orden. La
declaración también es útil para dar el estado disociado a un puntero indefinido. Una ventaja
de anular los indicadores en lugar de dejarlos indefinidos es que pueden tener diabetes por la
función intrínseca asociada (Sección 9.2). Por ejemplo, el extremo de la cadena de la Sección
3.13 será un indicador asociado al puntero si la declaración nullify (first) se ejecuta
inicialmente para crear una cadena de longitud cero. Debido a que a menudo hay otras formas
de acceder a un objetivo (por ejemplo, a través de otro puntero), la declaración de anulación
no desasigna los objetivos. Si también se requiere desasignación, se debe ejecutar una
declaración de desasignación (Sección 6.6).

3.15 Resumen

En este capítulo hemos visto cómo se pueden formar expresiones escalares y de matriz de
tipos numéricos, lógicos, de caracteres y derivados, y cómo se pueden realizar las asignaciones
correspondientes de los resultados. También se han presentado las expresiones relacionales y
el uso de punteros. Ahora tenemos la información requerida para escribir secciones cortas de
código formando una secuencia de declaraciones que se realizarán una tras otra. En el
siguiente capítulo veremos cómo se pueden construir secuencias más complicadas, que
implican ramificación e iteración.

Ejercicios

1. Si todas las variables son escalares numéricos, ¿cuáles de las siguientes son expresiones
numéricas válidas? a + b -c a + -c d + (- f) (a + c) ** (p + q) (a + c) (p + q) - (x + y) ** i 4. ((ad) - (a
+ 4. * x) +1) 2. En las siguientes expresiones, agregue los paréntesis que correspondan a las
reglas de precedencia de Fortran (suponiendo que a, c – f sean escalares reales, i – n son
escalares lógicos yb es una matriz lógica); por ejemplo, a + d ** 2 / c se convierte en a + ((d **
2) / c). c + 4. * f 4. * g-a + d / 2. a ** e ** c ** d a * e-c ** d / a + e i. y. j .or. k .not. l .or. .no. yo
y. m .neqv. n b (3). y.b (1) .o.b (6) .o..no.b (2)

3. ¿Cuáles son los resultados de las siguientes expresiones? 3 + 4/2 6/4/2 3. * 4 ** 2 3. ** 3/2 -
1. ** 2 (-1.) ** 3 4. Ascalarcaractervariable r haslengtheight. ¿Cuáles son los contenidos de una
de las siguientes tareas? r = 'ABCDEFGH' r = 'ABCD' // // '01234' r (: 7) = 'ABCDEFGH' r (: 6) =
'ABCD' 5. ¿Cuál de las siguientes expresiones lógicas son válidas si b es una matriz lógica?
.not.b (1) .and.b (2) .or.b (1) b (1) .or..not.b (4) b (2) (. y.b (3) .or. b (4)) 6. Si todas las variables
son escalares reales, ¿cuál de las siguientes expresiones relacionales son válidas? d <= c p <t> 0
x-1 / = y x + y <3 .or. > 4. d <c.and.3.0 q == r .and. s> t 7. Escribe expresiones para calcular: a) el
perímetro de un cuadrado del lado l; b) el área de un triángulo de base b y altura h; c) el
volumen de una esfera de radio r. 8. Un artículo cuesta n centavos. Escriba una declaración de
declaración para variables adecuadas y declaraciones de asignación que calculen el cambio
que se dará de un billete de $ 1 para cualquier valor de n de 1 a 99, usando monedas de
denominación 1, 5, 10 y 25 centavos.

También podría gustarte