Tymric
Tymric

Reputation: 300

How to execute a number of statements based on a user input variable (fortran90)?

I am writing a Fortran90 subroutine, but the language does not matter for the purpose of this question. Feel free to provide answers in psuedocode if it's more convenient.

I have a number statements (or groups of statements) to execute based on an input parameter. Let the input variable be x and let's call the statements A, B, C,..., N. These statements do not share enough common properties to be combined, and should therefore be executed separately.

The conditions are:

if ( x .eq. 1 ) then
  ! execute A
endif
if ( x .eq. 2 ) then
  ! execute A
  ! execute B
if ( x .eq. 3 ) then
  ! execute A
  ! execute B
  ! execute C
endif
  .
  .
  .

and so on...

(Note that all the ! execute statements are all mathematical calculations and variable assignments. Nothing is printed, no functions are called, etc...)

My attempt to simplify the code turned it into:

if ( x .ge. 1 ) then
  ! execute A
endif
if ( x .ge. 2 ) then
  ! execute B
endif
if ( x .ge. 3 ) then
  ! execute C
endif
  .
  .
  .

This is still too much coding to do for a large value of x. I know that I have to code all the execute statements (and I have already done so), but I am hoping that there is still a faster way to only run the number that the user specifies without having to type over a hundred if statements. Any thoughts on that?

Upvotes: 2

Views: 169

Answers (5)

agentp
agentp

Reputation: 6989

I might do something like this:

 i=howmany
 do while(i.gt.0)
     < a code >
     i=i-1;if(i.eq.0)exit
     < b code >
     i=i-1;if(i.eq.0)exit
      <c code>
     i=i-1;if(i.eq.0)exit
      <d code>
  exit
 enddo

or equivalently use a subroutine with return.

Note this is logically equivalent to where you started, but the conditional line is the same so a lazy typist can quickly do ctrl-y ctrl-y ctrl-y

Another advantage of this is, should you need to edit the lines you can insert/delete a line anywhere without manually reindexing.

Upvotes: 1

dwwork
dwwork

Reputation: 858

What about a recursive subroutine? Something like this:

recursive subroutine select(x)
    integer,intent(in) :: x
    select case(x)
        case(1)
            !execute A
        case(2)
            !execute B
        case(3)
            !execute C
     end select
     if(x > 0) call select(x-1)
end subroutine select

Again, this goes backwards, but a forward version shouldn't be too hard. And there's always the stack overflow possibility if you have a lot of these. This is essentially getting rid of the explicit loop in the accepted answer.

Upvotes: 1

High Performance Mark
High Performance Mark

Reputation: 78314

Oh what a shame that computed go to is frowned upon. No self-respecting Fortran programmer in C21 would write something like

      ...
      read(*,*) x
      go to (3,2,1) x    

 1    call C()
 2    call B()
 3    call A()

Of course, this executes the calls in the reverse order to that specified in the question, but the question also hints that the order doesn't matter.

I'll close this by reminding readers that this is definitely nasty old FORTRAN. Let us not speak of this again

Upvotes: 6

Alexander Vogt
Alexander Vogt

Reputation: 18098

You could use one-line versions of if:

if ( x .ge. 1 ) call ... ! execute A
if ( x .ge. 2 ) call ... ! execute B
...

Or, if processed within a subroutine or function, you could use return:

call ... ! execute A
if ( x .lt. 2 ) return

call ... ! execute B
if ( x .lt. 3 ) return
...

It's also possible to do this in one line per statement:

call ... ; if ( x .lt. 2 ) return ! execute A
call ... ; if ( x .lt. 3 ) return ! execute B

I don't think it will get less than that, even when using function pointers you would have to point them to the corresponding function/subroutine (which also amounts to one line per function)...

Upvotes: 2

cup
cup

Reputation: 8257

Not exactly an ideal solution since F90 doesn't have function pointers. Could do it in F03 with function pointers but since you have specified F90

subroutine selector(howmany)
   integer, intent(in):: howmany
   integer:: ii

   do ii = 1, howmany
      select case(ii)
      case (1)
         ! execute A
      case (2)
         ! execute B
      case (3)
         ! execute C
      case default
         continue
      end select
   end do
end subroutine selector
...
call selector(3)

Unlike C, fortran doesn't have a dropthrough

Upvotes: 4

Related Questions