A Fortran Primer, Puzzle, and Solution
Tags: fortran, tutorial, puzzle, programming
Published: 2022-10-24 10:14:29

## Primer
Fortran is an old programming language that is best used for physics-based computations regarding [spectra calculation and n-body simulations](https://www.moreisdifferent.com/2015/07/16/why-physicsts-still-use-fortran/). Otherwise it is commonly used for large scale mathematical computations. Regardless of the reason you are seeking to learn Fortran, this primer will help you get started. First, you will need to download the Fortran compiler. Follow the steps at [this website](https://fortran-lang.org/en/learn/quickstart/hello_world/) to get the compiler downloaded. Next you will need to create a file ending with the .f90 extension. Some things to note about Fortran: comments are done with !'s, the language is not case sensitive, and a Fortran file can only have one program block. Now you can get started programming with the following Fortran puzzle sourced from [CodeWars](https://www.codewars.com/kata/5592e3bd57b64d00f3000047).

## Puzzle
If you would like to attempt the puzzle for yourself in a different language that you already know, follow the above link. The puzzle asks that you calculate the number of cubes n each of whose volume equals n^3, (n-1)^3, ..., 1^3, given the total sum of the cube's volumes m. There are multiple approaches to solving a problem like this. The first and easiest is to iteratively add the volumes of the cubes incremented by one on each iteration until the sum of the volumes equals the passed in value m. Once that point is reached, return the iterator if the sum exactly meets the m or else return -1. The more complex yet faster solution is to create a formula based on the summation of the cubes to get the value of m. That formula is shown in the code below.

## Solution
Follow along with the code below to see both the iterative and formulaic solutions to the coding puzzle.

```
! modules are basically packages that can be used by programs
modUle testers
  
  ! disables a fortran feature that treats all variables starting with
  ! i, j, k, l, m, and n as integers and all other variables as reals
  ! by default
  implicit none
  
  ! defines a variable
  ! first argument is the data type of the variable
  ! parameter keyword specifies that this variable is a named constant
  ! selected_TYPE_kind(a) returns a kind for the specified data type that can represent all values from -10^a to 10^a
  integer, parameter :: ikind=selected_int_kind(16)
  integer, parameter :: rkind = selected_real_kind(16)
  
! contains blocks off the module's procedures from its global definitions
contains

  ! function definition
  ! begins with a type and kind to specify what the function will return
  ! next is the function keyword followed by the function name and its parameters
  ! optionally you can define a result variable which will inherit its type from the function
  ! the alternative to explicitly defining the result variable is to remove the result section entirely and the result 
  ! variable will default to the name of the function
  integer(16) function find_nb(m) result(n)
  
    ! defining the type and kind for the parameter m
    integer(ikind) :: m 
    integer(ikind) :: sum
    
    ! reals are a category of number that, in simple terms, can have decimals
    real(rkind) :: k
    
    ! Given a volume of m, return the number of cubes n where the volume
    ! of each cube is given by n^3 -> (n-1)^3 -> etc... -> 1^3 and when each
    ! cube's volume is added together you get m
    
    ! iterative solution
    ! n = 0
    ! sum = 0
    ! do while (sum < m)
    !   n = n + 1
    !   sum = sum + n ** 3
    ! end do
    ! if (sum /= m) then
    !   n = -1
    ! end if
    
    ! formulaic solution
    ! the real keyword here is used to convert the integer m into a real datatype of kind rkind
    ! the decimal tells the compiler to treat these whole numbers as reals instead of integers
    k = ((8. * (real(m, rkind)) ** (.5) + 1.) ** (.5) - 1.) / 2.
    ! merge is the ternary operator for fortran: merge(if true, if false, case)
    ! floor is the equivalent of Math.floor() in javascript
    n = merge(-1, floor(k), floor(k) /= k)
    
  ! end the function definition
  end function find_nb
    
! end the module
end module testers

! program denotes where we start the code for a file
program test
  
  ! gives access to the testers module defined above
  use testers
  implicit none
  
  ! outputs to the console in the specified format
  ! a lot to go into here, but basically the first argument to print specifies the type and spacing of the rest of the arguments
  ! A is for strings and i is for integers
  print "(A)", "Pile O' Cubes"
  print "(A, i4.0, A)", "expected: ", find_nb(9_ikind), " -> actual: 2" ! the function find_nb and the kind ikind are both provided by the cubes module
  print "(A, i4.0, A)", "expected: ", find_nb(36_ikind), " -> actual: 3"
  print "(A, i4.0, A)", "expected: ", find_nb(1071225_ikind), " -> actual: 45"
  print "(A, i4.0, A)", "expected: ", find_nb(24723578342962_ikind), " -> actual: -1"
  print "(A, i4.0, A)", "expected: ", find_nb(4183059834009_ikind), " -> actual: 2022"
  print "(A, i4.0, A)", "expected: ", find_nb(135440716410000_ikind), " -> actual: 4824"
  
! end the program
end program test
```
## Conclusion
While Fortran might be a bit dated and mostly outclassed by languages like C++, there are still cases for its usage. If you decide that Fortran is the tool you need then be sure to spend the time necessary to uncover its more powerful computational tools that are relevant to your needs.