Reputation: 60574
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
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
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