Coding Fortran: if-else

Decision statements form one of the core elements of any programming language and Fortran is no different. When Fortran first appeared, there was no true if-else statement, and so they were often coded using instruction jumps (goto in disguise and definitely more than meets the eye).

However newer versions of Fortran have moved onto a more contemporary form of the if-else statement, incorporating the keyword then, and like all control structures in Fortran, using the CS terminator end if. Let’s consider an example of finding the roots of a quadratic equation.

program roots

   real :: a, b, c
   real :: discriminant, root1, root2

   print *, 'Input A, B, C'
   read *, a, b, c

   discriminant = b ** 2 - 4.0 * a * c

   if (discriminant < 0.0) then
      print *, 'no real roots'
   else
      root1 = (-b + sqrt(discriminant))/(2.0 * a)
      root2 = (-b - sqrt(discriminant))/(2.0 * a)
      print *, 'roots are ', root1, root2
   end if

end program roots

This program creates a series of real variables, prompts the user for input, calculates the discriminant, and then decides whether the roots can be calculated. Due to the use of a terminator, there is no need to explicitly use a block structure (like C’s { } ) when more than one line of code is needed, either in the then or else part of the if statement. The structure of the if-else statement is similar to that encountered in other languages. The difference is that due to the CS terminators, there is no fear of the dangling else problem occurring. Fortran also protects against expressions like (discriminant = 0), which in C would be valid, but in Fortran assignment in an if-else expression is not allowed. It would produce an error of the form:

if (discriminant = 0.0) then
                1
Error: Syntax error in IF-expression at (1)

Now let’s go back briefly and look at what this code would have looked like in unstructured Fortran:

      program roots

      real a, b, c
      real discriminant, root1, root2

      write (*,*) "Input A, B, C"
      read (*,*) a, b, c

      discriminant = b ** 2 - 4.0 * a * c

      if (discriminant) 10, 20, 20
   10 write (*,*) "No real roots"
      goto 40
   20 root1 = (-b + sqrt(discriminant))/(2.0 * a)
      root2 = (-b - sqrt(discriminant))/(2.0 * a)
      write (*,*) "roots are ", root1, root2
   40 stop

      end program roots

Note how the expressions is now just a single variable, discriminant? These forms of if statements, known as arithmetic if‘s, determined if a mathematical  expression was (i) less than zero, (ii) zero, or (iii) greater than zero, and branched accordingly. In this case if the discriminant is less-than-zero, there are no real roots, so it branches to label 10, which outputs a statement to the user, then branches to label 40, effectively the end of the program (otherwise it would flow through to the code at label 20). The “else” component is the portion of code associated with label 20 (if discriminant is greater than or equal to zero). It works, but isn’t exactly pretty, and as complexity increase leads to spaghetti code.

 

Advertisements

A brief guide to Fortran Re-engineering

The process of re-engineering code is not an exact science – the sequence of steps will be different for each particular program, and has much to to with the make-up of the code than the algorithm itself. Is the code modular? Does the code contain a number of unstructured branches, (i.e. goto statements)? The presence or absence of the latter may determine how challenging the re-engineering process will be. Is there a basic series of steps which could be used to re-engineer a program? The series of steps below are given in the context of re-engineering Fortran (from Fortran 77 or prior), but could easily be adapted to any language.

0. Analyze the program

The first thing to do, before even trying to compile the legacy program is to try and analyze what it does. Is there documentation that came with it? Does the program have comments? A flow chart perhaps? If there is nothing but the program, you are going to have to do some detective work first. Walk through the code and see if you can create a flow chart – it may be best to try and visualize what the program is doing, especially if it has a few unstructured jumps.

1. Try compiling the program

The assumption is that the program will run, but that may not always be the case. Compilers like gfortran are backwards compatible – to a point. Some programs come from proprietary compilers, or ones that were not commonly used, and so may contain code idiosyncrasies. In other cases, the code may contain references to devices such as input card readers, which have to be dealt with before the program will even compile. Once the program is running, test data can be derived – this data will help assure the progress of the re-engineering process as it progresses.

