Fortran Introduction

by "Blag" - Developer Evangelist

Return to Geeky Thursday

What is Fortran?


Really...what is Fortran?


Fortran (Formula Translator) is a general-purpose, imperative programming language that is essentialy suited to numeric computations and scientific computing.


Originally developed by IBM in the 1950s.


There are many fortran iterations line Fortan77, Fortran90, Fortran95, Fortran2003 and Fortran2008



How to install Fortran?


If you're on Linux or Mac, you most likely have Fortran installed under the name of gfortran


If you don't simply do sudo apt-get install gfortran


On Windows, you can go here

Who uses Fortran?


Amazingly, Fortran is still being used...mostly for meteorology, oceanography, geophysical modeling and atmospheric science...


  • Lockheed Martin
  • Los Alamos National Laboratory
  • The Aerospace corporation
  • Vencore

Starting out...


Fortran doesn't come with a REPL...although it seems that you can find some on the web...


Basically you need to create your file and test it out...


And I would recommend getting Geany an awesome editor that will make things easier for you...

Creating our first Fortran file


To makes thing easier, we're going to create a file and use it as our sandbox...


Call it sandbox.f95


And type in the following...

				
!This is our Fortran sandbox


program sandbox

  write(*,*) "Hello World!"

end program sandbox
				

In order to run this app we need to compile and then build this source code...


gfortran -Wall -c "sandbox.f95"


gfortran -Wall -o "sandbox" "sandbox.f95"


After that, we can call our application using /.sandbox

Basic Concepts


Printing on the screen is easy...

And only one line comments are allowed...

				
write(*,*) "This a line"


!And this is a comment
				

Variables


Variables always start with a data type

And for character values, a fixed length...

				
character(4) :: name = "Blag"
  
integer :: age = 40


!If we use character(10) then we would have 6 empty 

!spaces after the name
				
				
character(4) :: name = "Blag"

integer :: age = 40

  
write(*,*) "My name is ", name, ", I'm ", age, &

           " years old."


!Prints -->  My name is Blag, I'm           40  years old.



write(*,'(a,a,a,i2,a)') "My name is ", name, &

      ", I'm ", age, " years old."
      
      
!Prints --> My name is Blag, I'm 40 years old.      
				
				
!We can create a dynamic string


character(:), allocatable :: name

 
name = "Blag"



!And print it's length


write(*,'(i1)') len(name)


!Prints --> 4 


!You might get a warning regading initialization

!however that seems to be a bug!
				

Arrays are easy...

				
!Array of five integer elements


integer, dimension(5) :: nums1 = (/ 1, 2, 3, 4, 5 /)


!Both ways are the same...


integer, dimension(5) :: nums2 = (/ (i, i=1,5) /)



!Dynamic allocation...well...sort of...

integer, dimension(:), allocatable :: nums3

integer :: allst
  
allocate(nums3(5), stat=allst)
				

Index starts at 1...

Wait, what?!


Multidimension Arrays are easy too...


				
integer, dimension(2,2) :: nums1 = 

         reshape((/1,3,2,4/), (/2,2/))



integer, dimension(:,:), allocatable :: nums3

integer :: allst

allocate(nums3(2,2), stat=allst)

Some fun with Arrays...

				
integer, dimension(5) :: nums1 = (/ 1, 2, 3, 4, 5 /)


write(*,*) nums1(1) !Prints 1



!Instead of a loop, we can use this short form

write(*,*) (nums1(i), i=1,5) !Prints all numbers



!Initializes all elements to zero

nums1 = 0


write(*,*) nums1(3) !Prints 0

				

Looping

Fortran provides us the do...end loop


				
integer :: counter


do counter = 1, 3

  write(*,'(i2)',advance="no") counter

end do


!Prints --> 1 2 3

!advance="no" eliminates the carriage return
				
				
integer :: counter = 1


do while (counter <= 3)

  write(*,'(i2)', advance="no") counter

  counter = counter + 1

end do


!Prints --> 1 2 3
				
				
integer :: counter = 1


do

  if(counter > 3) exit

  write(*,'(i2)', advance="no") counter

  counter = counter + 1

end do


!Prints --> 1 2 3
				

Subroutines and Functions


Subroutines return no value

Functions can return zero, one or multiple values

				
program sandbox

  integer :: a = 5, b = 10, results

  call sums(a, b, results)

  write(*,*) results
    
end program sandbox



subroutine sums(a, b, results)

  integer, intent(in) :: a, b

  integer, intent(out) :: results
  
  results = a + b
  
  return

end subroutine sums
				
				
program sandbox

  implicit none  !Allows us to find compile mistakes
  
  integer,external :: sums

  
  integer :: a = 5, b = 10, results
  
  results = sums(a, b)
  
  write(*,*) results
    
