cv.cm

Programación · Lenguajes de programación

Tutorial de Fortran para principiantes

7 min de lectura

Respuesta corta

Fortran es un lenguaje compilado y de tipado estático creado para el cálculo numérico y científico. El Fortran moderno (Fortran 90 y los estándares posteriores) tiene código fuente de formato libre, módulos, arreglos dinámicos y potentes operaciones sobre arreglos completos, y los compiladores lo convierten en código máquina muy rápido. Instala el compilador gratuito gfortran, guarda el código en un archivo .f90 y compílalo con gfortran hello.f90 -o hello.

Qué es Fortran y quién lo usa

Fortran («formula translation») lo desarrolló en IBM un equipo dirigido por John Backus en la década de 1950 y es uno de los lenguajes de programación más antiguos que siguen en uso activo. Está estandarizado por ISO; entre las revisiones principales están Fortran 90, 95, 2003, 2008, 2018 y 2023. El antiguo estilo de formato fijo (FORTRAN 77 en mayúsculas, con el código empezando en la columna 7) todavía se compila, pero el código nuevo usa la sintaxis de formato libre que se muestra aquí.

Fortran se usa donde importa el cálculo numérico intensivo: modelos del tiempo y del clima, dinámica de fluidos computacional, simulaciones de física y química, y muchos programas que se ejecutan en supercomputadoras. Las versiones de referencia de las bibliotecas de álgebra lineal BLAS y LAPACK, que se usan por debajo de herramientas como NumPy y MATLAB, están escritas en Fortran.

Instala un compilador y ejecuta Hola, mundo

gfortran, parte de GCC, es gratuito y está disponible en Linux (paquete gfortran), macOS (gcc de Homebrew) y Windows (MSYS2 o WSL). ifx de Intel y LLVM Flang son otros compiladores. El Fortran Package Manager (fpm) puede crear y compilar proyectos.

program hello
  implicit none
  print *, "Hello, world!"
end program hello
gfortran hello.f90 -o hello
./hello
#  Hello, world!

print * usa salida dirigida por lista, que elige el espaciado por ti (fíjate en el espacio inicial). Fortran no distingue mayúsculas de minúsculas: PRINT, Print y print son lo mismo.

Variables y tipos básicos

Todas las declaraciones van al principio de una unidad de programa, antes de las instrucciones ejecutables. Escribe siempre implicit none: sin ello, los nombres no declarados que empiezan por I a N son enteros de forma silenciosa y todos los demás son reales.

TipoDeclaración de ejemploNotas
integerinteger :: count = 3Normalmente de 32 bits; integer(int64) para 64 bits
realreal :: xNormalmente de precisión simple
real(real64)real(real64) :: yDoble precisión, la opción habitual en ciencia
complexcomplex :: z = (1.0, 2.0)Números complejos integrados
logicallogical :: done = .false..true. / .false., operadores .and., .or., .not.
charactercharacter(len=20) :: nameCadena de longitud fija, rellenada con espacios
program types
  use, intrinsic :: iso_fortran_env, only: int64, real64
  implicit none
  integer :: count = 3
  integer(int64) :: big = 9000000000_int64
  real(real64) :: third
  logical :: done = .false.
  character(len=:), allocatable :: name

  third = 1.0_real64 / 3.0_real64
  name = "Ana"
  print *, count, big, third, done, name
end program types

El sufijo _real64 establece el kind (precisión) de un literal. Sin él, 1.0 es una constante de precisión simple, que pierde dígitos al asignarse a una variable de doble precisión.

Control de flujo

program control
  implicit none
  integer :: i, total, score

  total = 0
  do i = 1, 10
    if (mod(i, 2) == 0) cycle   ! skip even numbers
    total = total + i
  end do
  print *, "sum of odd numbers:", total   ! 25

  score = 85
  if (score >= 90) then
    print *, "A"
  else if (score >= 80) then
    print *, "B"
  else
    print *, "C"
  end if

  select case (score)
  case (90:)
    print *, "excellent"
  case (80:89)
    print *, "good"
  case default
    print *, "keep going"
  end select
end program control

do i = 1, 10 incluye ambos extremos, y un tercer valor opcional establece el paso (do i = 10, 1, -1). cycle salta a la siguiente iteración y exit sale del bucle. También están disponibles do while (condition) y un do simple con exit. Los comentarios empiezan con !.

Funciones, subrutinas y módulos

Fortran tiene dos tipos de procedimientos: una función devuelve un valor y se usa en expresiones; una subrutina se llama con call y devuelve resultados mediante sus argumentos. Pon los procedimientos en un módulo para que el compilador pueda comprobar cada llamada.

module geometry
  implicit none
contains
  function circle_area(r) result(a)
    real, intent(in) :: r
    real :: a
    a = 3.14159 * r**2
  end function circle_area

  subroutine swap(a, b)
    integer, intent(inout) :: a, b
    integer :: tmp
    tmp = a
    a = b
    b = tmp
  end subroutine swap
end module geometry

program demo
  use geometry
  implicit none
  integer :: x, y
  x = 1
  y = 2
  print *, circle_area(2.0)   ! about 12.566
  call swap(x, y)
  print *, x, y               ! 2 1