2. Convert to lowercase

The easiest thing to start with is converting the program from UPPERCASE to lowercase. This may not seem like a big deal, but it will make the program easier to re-engineer. Don’t change the indenting at this point – languages like Fortran tend to use labels, and if the program is re-indented, these could be harder to decipher. You will find easy ways to covert to lowercase in “Useful Snippets of Code”.

3. Start with the easy things

The easiest things to change are the ones that will make the least impact. The first thing that should be changed is to copy the original code to a new file with a .f95 extension. Trying to compile this will mean that at least one thing won’t work – the comments. So in Fortran this means changing the comment delimiter from C to !. The program should now compile. Next convert the variable specifications. In Fortran this means changing any implicit variables to be explicitly declared. For example, early versions of Fortran allowed variables beginning with I, J, K, L, M, or N to be implicitly declared as integers. Aside from implicit variables, the specification syntax should also be modified. It is also a good idea to put the statement “implicit none” after the program header.

NB: Each time you make a core change to the program, make a new copy, so there is a progressive sequence of files associated with the re-engineer: if something goes eerily wrong (and it might), it is easy to go back to the copy that worked. Also make sure you compile the program after every change, and make sure it still functions as it should.

4. Restructured the simple ifs

The simple if statements should be dealt with next. This means converting them from their legacy format to if then- end if structure. Don’t deal with any if statements that are complex, such as arithmetic if’s.

5. Restructure the loops

The do statements are easy to convert into loops. This will mean converting them from do-continue statements to do-end do structures. This may seem like a trivial modification, but it means some of the labels in the program will disappear, making it less confusing.

6. Deal with the easy go to statements

The easy go to statements are those that are *somewhat* structured. Re-engineer the arithmetic-if and computed-if statements first.

7. Deal with the hard go to statements

There will be some go to statements that will be more challenging – this will require you to think about how to restructure these. Print out the code and annotate it, i.e. make lines from the jumping point to the label. Then ask yourself where the jumps go? Are there a bunch of jumps that jump back to the start of the program? This screams of a global containment loop with some continue type statements in there. Does the program need a function or two to make it work better, and eliminate some of the unstructured jumps?

8. Clean up the program

Once any remaining legacy features have been removed, deal with the aesthetics of the code. Do portions of the code require more indenting to make it more readable? There will likely still be labels in the program associated with format statements, and so it may not be possible to left-justify the program without it looking weird. Are there some variables that need to be renamed? Could the code be modularized in some manner? More appropriate documentation?

Things NOT to do

  • Don’t rush in and start re-engineering the program ad-hoc.
  • Don’t ignore a preliminary analysis of the program.
  • Don’t rush to modularize the program until you are sure you know what is going on – and the unstructured jumps have been removed.

 

Coding Fortran: A basic “Hello World”

When programming in Fortran (say F95), start with the most basic program, our friend “Hello World!”.

program helloWorld

   print *, "Hello World!"

end program helloWorld

A three line program (hello.f95). No need to worry about I/O libraries, or any sort of formatting. It is simple. This is compiled using gfortran as:

gfortran hello.f95

The print statement could have also been replaced with the more traditional:

write (*,*), "Hello World!"

If this were an older Fortran program (pre-F90)  the code would look similar, but wouldn’t allow any free-formatting, for example (hello.for):

1234567      
      program helloWorld

      write (*,*), "Hello World!"

      end program helloWorld

Here the actual code begins in the 7th column, and columns 1-6 are reserved for other things like program labels. If a line of code creeps into those columns, there will be an error of some sort.

 

Does Fortran matter?

Fortran gets a bad rap. It’s a great language. You could be forgiven for not liking it – if you have seen a piece of Fortran IV, or Fortran 77 code. But there is nothing intrinsically wrong with Fortran. You can’t beat up on it, just because it is kind-of old. I mean C *is only* 15 years younger. That’s nothing really. Coding in Fortran is pretty easy as well, probably easier to learn than C, largely because it is not inherently a low-level language. And there we have the crux of C (and some would say one of its benefits) – low level coding. Not everyone cares about coding at a low level, or what memory is doing for that matter. Operating systems, and compilers themselves have become so good at managing it, in some languages you don’t need huge memory handling skills.