end program sandbox


integer function sums(a, b)

  integer, intent(in) :: a, b
  

  sums = a + b
  
  return

end function sums
				

Fibonacci List


Finally...we're going to make our first application...


So grab your favorite text editor and get ready...


Name your file "fibonacci.f95"


				
program fibonacci

  
  implicit none
  
  
  integer :: a=0, b=1, num
  
  write(*,'(a)',advance="no") "Enter a number: "
  
  read(*,*) num
  
  write(*,*) trim(fib(num, a, b))
  

contains


recursive function fib(num, a, b) result(fibo)


  integer, intent(in) :: num, a, b

  integer :: ab

  character(1000) :: a_s, b_s, ab_s

  character(1000) :: fibo  
				
				  
  if(a > 0 .and. num > 1) then

    ab = a + b

    write(ab_s, '(I0)') ab

    fibo = trim(ab_s) // " " // fib(num - 1, ab, a)

  else if (a == 0) then

    ab = a + b

    write(a_s, '(I0)') a

    write(b_s, '(I0)') b

    write(ab_s, '(I0)') ab

    fibo = trim(a_s) // " " // trim(b_s) // " " // trim(ab_s) // " " // trim(fib(num - 1, ab, b))

  else

    fibo = ""

   end if
  
  return

end function fib

end program fibonacci
				

Open the Terminal and go to your source code folder...

gfortran -Wall -c "Name_of_File.f95"

gfortran -Wall -o "Name_of_Exec" "Name_of_File.f95"


When we run it we're going to see...


Making an LED Number App


This is one of my favorite codes of all time...


Name your file "LED_Numbers.f95"


				
program LED_Numbers

  
  implicit none

  
  character(100) :: num
  
  integer :: leng 
  
  integer, dimension(:), allocatable :: nums
  
  integer i, j, x, lenled
  
  integer :: allst
  
  character(15), dimension(10) :: leds
  
  character(:), allocatable :: led1
  
  character(:), allocatable :: led2
  
  character(:), allocatable :: led3
  
  character(:), allocatable :: text
  
  character(:), allocatable :: concat
				
				
  leds(1) = " _  ,| | ,|_| ,"

  leds(2) = "  ,| ,| ,"

  leds(3) = " _  , _| ,|_  ,"

  leds(4) = "_  ,_| ,_| ,"

  leds(5) = "    ,|_| ,  | ,"

  leds(6) = " _  ,|_  , _| ,"

  leds(7) = " _  ,|_  ,|_| ,"

  leds(8) = "_   , |  , |  ,"

  leds(9) = " _  ,|_| ,|_| ,"

  leds(10) = " _  ,|_| , _| ,"

  
  led1 = ""

  led2 = ""

  led3 = ""
				
				
  write(*,'(a)',advance="no") "Enter a number: "

  read(*,*) num
  

  leng = LEN(TRIM(num))

  allocate(nums(leng), stat=allst)
 

  nums = get_digits(trim(num))

  concat = ""
	

  do i = 1, leng

    x = 1

    text = trim(leds(nums(i) + 1))

    lenled = len(trim(text))
				
				
    do j = 1, lenled

      if(text(j:j) /= ",") then

        concat = concat // text(j:j)

      else

        select case (x)

          case (1)

            led1 = led1 // concat

          case (2)

            led2 = led2 // concat

          case (3)

            led3 = led3 // concat

        end select

        concat = ""

        x = x + 1
				
				
      end if

    end do

  end do

  
  write(*,*) led1

  write(*,*) led2

  write(*,*) led3
  

  contains  
				
				
    function get_digits(num)

      character(100):: num

      integer :: allst

      integer :: numslide

      integer :: leng

      integer :: cvtErr

      integer :: i
 
      integer, dimension(:), allocatable :: get_digits
 

      leng = len(trim(num))

      allocate(get_digits(leng), stat=allst)
 
      do i = 1, leng

        read(num(i:i), * ,iostat=cvtErr) numslide

        get_digits(i) = numslide

      end do 
  
      return
  
    end function get_digits
  
end program LED_Numbers
				

When we run it we're going to see...


Random Names


This App will generate 100,000 random names using two 16 elements arrays


We will measure the runtime


