Home > Software design >  Fortran: if (any(foo == (/1,2,3,4/)) instead of if ((foo == 1).or.(foo == 2).or. ...?
Fortran: if (any(foo == (/1,2,3,4/)) instead of if ((foo == 1).or.(foo == 2).or. ...?

Time:03-01

I have numerous if statements that read something like

if ((foo == 1).or.(foo == 2).or.(foo == 3).or.(foo == 4)) then
   call bar1
end if
if ((foo == 3).or.(foo == 4).or.(foo == 5).or.(foo == 6)) then
   call bar2
end if

Are there any reasons (w.r.t. speed, style, etc.) to not use something like this?

if (any(foo == (/1,2,3,4/))) call bar1
if (any(foo == (/3,4,5,6/))) call bar2

Addition: In my real example the numbers are not necessarily sequentially. So I can not use

if ((foo >= 1).and.(foo <=4)) call bar1
if ((foo >= 3).and.(foo <=6)) call bar1

Addition2: the overlap of the two if conditions is deliberate, which makes it in my understanding impossible to use the SELECT CASE statement

CodePudding user response:

Converting my comment to an answer so the question can be ticked off ...

With regards to the speed part of the question - if this is a concern for you then test and measure. If you don't think it's worth your time testing and measuring then (a) you're probably right, I don't think that I have ever worked on a significant Fortran program where the speed differences between the two approaches could have been of material interest; and (b) it's not worth my time either!

As to the style - that part of the question is off-topic here - but I don't find it all objectionable, though I might write a wee function with signature memberQ(foo, list) and the obvious implementation.

CodePudding user response:

High Performance Mark has answered most of your question, but allow me to present a nice alternative method.

Fortran allows operator overloading, and this allows us to overload .in. to see if an item is in a list. The code for this would look like

module in_module
  implicit none
  
  interface operator(.in.)
    module procedure integer_in_integer_list
  end interface
contains
  function integer_in_integer_list(item, list) result(output)
    integer, intent(in) :: item
    integer, intent(in) :: list(:)
    logical :: output
    
    output = any(item==list)
  end function
end module

And then your code simply becomes

if (foo .in. [1,2,3,4]) call bar1
if (foo .in. [3,4,5,6]) call bar2

In my opinion this is the cleanest way of doing this, and it should have similar performance to other methods. You can overload .in. to take other types (including user-defined types) as needed.

  • Related