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

https://www.open-mpi.org/

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/