Name your file "Random_Names.f95"


				
program randon_names
 
 
  implicit none
 
 
  real :: start, finish

  real :: x

  integer :: i, n, clock

  character(8), dimension(16) :: names

  character(12), dimension(16) :: last_names

  character(21), dimension(100000) :: full_names

  integer counter

  integer, dimension(:), allocatable :: seed

  integer rand1, rand2

 
  call cpu_time(start)				
				
				
  names =  (/"Anne    ", "Gigi    ", "Blag    ", &

             "Juergen ", "Marek   ", "Ingo    ", &

             "Lars    ", "Julia   ", "Danielle", &

             "Rocky   ", "Julien  ", "Uwe     ", &

             "Myles   ", "Mike    ", "Steven  ", &

             "Fanny   "/)


  last_names = (/"Hardy       ", "Read        ", &

                 "Tejada      ", "Schmerder   ", &

                 "Kowalkiewicz", "Sauerzapf   ", &

                 "Karg        ", "Satsuta     ", &

                 "Keene       ", "Ongkowidjojo", &

                 "Vayssiere   ", "Kayly       ", &

                 "Fenlon      ", "Flynn       ", &

                 "Taylor      ", "Tan         "/)

			
				
  call random_seed(size = n)
  
  allocate(seed(n))
  
  call system_clock(count = clock)
  
  seed = clock + 37 * (/ (i-1, i=1, n) /)
  
  call random_seed(put = seed)
  
  deallocate(seed)

  
  do counter = 1, 100000
  
    call random_number(x)
  
    rand1 = int(x * 16.0) + 1
  
    call random_number(x)
  
    rand2 = int(x * 16.0) + 1    
  
    full_names(counter) = trim(names(rand1)) // " " & 
    
                          // trim(last_names(rand2))
  
  end do
			
				
  call cpu_time(finish)
  

  print '("Time = ",f6.3," seconds.")',finish-start
        

end program randon_names
			

When we run it we're going to see...

How this behaves in Python?

And what about Go?

Go was faster this time, but barely!

Decimal to Romans


This App will create a Roman Numeral based on a decimal number


This will include some nice commands...


Name your file "Decimal_to_Roman.f95"


				
program decimal_to_roman
 
  
  implicit none
 
  
  integer, dimension(13) :: roman_keys
  
  character(2), dimension(13) :: roman_values
  
  character(1000) :: roman_num
  
  integer :: counter, key_num, num

  
  roman_keys = (/1000, 900, 500, 400, 100, &

                 90, 50, 40, 10, 9, 5, 4, 1/)       
  

  roman_values = (/"M ", "CM", "D ", "CD", "C ", &

                   "XC", "L ", "XL", "X ", "IX", &

                   "V ", "IV", "I " /)  
			
				
  write(*,'(a)',advance="no") "Enter a number: "

  read(*,*) num

  roman_num = ""

  do while(num > 0)

    do counter = 1, size(roman_keys)

      key_num = roman_keys(counter)

      if(num >= key_num) then

        roman_num = trim(roman_num) & 
        
                    // roman_values(counter)

        num = num - key_num

        exit

      end if

    end do

  end do
			
				
  write(*,'(a)') trim(roman_num)
 
 
end program decimal_to_roman
			

When we run it we're going to see...


Count Letters


In this example we're going to read a file and count how many time a letter appears...


Call your file "count_letters.f95" (all in lowercase).


Create a file called "readme.txt" with the following text...


"This is a text file that we're going to read using Fortran"


				
program count_letters
 
  
  implicit none
 
 
  character(10) :: myfilename = "readme.txt"

  character(1), dimension(100) :: key_letters

  integer, dimension(100) :: value_letters

  integer :: myreadstatus, counter, num, x

  character(100) :: readme

  open(unit=12, file=myfilename, status="old", & 
  
       action="read", position="rewind", & 
       
       iostat=myreadstatus)

  key_letters = ""

  value_letters = 0

  counter = 1
				
				
  if(myreadstatus > 0) stop "Cannot open file"

  read(12,'(a)', iostat=myreadstatus) readme

  do x = 1, len(trim(readme))

    if(ANY(key_letters == readme(x:x))) then

      counter = find_key(readme(x:x))

      num = value_letters(counter) + 1

      value_letters(counter) = num

    else

      key_letters(x) = readme(x:x)

      value_letters(x) = 1

    end if

  end do
				
				
  close(12)


  do counter = 1, size(key_letters)

    if(value_letters(counter) /= 0) then

      write(*,*) key_letters(counter), & 
        
                 value_letters(counter)

    end if

  end do
				
				 
  contains
  
    integer function find_key(char_value)

      character(1) :: char_value

      do counter = 1, size(key_letters)

        if(key_letters(counter) == char_value) then

          find_key = counter

          exit

        end if

      end do

      return

    end function
 
end program count_letters  
				

When we run it we're going to see...


That's it for now


Well...Fortran is pretty old...


Doesn't have much keywords...


You're not going to use it for Web Development...although technically you can...


Learning Fortran will make you glimpse into the past...and see how ancient programmers used to work...

Contact Information


Blag --> a.tejada.galindo@sap.com

@Blag on Twitter

Go back home...