[ anterior ] [ Contenidos ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 12 ] [ 13 ] [ siguiente ]
Fortran 90
para la asignatura Química Computacional
Los objetivos de esta clase son los siguientes:
presentar las diferentes estructuras de control condicionales en
Fortran
(branching).
presentar las diferentes formas de ejecutar bucles en programas
Fortran
(loops).
Estas estructuras de control son básicas para dominar el flujo de un programa, permitiendo que la ejecución del programa pueda depender de los datos implicados o de la decisiones del usuario que lo corra.
Es importante tener en cuenta que para cualquier proyecto medianamente complejo
es preciso tener una idea clara del problema, de los inputs y outputs del mismo
y del algoritmo que se utilizará, así como de la estructura del programa que se
llevará a cabo como un diagrama de flujo o como pseudocódigo antes de comenzar
a escribir el código Fortran
.
Los problemas complejos deben dividirse en tareas más simples, y si es necesario estas se subdividirán en otras tareas aún más simples (top-down design) y cada una de estas tareas debe codificarse y comprobarse de forma independiente.
Daremos de forma esquemática el formato que tienen las estructuras de control. En primer lugar las condicionales y en segundo lugar los bucles.
Estructuras condicionales.
Todas estas estructuras dependen de la evaluación de condiciones lógicas. Estas condiciones se establecen mediante los operadores relacionales siguientes:
== Ser igual a.
/= No ser igual a.
> Mayor que.
< Menor que.
>= Mayor o igual que.
<= Menor o igual que.
También es posible utilizar operadores lógicos para combinar diferentes condiciones. Los operadores lógicos son
.AND. Operador Y lógico.
.OR. Operador O lógico.
.NOT. Operador NO lógico.
.EQV. Operador '==' lógico.
.NEQV. Operador '/=' lógico.
Los diferentes condicionales posibles son los siguientes.
IF THEN ENDIF
La forma de este condicional es la siguiente
. . codigo . IF (cond logica) THEN . . bloque_1 . ENDIF . . codigo .
Solamente si se cumple la condición lógica impuesta se ejecutan las instrucciones en bloque_1, si no se cumple son ignoradas.
En caso de que sea únicamente una la instrucción ejecutada si se cumple la condición lógica se puede simplificar la orden eliminando THEN y ENDIF del siguiente modo
. . codigo . IF (cond logica) instruccion . . codigo .
IF THEN ELSE ENDIF
La forma de este condicional es la siguiente
. . codigo . IF (cond logica) THEN . . bloque_1 . ELSE . . bloque_2 . ENDIF . . codigo .
Si se cumple la condición lógica impuesta se ejecutan las instrucciones en bloque_1, si no se cumple se ejecuta el bloque bloque_2.
IF THEN ELSE IF ENDIF
La forma de este condicional es la siguiente
. . codigo . IF (cond logica_1) THEN . . bloque_1 . ELSE IF (cond logica_2) THEN . . bloque_2 . ENDIF . . codigo .
Si se cumple la condición lógica cond logica_1 se ejecutan las instrucciones en bloque_1; si no se cumple, pero sí se cumple la condición lógica cond logica_2, entonces se ejecuta el bloque bloque_2.
IF THEN ELSE IF ELSE ENDIF
La forma de este condicional es la siguiente
. . codigo . IF (cond logica_1) THEN . . bloque_1 . ELSE IF (cond logica_2) THEN . . bloque_2 . ELSE . . bloque_3 . ENDIF . . codigo .
Si se cumple la condición lógica cond logica_1 se ejecutan las instrucciones del bloque_1; si no se cumple, pero sí se cumple la condición lógica cond logica_2, entonces se ejecuta el bloque bloque_2. Si ninguna de las dos condiciones lógicas son ciertas, entonces se ejecuta el código en el bloque bloque_3.
SELECT CASE
La orden CASE permite escoger una opción entre diferentes posibilidades de forma más eficiente, clara y elegante que las estructuras de control anteriores.
La forma de este condicional es la siguiente
SELECT CASE (selector) CASE (label-1) bloque-1 CASE (label-2) bloque-2 CASE (label-3) bloque-3 ............. CASE (label-n) bloque-n CASE DEFAULT bloque-default END SELECT
En esta orden selector es una variable o una expresión cuyo resultado es del tipo entero, lógico o carácter. En concreto no puede ser una variable ni una expresión que dé como resultado un número real.
En esta orden label-1 hasta label-n son listas de etiquetas, separadas por comas, que deben tener una de las siguientes formas:
valor valor-1 : valor-2 valor-1 : : valor-2
La primera indica el valor valor, la segunda un valor comprendido entre valor-1 y valor-2, la tercer un valor mayor que valor-1y la última un valor menor que valor-2. Tanto valor como valor-1 y valor-2 deben ser constantes o alias definidos por una orden PARAMETER.
Como se ejecuta esta orden es evaluando selector. Se compara el resultado con los valores establecidos en cada una de las listas de etiquetas, ejecutando el bloque correspondiente a la primera de las comparaciones que resulte exitosa. Si ninguna comparación es exitosa se ejecuta -caso de que exista- el bloque-default. Tras ello se prosigue ejecutando las órdenes que existan tras el END SELECT.
Por ejemplo
SELECT CASE (I) CASE (1) PRINT*, "I = 1" CASE (2:9) PRINT*, "I in [2,9]" CASE (10:) PRINT*, "I in [10,INF]" CASE DEFAULT PRINT*, "I is negative" END SELECT CASE
La orden SELECT CASE es más eficiente que una combinación de IF's porque una sola expresión controla las diferentes alternativas.
Los condicionales == y /= no deben usarse con expresiones del tipo real, ya que estas son aproximadas. Así, si A y B son variables reales, no debe usarse
... IF (A==B) same = .TRUE. ...
Para evitar esto debe definirse una tolerancia y utilizar algo como
REAL :: TOL = 0.00001 ... IF (ABS(A-B) < TOL) same = .TRUE. ...
Estas estructuras de control condicionales pueden anidarse en varios niveles. En este caso es interesante a veces etiquetar los bucles para lograr una mayor claridad en el código, como en el siguiente caso
primerif: IF (a == 0) THEN PRINT*, "a is zero" IF (c /= 0) THEN PRINT*, "a is zero and c is not zero" ELSE PRINT*, "a and c are zero" ENDIF ELSEIF (a > 0) THEN primerif PRINT*, "a is positive" ELSE primerif PRINT*, "a is negative" ENDIF primerif
La etiqueta primerif simplemente trata de hacer el código más claro, sin jugar ningún otro papel. Si la etiqueta se define en el IF, entonces ha de estar presente en el ENDIF, aunque en las instrucciones ELSE y ELSEIF sea opcional. Puede haber tantos condicionales anidados como se desee.
En el ejemplo Programa ejemplo_5_1.f90, Sección 5.3.1 puede verse una aplicación de la estructura IF THEN ELSE IF ELSE ENDIF y en el ejemplo Programa ejemplo_5_2.f90, Sección 5.3.2 como se lleva a cabo, aparentemente, la misma tarea con una aplicación de la estructura CASE.
Bucles y comandos de utilidad en bucles
Primera forma de bucle (loop) con el comando DO
Ya conocemos una forma de formar bucles con la orden DO.
DO Var = vinicial, vfinal, incremento bloque de instrucciones END DO
Con esta forma la variable Var toma el valor inicial y se va incrementando en inc hasta que alcanza el valor vfinal. Cada vez se ejecuta el bloque de instrucciones limitado por el final del bloque marcado por el ENDDO. Por ejemplo, en el ejemplo Programa ejemplo_5_3.f90, Sección 5.3.3 se imprime el seno y coseno para una circunferencia completa dividida en octantes.
Segunda forma de bucle (loop) con el comando DO
Esta segunda forma, con el esquema siguiente, se conoce como un bucle WHILE
DO WHILE (expresion logica) bloque de instrucciones ENDDO
En este caso el bloque de instrucciones se ejecuta mientras que la expresión lógica en la cabecera del bucle sea cierta. Por ejemplo, en el programa Programa ejemplo_5_4.f90, Sección 5.3.4 se calculan aproximaciones sucesivas al SIN(X) usando la fórmula del desarrollo de Taylor de esta función, avanzando un grado en el desarrollo hasta que el usuario introduzca un cierto valor (cero en este caso).
Tercera forma de bucle (loop) con el comando DO
Esta forma es la conocida como un bucle del tipo REPEAT UNTIL. El esquema es el siguiente.
DO bloque de instrucciones IF (expresion logica) EXIT END DO
El bloque de instrucciones se repite hasta que se cumpla la expresión lógica en el IF. En este caso, a diferencia de los dos anteriores, siempre se ejecuta al menos una vez el bloque de instrucciones. En los otros dos casos puede no llegar a ejecutarse el bloque de instrucciones ni una sola vez.
En este caso se hace uso de la orden EXIT. Cuando se ejecuta esta orden el flujo del programa abandona el bucle y continúa en la orden siguiente al ENDDO que marca el final del bucle. Otra orden interesante cuando se trabaja con bucles es la orden CYCLE. Cuando se ejecuta esta orden se vuelve al principio del bucle, y no se ejecutan las órdenes que se hallen entre su posición y el final del bucle en esa iteración. Como en el caso de los condicionales, los diferentes bucles anidados pueden etiquetarse, lo que permite indicar a qué bucle en concreto se refiere la orden EXIT o CYCLE. Por defecto, sin usar etiquetas, se refieren al último bucle.
En el Programa ejemplo_5_5.f90, Sección 5.3.5 se
combinan varias de las instrucciones de FORTRAN
descritas en esta
sección. Este programa lee un fichero de datos (que se encuentra comentado más
abajo del programa, basta con cortar, pegar y eliminar los '!').
Al abrir el fichero con OPEN el programa se asegura de que sea un
fichero existente y solo de lectura (STATUS = 'OLD' y
ACTION='READ'). Comienza a leer el fichero y salta una serie de
lineas, en un bucle del tipo REPEAT UNTIL, hasta llegar a una
línea en la que se proporciona el número de puntos en el fichero[7].Tras ello lee los puntos y los
almacena en los vectores X e Y, calculando el máximo
valor de X y el mínimo valor de Y. Para llevar a
cabo este cálculo usa las funciones intrínsecas MAXVAL y
MINVAL (ver Objetivos, Sección
8.1).
Existe una última orden, cuyo uso no se fomenta ya que no está de acuerdo con los principios de programación estructurada, la orden GOTO.
PROGRAM EJEMPLO_5_1 ! IMPLICIT NONE ! REAL :: NOTA CHARACTER (3), DIMENSION(1:5) :: NT, LISTNT=(/'S','A','N','Sob','MH'/) INTEGER :: IN ! READ NOTE PRINT *, "Nota del estudiante?" READ 50, Nota 50 FORMAT(F4.1) ! IF (Nota>=0.0.AND.Nota<5.0) THEN IN=1 ELSE IF (Nota>=5.0.AND.Nota<7.0) THEN IN=2 ELSE IF (Nota>=7.0.AND.Nota<9.0) THEN IN=3 ELSE IF (Nota>=9.0.AND.Nota<10.0) THEN IN=4 ELSE IF (Nota==10.0) THEN IN=5 ELSE IN=0 ENDIF ! IF (IN==0) THEN PRINT *, "LA NOTA : ", Nota," NO ES UNA NOTA ACEPTABLE." ELSE PRINT 100, Nota, LISTNT(IN) ENDIF ! 100 FORMAT(1X,'LA NOTA DEL ALUMNO ES ',F4.1,' (',A3,')') ! END PROGRAM EJEMPLO_5_1
PROGRAM EJEMPLO_5_2 IMPLICIT NONE REAL :: Nota INTEGER :: IN, Inota CHARACTER (3), DIMENSION(1:5) :: LISTNT=(/'S','A','N','Sob','MH'/) ! READ NOTE PRINT *, "Nota del estudiante?" READ(*,*), Nota ! Inota = NINT(Nota) ! SELECT CASE (Inota) CASE (0:4) IN = 1 CASE (5,6) IN = 2 CASE (7,8) IN = 3 CASE (9) IN = 4 CASE (10) IN = 5 CASE DEFAULT IN = 0 END SELECT ! IF (IN==0) THEN PRINT *, "LA NOTA : ", Nota," NO ES UNA NOTA ACEPTABLE." ELSE PRINT 100, Nota, LISTNT(IN) ENDIF ! 100 FORMAT(1X,'LA NOTA DEL ALUMNO ES ',F4.1,' (',A3,')') ! END PROGRAM EJEMPLO_5_2
PROGRAM EJEMPLO_5_3 ! IMPLICIT NONE ! REAL :: Pio2 = ASIN(1.0) REAL :: Angle1 = 0.0, Angle2 = 0.0 INTEGER :: index ! DO index = 0, 16, 2 Angle1 = index*Pio2/4.0 ! WRITE(*,*) WRITE(*,*) 'Cos(',index/2,'Pi/4) = ',COS(Angle1),'; Cos(',index/2,'Pi/4) = ',COS(Angle2) WRITE(*,*) 'Sin(',index/2,'Pi/4) = ',SIN(Angle1),'; Sin(',index/2,'Pi/4) = ',SIN(Angle2) WRITE(*,*) ! Angle2 = Angle2 + Pio2/2.0 ! ENDDO END PROGRAM ejemplo_5_3
PROGRAM ejemplo_5_4 ! IMPLICIT NONE ! REAL :: X_val = 0.0 REAL :: X_app = 0.0, X_sum = 0.0 INTEGER :: I_flag = 1, I_count = 0 ! ! APROXIMACIONES SUCESIVAS A SIN(X) = X - X^3/3! + X^5/5! - X^7/7! + ... WRITE(*,*) "INTRODUZCA EL VALOR DEL ANGULO X (RAD) :" READ(*,*) X_val ! I_count = 1 X_app = X_val X_sum = X_val ! WRITE(*,*) ' ORDEN APROX SIN(X) APPROX-SIN(X)' DO WHILE (I_flag == 1) WRITE(*,*) I_count, X_app, SIN(X_val), X_app - SIN(X_val) ! X_sum = X_sum*(-1)*X_val*X_val/((I_count*2+1)*(I_count*2)) X_app = X_app + X_sum ! I_count = I_count + 1 ! WRITE(*,*) "STOP? (0 SI, 1 NO)" READ(*,*) I_flag IF (I_flag /= 1 .AND. I_flag /= 0) I_flag = 1 ! ENDDO END PROGRAM ejemplo_5_4
PROGRAM ej_5_5 ! IMPLICIT NONE REAL , DIMENSION(:), ALLOCATABLE :: X_vec, Y_vec INTEGER :: Index, Ierr, Numpoints = 0 REAL :: Max_x, Min_y CHARACTER(LEN=64) :: Filename ! ! READ FILENAME READ(5,*) Filename ! OPEN FILE OPEN( UNIT=10, FILE=Filename, STATUS='OLD', ACTION='READ' ) ! DO READ(UNIT=10, FMT=100, ERR=10) Numpoints IF (Numpoints /= 0) EXIT 10 READ (UNIT=10, FMT=*) ! JUMP ONE LINE CYCLE ENDDO ! PRINT*, 'NUMPOINTS = ', Numpoints ! ! ALLOCATE X, Y VECTORS ALLOCATE(X_vec(1:NUMPOINTS), STAT = IERR) IF (Ierr /= 0) STOP 'X_vec MEM ALLOCATION FAILED' ALLOCATE(Y_vec(1:NUMPOINTS), STAT = IERR) IF (Ierr /= 0) STOP 'Y_vec MEM ALLOCATION FAILED' ! DO I = 1, Numpoints ! READ(UNIT=10, FMT=110) X_vec(I), Y_vec(I) ! ENDDO ! Max_x = MAXVAL(X_vec) Min_y = MINVAL(Y_vec) ! PRINT*, "MAXIMUM X VALUE = ", Max_x PRINT*, "MINIMUM Y VALUE = ", Min_y ! DEALLOCATE AND CLOSE FILE DEALLOCATE(X_vec, STAT = IERR) IF (Ierr /= 0) STOP 'X_vec MEM DEALLOCATION FAILED' DEALLOCATE(Y_vec, STAT = IERR) IF (Ierr /= 0) STOP 'Y_vec MEM DEALLOCATION FAILED' ! CLOSE(10) ! FORMAT STATEMENTS 100 FORMAT(19X,I3) 110 FORMAT(F6.3,1X,F6.3) ! END PROGRAM ej_5_5 !# Remark 1 !# Remark 2 !Useless line 1 !Useless line 2 !Number of points = 4 !+1.300;-2.443 !+1.265;-1.453 !+1.345;-8.437 !+1.566;+4.455
[ anterior ] [ Contenidos ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 12 ] [ 13 ] [ siguiente ]
Lecciones de Fortran 90
para la asignatura Química Computacional
mailto:francisco.perez@dfaie.uhu.es