Fortran Programming Language Analysis By Chad Marshall
1. Authors
In December of 1953, John Backus proposed his idea of a programming language that could cut the cost of programming and debugging to his superior, Cuthbert Hurd at IBM (Backus 1998).
2. Creation Date
The Programming Research group (PRG) distributed the Fortran Automatic Coding System was distributed to many institutions in April of 1957 (Backus 1998).
3. Features
At inception, Fortran offered I/O statements, functions, expressions, subscripts, assignment statements, and DO formulas. Specification sentences like dimension, equivalence, frequency, and relative constant sentences are listed in a paper by Backus’ team called Preliminary Report in November of 1954 (Backus 1998). An example of a DIMENSION statement can be found in Example Programs. This section of the Preliminary Report also listed features to be added including complex and double precision arithmetic, matrix arithmetic, sorting, and differential equations to name a few. Matrix arithmetic can be seen in the example referenced above (PRG, 1954).
4. Design Goals
Backus’ goal when developing Fortran was to create a programming language where the proceeds gained from a programmer’s salary would outweigh the cost of timesharing a computer which in turn would bring profit. In a time where Moore’s law predicted that transistors on a chip are doubled and the cost of computers is halved, a language must compile, execute, and be written quickly. To accomplish this, Backus admits that his team focused on these three attributes above over language design. The language design is noted as casual and was developed along the way. In fact, the design of the compiler on the IBM 704 became the true challenge of the team (Backus 1998).
5. Applications
For the most part of the twenty first century, legacy Fortran has been rewritten to modern Fortran and modern Fortran has been rewritten to C based languages like C++. That said, there are still a few applications, specifically in the realm of physics, that use modern Fortran.
5.1 SIESTA
The open source program called SIESTA performs efficient electronic structure calculations and ab initio molecular dynamic simulations of molecules and solids by using a basis set of strictly-localized atomic orbitals (SIESTA group, 2020). Since the advent of parallelization through Open MPI in modern Fortran, the SIESTA team has been building and maintaining this robust simulator which has thousands of users worldwide.
For more information on Open MPI, please visit
5.2 FLASH
FLASH is an adaptive mesh hydrodynamics code for modeling astrophysical thermonuclear flashes. Adaptive Mesh Refinement is done through Fortran 90’s PARAMESH package. PARAMESH does this by extending the serial code that uses a locally Cartesian structured mesh into a parallel code with Adaptive Mesh Refinement (Fryxell, 2000).
For more information on PARAMESH, please visit
https://opensource.gsfc.nasa.gov/projects/paramesh/index.php
6. Example Programs – All example programs can be found in the Fortran folder in my tt084 directory
6.1. 2D Array (twoDarray.f90)
6.1.1. Use of DIMENSION sentence from Preliminary Report
6.1.2. N-dimensional array in Fortran can be populated with a single assignment with a loop inline at array initialization. In C-based languages, populating with a loop must be done with assignment coming second after looping.
PROGRAM main INTEGER :: row, col INTEGER, DIMENSION(2, 3):: array array = transpose(reshape((/(I, I = 1, 10)/), &
(/ size(array, 2), size(array, 1) /))) do row = 1, 2 write(*,*) ( array(row, col), col = 1, 3) end do END PROGRAM main |
Figure 6.1 2D Array |
6.2. Recursion of Legacy Fortran (recur.f)
6.2.1. Shows attempted recursion in legacy Fortran
6.2.2. In early Fortran compilers, this error may not have been caught. A standardized form of recursion was introduced in Fortran 90 in 1991. Unstandardized versions of recursion have been implemented prior with some compilers of Fortran 77.
PROGRAM RECUR C WHY RECURSION FAILS IN FORTRAN INTEGER A, B, C INTEGER RSUM DATA A,B/2,5/ C = RSUM(A,B) END INTEGER FUNCTION RSUM(X,Y) INTEGER X,Y,S PRINT *, X, Y S = RSUM(X+1,Y+1) ß Error caught in modern Fortran Compilers. See Liabilities print *, S RETURN END C How to compile: C gfortran -std=legacy -c recur.f C gfortran -o recur recur.o |
Figure 6.2 Recursion of Legacy Fortran |
6.3. Maximum Limit of DO Loops (loops256.f90)
6.3.1. Code snippet of 520 nested DO loops
6.3.2. No errors during compile time. Due to the amount of DO loops, it would take an interminable long time to see if errors occur during runtime
program hello INTEGER :: num INTEGER :: a1, … , z20 num = 0 do a20 = 1, 2 !20 . . . do z1 = 1, 2 if(z1 == 2) then n = n + 1 end if ! 1 end do ! z1 if(z1 == 2) then n = n + 1 end if end do ! y1 . . . end do num = num + 1 print*, num end do end program hello |
Figure 6.3 Maximum Limit of DO Loops |
6.4. C++ Program Used to Generate loops256.f90 (codeGenerator.cpp)
6.4.1. It became tedious writing the open DO and close END DO for the alphabet twenty times, so I wrote a C++ program to automate it for me.
#include <iostream> #include <fstream> using namespace std; int main(){
ofstream myfile; myfile.open("out.f90"); myfile << "program hello\nINTEGER :: n\n";
// variable declaraction for(int i = 1; i <= 20; i++){ myfile << "INTEGER :: "; for(char j ='a'; j <= 'z'; j++) { if (j == 'n') myfile << "\nINTEGER :: "; if(j == 'm' or j == 'z') myfile << j << i; else myfile << j << i <<", "; } myfile << "\n"; } // do myfile << "n = 0\n"; for(int i = 20; i >= 1; i--) { for(char j = 'a'; j <= 'z'; j++) { myfile << "do "<< j << i << " = 1, 2"; if(j == 'a') myfile << " ! " << i; myfile << "\n"; } } // end do for(int i = 1; i <= 20; i++) { for(char j = 'z'; j >= 'a'; j--) { if(i == 20) myfile << "n = n + 1\nprint*, n\n"; myfile << "end do\n"; } } myfile << "end program hello\n"; myfile.close(); } |
6.5. Ackermann’s Function Using Recursion in Fortran 90 (ackermann.f90)
6.5.1. Note that in C-based languages, there are no distinction between a recursive subprogram and non-recursive subprogram.
Program ackermann integer :: ack write(*,*) ack(2, 3) end program ackermann recursive function ack(m, n) result(a) integer, intent(in) :: m,n integer :: a if (m == 0) then a=n+1 else if (n == 0) then a=ack(m-1,1) else a=ack(m-1, ack(m, n-1)) end if end function ack |
6.6. Compiler Trickery With Recursion in Fortran 77 (test.f)
6.6.1. Here is what I was referring to in Example Program 6.2 where one can trick the compiler to recurse a subroutine by passing the subroutine as an argument to itself and then having a dummy subroutine call the original subroutine.
6.6.2. I would like to thank Andrew J Miller of Pennsylvania State University’s Engineering Science and Mechanics department for this example. His webpage can be found at https://sites.esm.psu.edu/~ajm138/fortranexamples.html
PROGRAM MAIN INTEGER N, X EXTERNAL SUB1 COMMON /GLOBALS/ N X = 0 PRINT *, 'Enter number of repeats' READ (*,*) N CALL SUB1(X,SUB1) END SUBROUTINE SUB1(X,DUMSUB) INTEGER N, X EXTERNAL DUMSUB COMMON /GLOBALS/ N IF(X .LT. N)THEN X = X + 1 PRINT *, 'x = ', X CALL DUMSUB(X,DUMSUB) END IF END |
6.6 Timed Ackermann’s Function (ackTime.f90)
program test_cpu_time integer :: ack write(*,*) ack(3,12) end program test_cpu_time recursive function ack(m, n) result(a) integer, intent(in) :: m,n integer :: a if (m == 0) then a=n+1 else if (n == 0) then a=ack(m-1,1) else a=ack(m-1, ack(m, n-1)) end if end function ack |
6.7 Timed Ackermann’s Function (ackTime.c)
#include<stdio.h> int A(int m, int n);
int main() { int a = A(3,12); printf("\nOUTPUT :: %d\n",a); }
int A(int m, int n) { if(m==0) return n+1; else if(n==0) return A(m-1,1); else return A(m-1,A(m,n-1)); return -1; } ~ |
7. Assets
There are many features of Fortran that make it lightning fast for heave computations. One umbrella of features spawned from the seemingly overoptimized compiler, which led to the lack of aliasing until pointers were introduced in Fortran 90. This meant that work was offloaded from the compiler to the programmer to watch out for those issues. Other optimizations include placing the initialized and computed instructions corresponding to a DO inside the object program at the outermost DO level (Backus 1957). This removes certain instructions from the most frequent innermost loop. Data type and storage for all variables are fixed prior to execution. This means that no new variables could be allocated during execution time which leads to the largest liability in this discourse being that variable binding is static (Sebesta, 2012). The static allocation of variables can be seen in every Example Program. The benefit to this is further efficiency with the lack of subroutine call stack. These optimizations are not exhaustive, and they amalgamate to a programming language that is almost twice as fast as hand-coding, which in turn saves resources like time and money that would otherwise be spent timesharing a computer in 1954.
We can quantify these optimizations by timing how the program’s execution. What better application is there than Ackermann’s function? An explanation of Ackermann’s function can be found in Liabilities section. The programs used can be seen above (Example Program 6.6 and Example Program 6.7).
Here is the result when m = 3 and n = 12
As one can see, the C program is faster than the Fortran 90 program. Under optimal conditions, Fortran 90 being a language that excels at numerical computation should dominate C. These results are not what I was expecting. The test performed was on a virtual machine running SEED Linux. The battle is not of which is the faster language, but which is more optimized compiler. Fortran 90 was at an inherent disadvantage since Fortran is optimized in array indexing. Ackermann’s function being the benchmark was not the best choice since C and subsequently C++ has been used to robust programs like create operating systems. There is also the problem of where the code and executable is being stored. Is it stored in the cache in the Data Segment or is it on an external disk like a flash drive?
8. Liabilities
One of the most well-known issue of legacy Fortran is the inability to perform recursion at the user level. On overlooked reason for this is the lack of a subroutine call stack. Although not explicitly stated in The FORTRAN Automatic Coding System, it is implied that variables are statically bound (Backus, 1957). If Syntactic error checking facilities were weak (which they were in 1957!), then the program in Example Program 6.2 would be able to compile without error and therefore the subroutine would be recursively called. Since there is no structure in memory to keep track of the variables dynamically at each call, the data would just become garbage. Why would we need recursion in a mathematical language such as Fortran?
Ackermann’s function (Example
Program 6.5) is a perfect example as it shows how large a function can get
in a small amount of time. While the literature states that input to
Ackermann’s function are integers, they have to be non-negative. For this
purpose, I will refer to them as whole numbers. For a base case of the first
whole number m equaling zero, the second whole n is incremented and returned.
If the n is equal to zero, then the function is recursed, passing a decremented
m as the first parameter and n as the second parameter. The second and final
recursive case can be found in Example Program 6.5. To give a scale as
to how large the function gets, if m equals four, then it is no longer
exponentiation, its tetration, which is repeated exponentiation i.e. .
When m equals 5 it is pentation, which is repeated titration.
As shown, recursion achieves a form of infinite looping that iterating with DO loops could never accomplish. In the Intel® Fortran Compiler XE 19.0 User and Reference Guides under the Compiler Limits section, it lists the maximum amount of nest DO, IF, CASE, and WHERE statements in a program as 512. As a test, I wrote a program (Example Program 6.3) that loops 520 (26 letters in the alphabet multiplied by 20) nested DO loops. I left the program running for two days without a single incrementation of the outermost DO loop. The counter was incrementing, and I hypothesized that it would overflow once it exceeded a 4-byte integer (huge) value of 2147483647 (Intel Corporation, 2021).
9. Conclusion
Fortran remains one of the highest performing languages of its time and with recursion being supported in its modern phase of life, it can do virtually everything that any modern programming language can do. Currently Fortran is still used for computations in Physics and Chemistry. As mentioned previously, NASA has developed the PARAMESH extension to Fortran 90. Even the code of the Voyager Spacecraft was written in Fortran 5 and later ported to Fortran 77 (Mann, 2013). Today, modern Fortran can be used as a learning tool in universities as C++ is at the University of Central Oklahoma to teach data structures, sorting algorithms, and the rich history of computer science.
10. References
Bruce A Fryxell, et al. “FLASH: An Adaptive Mesh Hydrodynamics Code for Modeling Astrophysical Thermonuclear Flashes” The Astrophysical Journal Supplement Series, vol 131, (April 2000): 273-334 doi:10.1086/317361
Intel Corporation, “Fortran Compiler Classic and Fortran Compiler (Beta) Developer Guide and Reference” (2021)
John W Backus, et al. “The FORTRAN Automatic Coding System.” IRE-AIEE-ACM '57 (Western): Papers presented at the February 26-28, 1957, western joint computer conference: Techniques for reliability (February 1957): 188-198 doi: 10.1145/1455567.1455599
John W Backus, "The History of FORTRAN I, II and III." Annals of the History of Computing, vol. 1, no. 1, (Jan.-March 1979): 21-37 doi: 10.1109/MAHC.1979.10013.
José M Soler, et al. “The SEISTA method for ab initio order-N materials simulation” Journal of Physics: Condensed Matter, vol. 14, no. 11, (March 2002): 2745-2779 doi: 10.1088/0953- 8984/14/11/302
Adam Mann, “Interstellar 8-Track: How Voyager's Vintage Tech Keeps Running.” Wired, Conde Nast, (25 Sept. 2013), https://www.wired.com/2013/09/vintage-voyager-probes/.
Programming Research Group, “Specifications for The IBM Mathematical FORmula TRANslating System, FORTRAN” Preliminary Report, (November 1954): 20-27
Robert W Sebesta, “Concepts of Programming Languages” Boston Person (2012): 45-47
[1] https://www.wired.com/2013/09/vintage-voyager-probes/
SIESTA https://departments.icmab.es/leem/siesta/