end program demo

Los argumentos se pasan por referencia, así que un procedimiento puede cambiar las variables de quien lo llama. intent(in), intent(out) e intent(inout) documentan y hacen cumplir lo que puede hacer cada argumento. ** es el operador de potencia.

Arreglos: la característica distintiva de Fortran

Los arreglos son centrales en Fortran. Los índices empiezan en 1 por defecto (se permite cualquier límite inferior), la aritmética funciona sobre arreglos completos sin bucles, los slices usan a(start:end) y muchas funciones intrínsecas operan directamente sobre arreglos.

program arrays
  implicit none
  integer :: i
  real :: a(5), b(5)
  real, allocatable :: c(:)
  integer :: m(2, 3)

  a = [(real(i), i = 1, 5)]   ! 1.0 2.0 3.0 4.0 5.0
  b = 2.0 * a + 1.0           ! whole-array arithmetic
  print *, b(2:4)             ! 5.0 7.0 9.0
  print *, sum(a), maxval(b)  ! 15.0 11.0

  allocate(c(10))
  c = 0.0
  print *, size(c)            ! 10
  deallocate(c)

  m = reshape([1, 2, 3, 4, 5, 6], [2, 3])
  print *, m(2, 1)            ! 2 (column-major order)
end program arrays

Los arreglos multidimensionales se almacenan en orden de columnas: el primer índice cambia más rápido en memoria, lo contrario que en C. Para ir más rápido, haz que el bucle más interno recorra el primer índice. Otras funciones intrínsecas útiles son matmul, dot_product, transpose, minval y count. El Fortran moderno ofrece además bucles do concurrent y coarrays para programas paralelos.

Manejo de errores

Fortran no tiene excepciones. Las instrucciones que pueden fallar aceptan un argumento de estado: iostat para entrada y salida, stat para allocate. Comprueba el valor y reacciona; si lo omites, un error detiene el programa. error stop termina el programa con un error.

program parse
  implicit none
  character(len=20) :: text
  integer :: n, ios

  text = "abc"
  read(text, *, iostat=ios) n
  if (ios /= 0) then
    print *, "not a number: ", trim(text)
  else
    print *, "n =", n
  end if
end program parse

Leer de una variable de tipo carácter, como arriba, se llama lectura interna y es la forma habitual de convertir una cadena en un número.

Un programa pequeño y completo: media y desviación estándar

module stats
  implicit none
  integer, parameter :: dp = kind(1.0d0)
contains
  pure function mean(x) result(m)
    real(dp), intent(in) :: x(:)
    real(dp) :: m
    m = sum(x) / size(x)
  end function mean

  pure function std_dev(x) result(s)
    real(dp), intent(in) :: x(:)
    real(dp) :: s
    s = sqrt(sum((x - mean(x))**2) / (size(x) - 1))
  end function std_dev
end module stats

program main
  use stats
  implicit none
  real(dp) :: values(5)
  values = [2.0_dp, 4.0_dp, 4.0_dp, 5.0_dp, 7.0_dp]
  print '(a, f6.3)', "mean    = ", mean(values)
  print '(a, f6.3)', "std dev = ", std_dev(values)
end program main
! mean    =  4.400
! std dev =  1.817

La declaración x(:) es un arreglo de forma supuesta, por lo que las funciones aceptan arreglos de cualquier longitud. pure promete que una función no tiene efectos secundarios. El formato '(a, f6.3)' imprime una cadena seguida de un número real de 6 caracteres de ancho con 3 decimales.

Siguientes pasos

  • fortran-lang.org: la sección Learn, con un tutorial de inicio rápido y buenas prácticas.
  • El manual de GNU Fortran (gfortran), para las opciones del compilador y los procedimientos intrínsecos.
  • Prueba el Fortran Package Manager (fpm) para crear proyectos y usar bibliotecas como la biblioteca estándar de Fortran (stdlib).
  • Compila con advertencias y comprobaciones en tiempo de ejecución mientras aprendes, por ejemplo gfortran -Wall -fcheck=all.

Preguntas frecuentes

¿Fortran se sigue usando hoy?

Sí. Fortran sigue muy usado en computación científica y de alto rendimiento, sobre todo en simulaciones de clima, tiempo, física e ingeniería, y el estándar del lenguaje se sigue actualizando.

¿Cuál es la diferencia entre los archivos .f y .f90?

Por convención, los archivos .f y .for usan el antiguo formato fijo de FORTRAN 77, en el que las columnas importan, mientras que los archivos .f90 usan código fuente de formato libre. La extensión .f90 se usa para código de formato libre de cualquier estándar moderno, no solo de Fortran 90.

¿Por qué Fortran es rápido?

El lenguaje se diseñó para el trabajo numérico: los arreglos están integrados, las reglas de aliasing permiten a los compiladores optimizar de forma agresiva y décadas de trabajo en compiladores lo respaldan. Un C o C++ bien escrito puede alcanzar una velocidad similar.

¿Los arreglos de Fortran empiezan en 0 o en 1?

Empiezan en 1 por defecto, pero puedes elegir cualquier límite inferior; por ejemplo, real :: a(0:9) declara diez elementos indexados de 0 a 9.

Todos los tutoriales de programación