Tomas Aschan
Tomas Aschan

Reputation: 60574

Why does the second if-clause even execute?

I have a do while loop in my program, who's condition to continue keeps giving me off-by-one errors and I can't figure out why. It looks like this:

do while (ii .le. nri .and. ed(ii) .le. e1)
    ! do some stuff...
    ii = ii + 1
end do

where ii and nri are scalar integers, e1 is a scalar real, and ed is a real array of length nri. What I expect to happen after the last run is that since ii.le.nri returns .false. the second condition is never tested, and I don't get any off-by-one problems. I've verified with the debugger that ii.le.nri really does return .false. - and yet the program crashes.

To verify my assumption that only one condition is tested, I even wrote a small test program, which I compiled with the same compiler options:

 program iftest
     implicit none

     if (returns_false() .and. returns_true()) then
         print *, "in if block"
     end if
 contains
     function returns_true()
         implicit none
         logical returns_true
         print *, "in returns true"
         returns_true = .true.
     end function

     function returns_false()
         implicit none
         logical returns_false
         print *, "in returns false"
         returns_false = .false
     end function
 end program

Running this program outputs, as I expected, only

 $ ./iftest
 in returns false

and exits. The second test is never run.

Why doesn't this apply to my do while clause?

Upvotes: 1

Views: 232

Answers (2)

M. S. B.
M. S. B.

Reputation: 29391

Extending the answer High Performance Mark, here is one way to rewrite the loop:

ii_loop: do

  if (ii .gt. nri) exit ii_loop
  if (ed(ii) .gt. e1) exit ii_loop

  ! do some stuff

  ii = ii + 1

end do ii_loop

Upvotes: 4

High Performance Mark
High Performance Mark

Reputation: 78316

In contrast to some languages Fortran does not guarantee any particular order of evaluation of compound logical expressions. In the case of your code, at the last go round the while loop the value of ii is set to nri+1. It is legitimate for your compiler to have generated code which tests ed(nri+1)<=e1 and thereby refer to an element outside the bounds of ed. This may well be the cause of your program's crash.

Your expectations are contrary to the Fortran standards prescriptions for the language.

If you haven't already done so, try recompiling your code with array-bounds checking switched on and see what happens.

As to why your test didn't smoke out this issue, well I suspect that all your test really shows is that your compiler generates a different order of execution for different species of condition and that you are not really comparing like-for-like.

Upvotes: 7

Related Questions