Why does Fortran matter? Mostly because it is still heavily used in scientific fields (and the military), and a large repertoire of legacy code exists. It also has superior array handling capabilities (some of which I have mentioned before), and there is little need to worry about pointers and memory allocation. And it is fast. Maybe not as fast as C, but it follows on C’s heels. Remember recently when NASA was able to reprogram the thrusters on Voyager 1? Well Voyager 1 has spent 40 years in the vacuum of space running on computers programmed in Fortran and assembly language, and using 68K of memory.  Check out this paper describing the Fortran I compiler.

Fortran is a coding behemoth, in an era where legacy code is becoming ever more relevant, and individuals with the skills to deal with this code are becoming rarer.

Go on, use the Fortran. (Look some may say “May the Forth be with you”, but I would stay well clear of that Forth stuff – nasty! ).

 

Windows – 200 years in the future? I hope not!

The third episode of the first season of Star Trek: Discovery contained something none of us would hope to ever see in the year 2256 – a vessel capable of interstellar travel running on Windows. At one point in the episode, Michael Burnham is tasked with reconciling two suites of code by Lieutenant Paul Stamets. The code as it turns out is decompiled code from the 2010 Stuxnet virus/cyber-weapon.

.

I know, it’s *only* a TV show right? But they try so hard portraying other types of technology, like the whole idea of using mushroom spores for interstellar travel, but forget about the simple stuff. Of course it is only 240 odd years in into the future. Seem like a lot of time? Think again. Cobol first appeared nearly 60 years ago, and it’s still going strong. I imagine we will easily see its 100 year anniversary being used extensively.

So Windows being used 200 years in the future? I hope not, but one never really knows. It will probably still be coded in C or something, The honest truth is that there has been very little in the way of new programming languages since the 1980s (notable exceptions are languages like Julia). The same with operating systems. We’re stuck with Windows, Linux, and MacOS. The likes of innovative OS’s like BeOS (revived as Haiku), never really made it anywhere. So it seems we are stuck in a sort of technology quagmire, somewhere in the late 1980s.

