Author Topic: [Fortran77] Some historical views, multiprocessor example  (Read 1346 times)

0 Members and 1 Guest are viewing this topic.

Offline Deque

  • P.I.N.N.
  • Global Moderator
  • Overlord
  • *
  • Posts: 1203
  • Cookies: 518
  • Programmer, Malware Analyst
    • View Profile
[Fortran77] Some historical views, multiprocessor example
« on: January 03, 2014, 09:21:15 am »
Did you read Fortran77? Yes, you did. This is just a silly project I made, because I am curious about old languages. I want to tell you some facts I found out about this language using this example.

But first comes the project code and some explanations:

Code: (fortran) [Select]
      program
        implicit none
        double precision pi, res, integral, testfun1, testfun2, a, b
        double precision recvdata
        external testfun1, testfun2
        integer n, pipetail
        parameter (n=20)
       
        integer makepipe, topid, id, np, links(2), nprocs
       
        np = nprocs()
        pipetail = np - 1
        topid = makepipe(1, np, -1, -1, -1, -1, -1, -1, id, links)
        pi=4.d0*datan(1.d0)
       
        a = 0
        b = pi
        call sliceinterval(a, b, id, np)
        res = integral(testfun1, a, b, n)
       
        if(id.ne.0) then
          call recv(topid, links(1), recvdata, 8)
          print*, "id", id, ", recieved", recvdata
        endif
       
        res = res + recvdata
        if(id.ne.pipetail) then
          call send(topid, links(2), res, 8)
        endif
       
        if(id.eq.pipetail) then
          print*,"testfunction 1"
          print*,"integral", res
          print*,"pi", pi
          print*,"distance", abs(res-pi)
          print*,""
        endif
       
        call freetop(topid)
      end

C     sets new interval boundaries based on the own id and number of processors
      subroutine sliceinterval(a, b, id, np)
        double precision a, b, h
        integer id, np
        h = (b-a) / np
        a = a + id * h
        b = a + h
      end
   
C     the first testfunction   
      double precision function testfun1(x)
        double precision x
        testfun1 = x * dsin(x)
      end
     
C     the second testfunction
      double precision function testfun2(x)
        double precision x
        testfun2 = 4/(1 + x*x)
      end
     
C     calculates the integral of the given function fun in the interval [a,b]
C     with n steps
      double precision function integral(fun, a, b, n)
        double precision fun, a, b, h, integral, xs
        integer n, i, c
        h = (b-a)/n
        integral = fun(xs(0,a,h))
        do i=1,n-1
          c = 2 + 2 * mod(i,2)
          integral = integral + c * fun(xs(i,a,h))
        enddo
        integral = (integral + fun(xs(n,a,h))) * h/3
      end
     
C     returns x_i for the given i (index), a (interval start) and h (with h=(b-a)/n)
      double precision function xs(i,a,h)
        integer i
        double precision a,h
        xs = a + i*h
      end

This simple program will calculate the integral of any given function (in this case testfunction1) in any given interval by using the formula:
the interval is [a,b]
integral(f(x)) = h/3(y0 + 4*y1 + 2*y2 + 4*y3 + ... + 2*yn-2 + 4*yn-1 + yn)
h = (b-a)/n

The result is just an approximation, so for testing it I chose a testfunction whose integral will be PI in the interval [0, pi] and compared it to the machine PI I can calculate using atan.

The same can be done with testfunction2 in the interval [0,1], which will also result in PI.

To work with multiprocessors, the parex library is used. Every processor calculates the integral of a part of that interval given. I chose to build a pipe as virtual architecture and then populate and sum up the result from the first processor to the last.
I.e. processor with id 0 will calculate the integral 1,1
id 1 receives the result and adds it to it's own calculation, 1,1 + 0,2 = 1,3.
id 2 gets the result from id 1 which is 1,3 and so on until you get to the very end of the pipe where the final result will be printed.

Here is the output of the code above:

Code: [Select]
id           1, recieved  1.9876787099988892E-02
 id           2, recieved  0.1517464117063354   
 id           3, recieved  0.4730412324368839   
 id           4, recieved  0.9999999975225691   
 id           5, recieved   1.675276693198365   
 id           6, recieved   2.373187882619952   
 id           7, recieved   2.922329941636222   
 testfunction 1
 integral   3.141592656184073   
 pi   3.141592653589793   
 distance  2.5942803461020958E-09

Now some silly facts about fortran77: This old fortran version still has some remains from the times where you used punchcards to write your program.

Look at this punchcard for example:



There you have several sections in the columns. In the first column there will be a C if a comment is following. Col 2-5 are for statement numbers (where you can jump to). Col 6 can be punched to mark a continuation from the last line.
Col 7-72 is actual source code (the section in the middle) and everything after that won't be read at all by fortran and can be used for anything you like (often used for identifying information).

Again: This punchcard was used for the very first version of Fortran which appeared in 1957. If you are interested in that, read more about it here: http://www.fortran.com/FortranForTheIBM704.pdf

Fortran77 came 20 years later and still you had to adhere the structure of the punchcards. That means you can only write code from column 7 to 72, otherwise the compiler will complain. You also have to mark comments with a C in the very first column and so on. You can't get any commandline arguments.
However, I was surprised that I could just pass a function as an argument. That's something I didn't expect from an old language like that. I also feel that Fortran77 is still more comfortable to program with than C.

Fotran uses call-by-reference, so any parameter you change in a subroutine or function is changed within the caller too.
The functions are a bit weird. The result is always the value of the variable that has the same name as the function when either "end" or "return" statement is reached.
You also declare the types of the parameters in the first lines of the body.

Speaking of types: Fortran has implicit type declaration which probably came from the fact that the inventor Backus was a mathematician or had a firm mathematical background. Every variable or function whose name starts with i, j, k, l, m or n is an integer (note that these are common names for indices and the like in mathematical formulas), everything else will be a real (which is a single precision floating point number, or float in C).
I decided to explixitly declare every type nevertheless to avoid confusion.

Fortran77 is also case insensitive. Doesn't matter if you write Name, name, nAME, NAME, it will all be the same for the compiler.

That's it for now.

Have fun coding.
Deque