The speed of if

Sorry to be bombarding everyone with questions but the responses I have had so far have been absolutely fascinating (I am STILL working through the COMMON responses; I love it when a topic becomes a discussion on other finer points).

My question this time is about the use of if statements.

The code I have has a number of single if statement lines:

if (Jsub .gt. 0) call sub(Jsub)

In most cases these contribute to easy-to-read code. Yet sometimes it leads to a mess (when the test itself is complex).

Equally, I have a single if statement where it’s test is incredibly long…

                    if (line(1:1) .ne. 'c' .and. line(1:1) .ne. 'C'     &
     &              .and. line .ne. oldline(linecount)) then
                        write (lunit, '(a)') line
                    end if

In the case of the single-line example, where the code gets difficult to read, I am converting these to…

if (Jsub .gt. 0) then
    call sub(Jsub)
end if

(I wouldn’t - haven’t - in this particular case, since it is easy to read; but it acts as an example).

And in the case of the multi-line test, I am thinking of resorting to nested if statements…

                    if (line(1:1) .ne. 'c' .and. line(1:1) .ne. 'C') then
                        if *line .ne. oldline(linecount))) then
                            write (lunit, '(a)') line
                        end if
                    end if

The thing is, would these have significant impact upon processing speed, once compiled?

I can’t see how the first one would (I am sure it would compile to the same) and I believe it is the same for the latter example, but wondered if anyone had experience of this?

Thanks in advance.

I think the various ways of writing the if blocks should have about the same speed and that you should write them in the most legible way. Note that since the Fortran .and. does not short circuit, a common reason to write

if (a) then
   if (b) call foo()
end if

is to ensure that condition b is only evaluated if condition a is true. In your case condition a should be the one that is fastest for the compiler to evaluate.

4 Likes

First, make your code work correctly. Only then should you consider modifications to make the program faster. In order to make your code correctly, you have to know the rules of the language well.

Here is an example of the implications. Suppose you wish to know if a data file is “fat”, where “fat” stands for “at least 80 percent of the lines in the file have more than 132 characters”. If you write

 if (opened(file) .and. num_big_lines .ge. 0.8*num_lines)then ...

and opened(file) is not .true., it is possible that the two variables starting with “num” are not even defined. However, the Fortran language allows the sub-expressions to be evaluated in any order, and allows some evaluations to be skipped. Even sub-expressions whose value can have no effect on the result may nevertheless get evaluated. Therefore, this IF statement can cause program failure if the file has not been opened and the values of the variables num_… have not been established or have incorrect values.

3 Likes

For big complicated conditionals, I will often save them into a logical variable with a descriptive name first, and then use that in the conditional statement:

should_i_write_this_line = line(1:1) .ne. 'c' .and. line(1:1) .ne. 'C' .and. line .ne. oldline(linecount)
if (should_i_write_this_line) then
    write (lunit, '(a)') line
end if
6 Likes

I love this idea; why have I never seen this before?!?!

I know EXACTLY where I intend to do this; thank you.

It comes in handy if the same conditional gets repeated multiple times too.

I’d also suggest that it is better to name logical variables like a mathematical proposition that evaluates to either true or false, like i_should_write_this_line or this_line_should_be_written.

Another option:

associate (should_i_write_this_line => line(1:1) .ne. 'c' .and. line(1:1) .ne. 'C' .and. line .ne. oldline(linecount))
    if (should_i_write_this_line) then
        write (lunit, '(a)') line
    end if
end associate

This way you don’t have to declare should_i_write_this_line at the top of your subprogram and it makes it clear that it is only used once.

1 Like

I don’t know what a mathematical proposition is, but your way definitely reads better:

if (i should write this line)

However, reading the conditional again and guessing at the intent I would probably name it

line_is_not_comment_or_old

This gives a clear meaning as to what the conditional is actually testing for.

1 Like