On top of everything, will we still be using the same interfaces 200 years from now? Keyboards and touch-screens? Coding in an editor? I would think not, but then again, we are still using the same hammer we were 1000 years ago – albeit some are made of titanium (they aren’t really better hammers, just fancier). So maybe the input technology wont change that much (or maybe sci-fi writers can’t think of new things anymore the way they did in the 1960s?). There are plenty of concepts for new input devices of course, such as AirType, but its still typing isn’t it? Voice-based – been there, and it didn’t work so well (I’m sure the technology is better nowadays, but imagine a whole office with people talking to their computers – noisy, and hardly private (or secure for that matter)? Implants then? Direct connection with the machine (hopefully *not* via Bluetooth)? Who knows.

The future is exactly that. The future. Let’s just hope it isn’t filled with Windows.

 

Recollections of programming in the 1980s

When I first started learning to program, Pascal was the language of choice for many institutions. In the scope of software today, it would never have evolved to the point of being able to tackle the gargantuan pieces of software written today (but really has C++?). However it was never designed to do that – it was designed by Niklaus Wirth as a teaching language, to make up for the failings of languages like Algol 68, which had honestly ballooned out of proportion. The choices at the time were not much better, Ada was new, Fortran was considered passé, (and only used by mathematicians), and C had an aura of “don’t teach it as a first language” about it. But eventually through one means or another, you experienced all these languages: Pascal, Ada, C, Cobol, Fortran, all with varied pedigrees and different ways of doing things.

Fortran was interesting, because the version at the time was F77. This means it was halfway between the unstructured coding of Fortran IV/66, and the structured world of C/Ada/Pascal. But whereas the latter languages had forgone the use of forced formatting F77 retained it, as well as many of the goto-like statements that made for “interesting” coding. This was likely the reason it had been rejected by so many as an introductory language. By the 1970s, the use of structured languages  was more or less  entrenched in programming. The intervening decade of the 1980s allowed C and C++ to gain a foothold in the world of introductory programming, and saw decreased academic use of Fortran. Few knew that F90 would evolve Fortran out of the primordial muck, but it seems it was too late – at least in its use as an introductory language. By the late 1980s, Pascal was starting to have to watch its back even more, its influence waning. The age of the C-based languages had dawned.

And now that the genie is out of the bottle it seems hard to cram it back in!

P.S. Here is an iterative version of Quicksort written in Fortran 77.

 

In-camera keystone compensation (Olympus) (ii)

So I took some photographs using the Olympus keystone compensation on a trip to Montreal. Most of them deal with buildings that are leaning back, which is the classic case when trying to photograph a building. The first set deal with some landscape photographs. In both these photographs I could not move any further back to take the photographs, and both were taken with the Olympus 12-40mm, set as wide angle (12mm or 24mm full frae equivalent).It was possible to correct both images, without loosing any of the building.

Originals (left), keystone corrected (right)

The second case deals with portrait format photographs. In both cases it was slightly more challenging to make sure the entire picture was in the frame, but doing it in-situ it was possible to assure this happened. Doing in post-processing may result in the lose of a portion of the photograph. In the lower image I had enough leeway to position the keystone-corrected frame in such a manner that the building is surrounded by ample space.

Originals (left), keystone corrected (right)

Compensating for perspective distortion often comes at a price. Modifying the geometry of a photograph means that less will fit in the photograph. Taking a photograph too close to a building may mean something is cut off.

Horizontal keystone correction can sometimes be more difficult, because the distortion is usually a compound distortion. In the example below, the photograph was taken slightly off-centre, producing an image which is distorted both from a horizontal and a vertical perspective.

Complex distortion

Is there a loss in aesthetic appeal? Maybe. Food for future thought.

In-camera keystone compensation (Olympus) (i)

The Olympus OM-D EM5 Mark II has a completely cool feature they call keystone compensation. It’s a kind-of weird name – but dig a little deeper and you run into the keystone effect  which is the apparent distortion of an image caused by projecting it onto an angled surface. It basically makes a square look like a trapezoid, which is the shape of an architectural stone known as a keystone. Now normally when you take a photograph of a building, this effect comes into play. Reducing the keystone effect is called keystone correction. There are special lenses that remove this distortion, i.e. tilt-shift lenses. Now Olympus has introduced an algorithm which compensates for the keystone effect. Here is an example of keystone correction (distortion is shown as the opaque pink region).

Keystone correction before (left) and after (right)

Olympus has introduced an algorithm on some of their cameras (e.g. EM5ii) which compensates for the keystone effect. First, you have to enable Keystone Correction in “Shooting Menu 2”.

Then it’s a simple matter of using the front or rear dial for correction. The front dial is used to horizontal correction, and the rear dial is used for vertical correction. Note that it doesn’t allow for both types of keystone compensation to be used at the same time. If you decide to change from vertical to horizontal correction, you have to reset the vertical component to 0. Frame the shot and adjust the effect in the display using the front and rear dial. Select the area to be recorded using the directions buttons (surrounding the OK button).

The only trick is using the INFO button to switch between keystone compensation and making adjustments to exposure compensation. In fact if you are using keystone correction often, I would program it into one of the function buttons.

Keystone Compensation mode enables keystone distortion to be corrected when shooting architecture and product photography without resorting to tilt-shift lenses or post-processing corrections in Photoshop.

Is there something weird going on here?

Why does the red light on the  lead cars of the new Bombardier-Alstom MPM-10 subway trains on the Montreal Metro remind me of the vintage Cylon’s eye from Battlestar Galactica? There is something eerily weird about it.

Just a bit of fun for the 500th post! Coming in January, more image processing/digital photography posts, and a series of basic programming posts in Fortran and Ada. Stay tuned!