Fortran

Guide To Learn

Array constructors will come in handy to initialize the stock symbols. If we do it correctly, looping over them and printing each one to the screen, the output will look like this:

Working on AAPL
Working on AMZN
Working on CRAY
Working on CSCO
Working on HPQ
Working on IBM
Working on INTC
Working on MSFT
Working on NVDA
Working on ORCL

As you can imagine, specific symbols depend on what data we have. Since in this exercise we’ll work with only 10 stocks, we can type them directly in the code, as shown in the following listing.

Listing 5.3 Initialize and print stock symbols to screen

program stock_gain
  ...
  integer :: n
 
  symbols = ['AAPL', 'AMZN', 'CRAY', 'CSCO', 'HPQ ', &   ❶
             'IBM ', 'INTC', 'MSFT', 'NVDA', 'ORCL']     ❶
 
  do n = 1, size(symbols)                                ❷
    print *, 'Working on ' // symbols(n)                 ❷
  end do                                                 ❷
 
end program stock_gain

❶ Initializes stock symbols

❷ Loops over stock symbols and prints them to screen

Here, I use the built-in function size to return the integer size of an input array, in this case 10. We used this function already back in chapter 3. Where I initialize the stock symbols, I also introduce a new syntax element, the array constructor, to assign the stock symbols to the symbols array. Array constructors allow you to create arrays on the fly and assign them to array variables:

integer :: a(5) = [1, 2, 3, 4, 5]     ❶

❶ Initializes from a constant array

In this example, I used square brackets to enclose a sequence of five integers. Together, this syntax forms a literal constant array that is then assigned to a. For static arrays, the size and shape of the array constructor must match the size and shape of the array variable on the left side.

Alternative syntax for array literals

Besides the square brackets, there’s another standard-compliant way to create array literals, using parentheses and forward slashes:

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

I mention this because you may encounter it in existing Fortran code. However, since this syntax is more verbose (twice as much, in fact), I recommend using square brackets exclusively, which I’ll do throughout this book.

In the array constructor snippet, I initialized a on the declaration line. This makes for an easy and concise declaration and initialization of a small array. However, there’s one exception case in which you’re not allowed to do this: pure procedures. In that case, you have no choice but to declare and initialize in separate statements:

integer :: a(5)
a = [1, 2, 3, 4, 5]      ❶

❶ Initializes from a constant array

This is no big deal, but you may rightfully ask, why this restriction? It stems from a historical feature of Fortran called implicit save behavior.

Implicit save

Adding a save attribute to the declaration statement in a procedure causes the value of the declared variable to be saved between calls. In other words, the procedure would “remember” the value of that saved variable. Now, here’s the twist: if you initialize a variable in the declaration statement, this will implicitly add the save attribute to the declaration. A variable with the save attribute will maintain its value in memory between procedure calls. As this is a side effect, it can’t be used in pure procedures.

I don’t recommend using the save attribute or relying on the implicit save feature to maintain state between calls. In main programs and modules, it’s harmless, and you can safely initialize on declaration. In procedures, I recommend against using the implicit save behavior, as it leads to bug-prone code.

There’s another, more general way of constructing an array. In several examples, I’ve assigned to a an array of five elements, and they were easy to type in by hand. However, what if you wanted to assign a hundred or a thousand elements? This is where we can use the so-called implied do loop constructor, as shown in the following listing.

Listing 5.4 Initializing an array from an implied do loop constructor

integer, allocatable :: a(:)
integer :: i
 
a = [(i, i = 1, 100)]     ❶

❶ Elements will range from 1 to 100.

This syntax is called an implied do loop because (i, i = 1, 100) is just syntactic sugar for an explicit do loop:

do i = 1, 100
  a(i) = i
end do

With an implied do loop array constructor, you aren’t restricted to just the loop counter. For example, you can use it to assign array values from arbitrary functions or expressions, as shown in the following listing.

Listing 5.5 Initializing a real array with sines from 0 to 2π, with 1,000 steps

real, allocatable :: a(:)
integer :: i
real, parameter :: pi = 3.14159256
 
a = [(sin(2 * pi * i / 1000.), i = 0, 1000)]     ❶

❶ Initializes an array with sines from 0 to 2π

Here, I used the integer index i to construct an array of sines with arguments that go from 0 to 2π in 1,000 steps. Although it’s almost always useful, i doesn’t need to appear in the expression that evaluates array elements.

For example, initializing an array of a thousand zeros is trivial:

a = [(0, i = 1, 1000)]

Finally, Fortran also lets you create empty arrays using [integer ::] or [real ::]. In practice, these could be useful if invoking a generator –a function that appends an element to an array on every call..

Combining different numeric types in expressions

Notice that in listing 5.5 I’ve mixed integer and real variables in a single expression: sin(2 * pi * i / 1000). What’s the type of the result then? Integer or real? Fortran follows two simple rules:

  1. The expression is first evaluated to the strongest (most precise) type. For example, multiplying a real with an integer always results in a real, and multiplying a complex number with either a real or an integer always results in a complex number. Same goes for kinds of different precision–adding a real32 to a real64 results in a real64 value.
  2. If you’re assigning the result of the expression to a variable, its type is automatically promoted (or demoted!) to the type of the variable.

In the specific example of listing 5.5, 2i, and 1000 are integers, and pi is a real. The whole expression is thus a real number. This is generally known as type coercion or mixed-mode arithmetic. We’ll use it often in this book.

Array constructors

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top