Fortran
The original language of scientific computing.
Fortran (FORmula TRANslation) was the first widely used high-level language, and it is still a leader in numerical computing. Weather forecasts, climate models, physics simulations and the BLAS and LAPACK linear algebra routines inside NumPy and many ML libraries all have deep Fortran roots.
Why learn Fortran?
Supercomputers still run huge amounts of Fortran, and modern Fortran is far cleaner than its reputation suggests.
- Array maths built in: whole-array operations without loops.
- Speed: compilers have optimised Fortran for over 60 years.
- HPC and GPUs: coarrays, OpenMP, OpenACC and CUDA Fortran for parallel work.
Set up and run your first program
Install gfortran (part of GCC). The Fortran Package Manager (fpm) makes projects easy.
sudo apt install gfortran
gfortran hello.f90 -o hello
./helloprogram hello
implicit none
character(len=*), parameter :: name = "Ada"
print *, "Hello, AI! Welcome to Fortran, ", name, "."
end program helloimplicit none so every variable must be declared.Variables and types
Declare variables at the top of a program unit. parameter makes a constant. Use real(8) or the iso_fortran_env kinds for double precision.
program variables
use iso_fortran_env, only: dp => real64
implicit none
integer, parameter :: layers = 32
real(dp) :: params, lr
params = 8.03e9_dp
lr = 3.0e-4_dp
print '(A, I0)', "Layers: ", layers
print '(A, F6.2, A)', "FP16 size: ", params * 2 / 1e9_dp, " GB"
end program variablesControl flow
do loops and if blocks end with end do and end if. select case handles multi-way choices.
program control
implicit none
integer :: epoch, bits
do epoch = 1, 3
print *, "epoch", epoch
end do
bits = 8
select case (bits)
case (32); print *, "FP32"
case (16); print *, "FP16"
case (8); print *, "FP8"
case default; print *, "other"
end select
end program controlArrays: Fortran’s superpower
Arrays are first-class. You can add, multiply and slice whole arrays, and functions like sum, maxval and matmul are built in. Arrays start at index 1 by default.
program arrays
implicit none
real :: x(5) = [1., 2., 3., 4., 5.]
real :: a(2,3), b(3,2), c(2,2)
print *, x * 2 + 1 ! element-wise
print *, sum(x), maxval(x)
print *, x(2:4) ! slice
a = reshape([1.,2.,3.,4.,5.,6.], [2,3])
b = transpose(a)
c = matmul(a, b)
print *, c
end program arraysFunctions, subroutines and modules
Modules group procedures and data. intent(in) and intent(out) document how arguments are used and help the compiler optimise.
module model_math
implicit none
contains
pure function params(layers, width) result(p)
integer, intent(in) :: layers, width
integer(8) :: p
p = 12_8 * layers * int(width, 8)**2
end function params
subroutine relu(x)
real, intent(inout) :: x(:)
where (x < 0) x = 0
end subroutine relu
end module model_math
program main
use model_math
real :: v(4) = [-1., 2., -3., 4.]
print *, params(32, 4096)
call relu(v); print *, v
end program mainParallel loops
do concurrent tells the compiler iterations are independent. With OpenMP (-fopenmp) or nvfortran (-stdpar=gpu) the same loop can run on many cores or a GPU.
program saxpy
implicit none
integer, parameter :: n = 10000000
real, allocatable :: x(:), y(:)
integer :: i
allocate(x(n), y(n))
x = 1.0; y = 2.0
do concurrent (i = 1:n)
y(i) = 2.5 * x(i) + y(i)
end do
print *, y(1), y(n) ! 4.5 4.5
end program saxpy
! gfortran -O3 -fopenmp saxpy.f90 | nvfortran -stdpar=gpu saxpy.f90AI with Fortran
Fortran's biggest AI role is hidden: BLAS and LAPACK, which do matrix maths for NumPy, SciPy and many ML libraries, began in Fortran. Scientists now combine Fortran simulations with neural networks, for example ML-based physics in weather and climate models, using libraries like neural-fortran or calling PyTorch models through FTorch.
The essential libraries
Gradient descent from scratch
Fit y = 3x + 0.5 with whole-array operations, no inner loops needed.
program gradient
implicit none
integer, parameter :: n = 100
real :: x(n), y(n), err(n), w = 0, b = 0, lr = 0.1
integer :: i, step
x = [(-1.0 + 2.0 * (i - 1) / (n - 1), i = 1, n)]
y = 3 * x + 0.5
do step = 1, 500
err = w * x + b - y
w = w - lr * 2 * sum(err * x) / n
b = b - lr * 2 * sum(err) / n
end do
print '(A, F5.2, A, F5.2)', "w = ", w, " b = ", b
end program gradientFortran as an AI agent tool
The practical way to put Fortran in an agent is to wrap a fast Fortran routine with f2py and let a Python agent call it as a tool, which is exactly how scientific codes are joined to LLM tools today.
# physics.f90 -> python -m numpy.f2py -c physics.f90 -m physics
# subroutine projectile(v, angle, dist)
# real(8), intent(in) :: v, angle
# real(8), intent(out) :: dist
# dist = v**2 * sin(2 * angle * 3.141592653589793d0 / 180) / 9.81d0
# end subroutine
import json, physics
from openai import OpenAI
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
tools = [{"type": "function", "function": {"name": "projectile", "description": "Range in metres of a projectile",
"parameters": {"type": "object", "properties": {"v": {"type": "number"}, "angle": {"type": "number"}},
"required": ["v", "angle"]}}}]
messages = [{"role": "user", "content": "How far does a ball launched at 20 m/s and 45 degrees travel?"}]
for _ in range(5):
msg = client.chat.completions.create(model="llama3.1", messages=messages, tools=tools).choices[0].message
messages.append(msg)
if not msg.tool_calls:
print(msg.content); break
for c in msg.tool_calls:
dist = physics.projectile(**json.loads(c.function.arguments))
messages.append({"role": "tool", "tool_call_id": c.id, "content": f"{dist:.2f} m"})f2py turns the intent(out) argument into a return value, so the call returns the distance directly.
ollama pull llama3.1, and keep it running. The code talks to its OpenAI-compatible API at http://localhost:11434/v1, so the same program also works with vLLM, llama.cpp server or a cloud API by changing the URL, model name and adding an API key.Fortran learning roadmap
Tick items off as you go. Your progress is saved in this browser.
Beginner
Intermediate
Advanced
Projects to build
Fortran cheat sheet
| Task | Syntax |
|---|---|
| Declare | integer :: n |
| Constant | real, parameter :: pi = 3.14159 |
| Loop | do i = 1, n ... end do |
| Array op | y = 2*x + 1 |
| Slice | x(2:5) |
| Matmul | c = matmul(a, b) |
Common mistakes
- Forgetting
implicit nonemakes variables starting with i–n integers automatically. - Arrays are 1-indexed and stored column-major (the opposite of C and NumPy's default).
- Old fixed-form code (.f, columns 7–72) looks very different from modern free-form (.f90).
Where to go next
- fortran-lang.org — official tutorials
- Fortran Package Manager — build tool
- Fortran Discourse — community
On TensorCore.si: C volume, Julia volume.
Keyboard: [ previous language · ] next language · / search the library