Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
27996 Discussions

## SUBROUTINE with Arbitrary Number of Variables Beginner
253 Views

This is probably wishful thinking, but is there a way of passing multiple variables (unknown quantity) to a subroutine and then received by the subroutine as an array? I guess a good anology would be to minic something like the MAX function (where you have MAX(A,B,C, ...).

Below is an example subroutine that reduces entries in a vector based on its total sum.

```  PURE SUBROUTINE VEC_ADJUST_MAXSUM(MAXSUM, VEC)
DOUBLE PRECISION, INTENT(IN)::MAXSUM
DOUBLE PRECISION,DIMENSION(:),INTENT(INOUT):: VEC
INTEGER:: I,J,N
DOUBLE PRECISION:: TOT
!
N = SIZE(VEC) - ONE
TOT = SUM(VEC)
!
DO I=ONE, N
IF(TOT > MAXSUM) THEN
ASSOCIATE(VAL => VEC(I))
!
VAL = MAXSUM
DO CONCURRENT(J=I+ONE:N); VAL = VAL - VEC(J)
END DO
IF(VAL < DZ) VAL = DZ
!
TOT = SUM(VEC)
!
END ASSOCIATE
ELSE
EXIT
END IF
END DO
!
IF(TOT > MAXSUM) THEN
N = N + ONE  !MOVE TO LAST LOCATION
!
IF(MAXSUM < DZ) THEN
VEC(N) = DZ
ELSE
VEC(N) = MAXSUM
END IF
END IF
!
END SUBROUTINE```

The main goal of this is I have a set of variables (with the potential of more standalone ones being added such that the subroutine would called as:

```PROGRAM TEST
IMPLICIT NONE
DOUBLE PRECISION:: MX, A,B,C,D,E

A  = 1D0
B  = 2D0
C  = 3D0
D  = 4D
E  = 5D0
MX = 10D0

END PROGRAM```

The idea is that if the sum of the variables excedes the maxsum (MX) that A is first reduced, then B, then C, ect.

The code will eventually grow with additional variables, which is why this structure would be advantageous.

The suggested subroutine does not work (the INTENT causes it to fail and when I remove that it does not update the variables themselves)

Any suggestions on how to pass an arbitrary number of variables would be great (hopefully something beyond pre-specifying them as optional and having lots of IF(PRESENT()) checks.

Thanks

3 Replies Honored Contributor II
253 Views
`!`

Then array constructor on the call is creating  temp array so you cannot pass back. You could  do,  mytmp = [ a, b, c] where mytmp was an allocatable array and then pass mytmp, that should be OK Black Belt Retired Employee
253 Views

Fortran doesn't have the ability for a programmer to write a procedure that has an arbitrary number of arguments. MAX and MIN are examples of language features that you can't replicate in your own code. Beginner
253 Views

One work around that I did is use a pointer data type. I just wanted to check how safe this is or if it would be better to just create a vector and copy the variables over.

```PROGRAM MAIN

TYPE VAR_VAL
DOUBLE PRECISION, POINTER:: D => NULL()
END TYPE

TYPE VAR_POINTER_LIST
TYPE(VAR_VAL), DIMENSION(:), ALLOCATABLE:: LST
END TYPE

TYPE(VAR_POINTER_LIST):: PNT

DOUBLE PRECISION:: A, B, C, D

ALLOCATE(PNT%LST(4))

CALL SET_VAR(PNT, A, 1)
CALL SET_VAR(PNT, B, 2)
CALL SET_VAR(PNT, C, 3)
CALL SET_VAR(PNT, D, 4)

CALL DO_STUFF_ROUTINE(PNT)  !does stuff to variables A, B, C, and D

END PROGRAM

SUBROUTINE SET_VAR(DTYP, VAR, POS)
TYPE(VAR_POINTER_LIST), INTENT(INOUT):: DTYP
DOUBLE PRECISION, INTENT(IN),TARGET:: VAR
INTEGER, INTENT(IN):: POS

DTYP%LST(POS)%D => VAR

END SUBROUTINE

SUBROUTINE DO_STUFF_ROUTINE(DTYP)
TYPE(VAR_POINTER_LIST), INTENT(INOUT):: DTYP

! Do stuff with arbitrary number of variables

END SUBROUTINE```

In reality what I did was make it a bit more Object Orietented with making type bound procedures that init the vectors size and then add as many variables as needed. Then that vector can handle any local variables as if they were in a vector. I ran some tests and it seems to work, but I was unsure about any pitfalls.

I attached the full fortran module here for any suggestions. 