I got a phonecall from a physicist friend of mine today asking if I knew Fortran. “Uhm, no,” I replied, somewhat astonished. “I’ve never learned that.”
And I haven’t. Most people haven’t. And there’s a good reason for that. In the words of Edsger Dijkstra, “FORTRAN, the infantile disorder, by now nearly 20 years old, is hopelessly inadequate for whatever computer application you have in mind today: it is now too clumsy, too risky, and too expensive to use.”
But physicists use it a lot. Why? When I asked once, the answer I got was that Fortran was simply faster than any other language. “No,” I replied pointedly. It just isn’t true.
Fortran compiles down to native code much like C. Which means that fundamentally Fortran follows the same speed restrictions as C. Yes, not all compilers are as good as optimization, but that’s not a real issue.
A more important thing to recognize is Moore’s law and that it doesn’t really matter all that much any more which language you use. Yes, sure, fine, you’ll get your results a bit quicker using C than Java, but for most intents and purposes most languages are equal - although I still prefer using C for anything time-critical than Python, for example, which I use for almost everything else.
The thing about Fortran is it takes an age to make anything in it. The syntax is archaic and unintuitive and the language is stuck with 30 year old computer science concepts, most of which have long been exchanged for something better.
Consider for a moment a typical task for a Physicist: Calculating the value of exp(i*pi/2) and printing it out
Fortran (I wrote this myself after having consulted some examples on the net, it might be slightly wrong or overly complicated):
PROGRAM EXPCOMPLEXPIDIV2 IMPLICIT COMPLEX(X)
PARAMETER (PI = 3.141592653589793, XI = (0, 1))
X = EXP(XI * PI / 2)
IF (AIMAG(X).LT.0) THEN
PRINT 2, 'e**(i*pi/2) = ', REAL(X), ' - i', AIMAG(X)
ELSE
PRINT 2, 'e**(i*pi/2) = ', REAL(X), ' + i', AIMAG(X)
END IF
END
Python equivalent:
from math import *
print "e**(i*pi/2) = %s" % (e**(1j*pi/2))
Let’s consider a more complicated example, solving a system of linear equations, Ax=b. (Copied from Wikibooks; I don’t know Fortran, remember!)
function GaussSparse(NumIter, Tol, b, A, X, ActualIter)
implicit none
real GaussSparse
integer, intent(in) :: NumIter
real, intent(in) :: Tol
real, intent(in), dimension(1:) :: b
real, intent(in), dimension(1:,1:) :: A
real, intent(inout), dimension(1:) :: X
integer, optional, intent(out) :: ActualIter
integer i, n, Iter
real TolMax, Xk
n = ubound(b, dim = 1)
TolMax = 2. * Tol
Iter = 0 convergence_loop: do while (TolMax >= Tol.AND.Iter < NumIter); Iter = Iter + 1
TolMax = -1.
iteration_loop: do i = 1, n
Xk = (b(i) - sum(A(i,1:i-1) * X(1:i-1)) - sum(A(i,i+1:n) * X(i+1:n))) / A(i, i)
TolMax = max((abs(X(i) - Xk)/(1. + abs(Xk))) ** 2, abs(A(i, i) * (X(i) - Xk)), TolMax)
X(i) = Xk
enddo iteration_loop
enddo convergence_loop
if (present(ActualIter)) ActualIter = Iter
GaussSparse = TolMax
end function GaussSparse
And in Python, here’s the same (alas, not for a sparse matrix):
from numarray import dotdef gauss(A,b):
n = len(b)
for i in range(0,n-1):
for j in range(i+1,n):
if a[j,i] != 0.0:
lam = A[j,i]/A[i,i]
A[j,i+1:n] = A[j,i+1:n] - lam*A[i,i+1:n]
b[j] = b[j] - lam*b[i]
for i in range(n-1,-1,-1):
b[i] = (b[i] - dot(A[i,i+1:n],b[i+1:n]))/A[i,i]
return b
Nowadays, speed of development is more important than speed of execution because we can almost always just toss more computer at the problem - manpower costs more. This does not mean we can allow ourselves to be sloppy or to use overly heavy algorithms complexity wise, and we must still obey the laws of nature - which enforces bandwidth restrictions and convolution of data transmission functions over time (which we generally simply call lag), but it does mean that the idea that writing Fortran code will save you some time in the long run is simply wrong.
So to physicists (and those three other people who use Fortran) I say:
- Learn Python, C++, or some other language that has at least some modern features.
- Learn some complexity theory and get a good feeling for algorithm optimization - nowadays I can generally eyeball c.a. the big-O complexity of an algorithm with a fair degree of correctness. You should be able to work it out for yourself with little hassle.
- Extra credit: is the Python version of the Gauss function faster or slower than the Fortran version?*
(*Answer: Without actually having calculated it, it seems to me that the Python version is roughly O(n log(n)), the Fortran version is roughly O(n²). Fortran code may run faster, but algorithm complexities are a lot more important than CPU cycles!)