So, this made me laugh and scratch my head at the same time.
I had a feedback from some colleagues stating they were having strange results running a given type of computation. Long story short, I then debugged the code using their input data, and realised that it was a bug of this type:
skip = 1
do while (skip <= NM_EFF__ .and. peak_ext_lims_(2, skip) <= bpw_ext_2)
skip = skip + 1
enddo
In fact, their example was that the second conditon was never met for any index in subscript 2. But, to avoid overflow (which actually happened), I put the first guard condition, to bound the increasing of the index skip. But clearly, not meeting the first condition didn’t help avoiding evaluating the second peak_ext_lims_(2, skip) <= bpw_ext_2, which at that moment, was reading one-index-off the allowed range.
I mean, shouldn’t binary logical .and. avoid evaluating the next conditions as soon as it detects a 0-evaluated one?
The Fortran standard neither requires nor prohibits such short-circuiting, and if you want condition A to be evaluated before condition B, you must write
if (A) then
if (B) then
! do something
end if
end if
The committee has discussed short-circuiting many times. The sentiment is generally against implicit short-circuiting, as the standard currently allows evaluation of any equivalent expression to any degree of completeness. Requiring short-circuiting would hinder some optimizations.
The programmer is required to write the expression such that it doesn’t matter which way the compiler chooses to evaluate it. This gives the compiler the maximum flexibility in the evaluation order, factoring out common subexpressions, lifting expressions outside of loops, and so on.
As noted above, this does not place any constraints on the programmer who might prefer a specific evaluation order. In this case, the programmer can use nested if statements to achieve that order.
In this sense, the fortran semantics choice is optimal, and one wonders why all languages don’t do it this way.
do skip = 1, NM_EFF_
if (peak_ext_lims(2, skip)>bpw_ext_2) exit
end do
And you can check if the condition have been met by looking at the value of the variable skip after the loop.
It will be equal to NM_EFF_ + 1 if the condition have not been met.
This looks like it constructs an intermediate logical array and then searches for the location of the first .true. value, but most compilers will optimize away the intermediate array and inline the tests. In this case, skip would be zero if no element is found.
If you are only interested if there is a successful test somewhere in the array, but you don’t care about its array index, then
if ( any(peak_ext_lims(2, 1:NM_EFF_)>bpw_ext_2) ) then
! test successful, do whatever is appropriate...
endif
would work. The compiler would typically optimize away the intermediate logical array in this expression too.
I don’t think there is any performance differences in any of these choices, so the best option is the one that is the simplest and clearest code. That depends in part on what happens after this test and if/how the integer skip is used.
This looks interesting, since I do care about the index, if it exists.
And since the array is actually sorted in increasing order, a binary search would be best (which maybe findloc hides behind?), but didn’t put it in place since usually here we deal with small array sizes.
I apprecciate the hint, thanks!
Just got hit by “short-circuiting” assumption