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

How to tame the ancient arrays?

Ivan_S_
Beginner
1,267 Views

The description of problem: I have a very old subprogram which was written for Microsoft Fortran v.5 (DOS, pre-windows era). There are two arrays in program code. The dimensions, the array specifications are (35,40) and (37,38). The program code was written so that it assumed that all elements of array specification that less than 1 are computed, but their values are equal 0. In Intel Fortran, the elements of array specification that less than 1 are computed with the own values. As result, the two summations give two different results of computing compared MS-Fortran and Intel Fortran. I understand that the modern Fortran operates with elements of array specification that less than 0 and negative ones. And the old code is a heritage of Fortran IV. Thus I have a question: how to lock the individual elements of array which are less than 1 and make all calculations with them are equal 0 in order to revert to the scheme of old Fortran.

0 Kudos
10 Replies
mecej4
Honored Contributor III
1,267 Views

Ivan S. wrote:
The program code was written so that it assumed that all elements of array specification that less than 1 are computed, but their values are equal 0. In Intel Fortran, the elements of array specification that less than 1 are computed with the own values.

If you meant to say that, given the two arrays with implicit lower bounds equal to 1, you have code that references the arrays with indices that are zero or negative, the assumption that the values referenced are zero is not only incorrect and against every Fortran standard, but also can be considered a gross violation of coding standards. On MSDOS, such a program probably caused the OS to crash or reboot quite often, given that user and OS programs were not insulated from one another.

You can use the /Qzero option to initialize variables to zero, but referencing arrays with incorrect subscripts is very likely to cause your program to crash. You must fix the out of bounds array references in the code. While you are doing so, you have a good opportunity to initialize the arrays, as well, so that /Qzero is no longer needed.

0 Kudos
andrew_4619
Honored Contributor III
1,267 Views

Ivan, your description is not clear. I think attaching some code or code snippets to illustrate what you mean will allow some answers to be given rather than us all guessing as to the actual problem.

 

0 Kudos
Ivan_S_
Beginner
1,267 Views

No doubt my description is not perfect.

Please look at this code snippet:

[fortran]      ...

      DOUBLE PRECISION CSK,SSK,CG,SG,RV,RR,RSK,RPV,TSK,D1,D2,D3,D4,D5...

      ...

     *,CS(35,40),PDP(37,38)

      ...

      (Common blocks)

      ...

      TSK=SSK/CSK

      D2=AEK/RV

      D3=DSQRT(3D0)

      PDP(1,1)=1D0

      PDP(2,1)=SSK*D3

      PDP(2,2)=CSK*D3

      N=2

      SNR=0D0

      SNSK=0D0

      SNPV=0D0

      I1=1

      I3=35

      I5=3

      I7=35

   14 I2=1

      I4=40

      I6=1

      I8=38

      I=1

      M=0

      SMR=0D0

      SMSK=0D0

      SMPV=0D0

      PN=N

   12 PM=M

      IF(M.EQ.N) GO TO 10

      A2A=PN*PN-PM*PM

      A1A=4.D0+(4.D0*PM*PM-1.D0)/A2A

      A1=SSK*DSQRT(A1A)

      IF(M.NE.N-1) GO TO 15

      PDP(I5,I6)=A1*PDP(I5-1,I6)

      GO TO 9

   15 B1B=(1.D0+4.D0/(2.D0*PN-3.D0))*(1.D0-(2.D0*PN-1.D0)/A2A)

      B1=DSQRT(B1B)

      PDP(I5,I6)=A1*PDP(I5-1,I6)-B1*PDP(I5-2,I6)

      GO TO 9

   10 C1C=1.D0+1.D0/(2.D0*PN)

      C1=CSK*DSQRT(C1C)

      PDP(I5,I6)=C1*PDP(I5-1,I6-1) [/fortran]

The outputs for C1C, C1, and PDP(I5,I6) see below.

[fortran]

    9 IF(I.NE.1) GO TO 11

      I=2

    3 IF(M-1)16,6,7

   16 FS2=0D0

      FC2=1D0

      GO TO 8

    6 FS2=SG

      FC2=CG

      GO TO 8

    7 FS2=FS1*CG+FC1*SG

      FC2=FC1*CG-FS1*SG

    8 FS1=FS2

      FC1=FC2

      SP=CS(I1,I2)*FC1+CS(I3,I4)*FS1

      SPR=SP*PDP(I5,I6)

      SPPV=PM*(-CS(I1,I2)*FS1+CS(I3,I4)*FC1)*PDP(I5,I6)

      I6=I6+1

      IF(N.NE.M) GO TO 17

      PDP(I7,I8)=-PM*TSK*PDP(I5,I6-1)

      GO TO 1

   17 M=M+1

      GO TO 12

   11 M=M-1

      PM=M

      IF(M.EQ.0) GO TO 4

      D4=1.D0

      GO TO 13

    4 D4=.5D0

   13 D4D=DSQRT((PN-PM)*(PN+PM+1.D0)*D4)

      PDP(I7,I8)=-PM*TSK*PDP(I5,I6-1)+D4D*PDP(I5,I6)

    1 SPSK=SP*PDP(I7,I8)

      SMR=SMR+SPR

      SMSK=SMSK+SPSK

      SMPV=SMPV+SPPV

      IF(N.EQ.M) GO TO 2

      M=M+1

      PM=M

      I2=I2+1

      I4=I4-1

      I8=I8-1

      GO TO 3

    2 D5=D2**(N+2)

      SMR=SMR*(PN+1.D0)*D5

      SMSK=SMSK*D5

      SMPV=SMPV*D5

      SNR=SNR+SMR

      SNSK=SNSK+SMSK

      SNPV=SNPV+SMPV

      IF(KG.EQ.N) GO TO 5

      N=N+1

      I1=I1+1

      I3=I3-1

      I5=I5+1

      I7=I7-1

      GO TO 14

    5 RR=...

      ... [/fortran]

1. MS-Fortran v.5.0 (under DOS) gives the following output:

[fortran] C1C,C1,I5-1,I6-1,PDP(I5,I6)       1.250000000000000        1.118033854171124

           2           2   0.000000000000000E+000[/fortran]

2. Intel Fortran (under Windows) gives the following output:

[fortran] C1C,C1,I5-1,I6-1,PDP(I5,I6)       1.25000000000000         1.11803385417112

           2           2   1.93649120690920[/fortran]

The first result is correct. I would like to see 0 in second case.

Any ideas are welcome.

mecej4 wrote:

You can use the /Qzero option to initialize variables to zero...

It is not help to solve the problem.

app4619 wrote:

... your description is not clear. I think attaching some code or code snippets to illustrate ...

Now attached. I will be glad to hear any questions.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,267 Views

While the results may be correct (or at least the way you have been using them all these years), the way it go to the results may be incorrect.

What happens when you compile the Intel Fortran code with all runtime checks enabled, in particular, array index out of bounds.

If your code has index out of bounds, then it is either by design or by accident.

If by design then the old code is relying upon memory placement of the data as expressed in the software on the then targeted system. A lot of things can affect the placement of data such as size of INTEGER and LOGICAL, as well as newer compilers wanting to align arrays. Any such change will cause the intended out of bounds access to hit something other than the intended address.

If by accident, then the same reasons above for different placement in memory may now result in clobbering something important (enough) to show up in your output data.

Please bear in mind, and this may give you an unpleasant feeling, that the first answer is wrong, and the second one is right. Or just as uneasy of feeling, both are wrong.

Jim Dempsey

0 Kudos
mecej4
Honored Contributor III
1,267 Views

The code snippets do not add much useful information. I still do not understand what exactly the problem is, going on the basis of what you have shown so far.

In particular, where are those "all elements of array specification that less than 1",  as you described in #1, to be found in the code snippets of #4? The two lines of output shown in #4 show PDP(3,3), so I don't see any negative indices involved.

The first result is correct. I would like to see 0 in second case.

Correct on what grounds? The rules of Fortran, or the rules of the application domain? Please clarify.

Can you post a complete "reproducer" code? If we could compile and run the complete code, we could see some of the issues that you mentioned.

0 Kudos
Les_Neilson
Valued Contributor II
1,267 Views

Ivan

In your first code snippet on line 24 I6 is set to 1. After label 10 in the same snippet, if the value of I6 has not been modified, the code accesses PDP(I5-2, I6-1) and the second subscript is out of bounds zero. If this really was intentional then the code does not conform to the Fortran standards and presumably relies on that particular behaviour from that particular compiler and OS combination. Other compilers (if there were any at that time) on the same OS might not behave in the same way. Certainly modern compilers with run-time checking can identify this situation - subscript out of bounds.

According to your later comments showing the output of MS-Fortran and Intel Fortran the values of I5-1 and I6-1 are both 2 i.e. greater than zero.

So it would seem from your comments, that the code is expecting PDP(2, 2) to be zero.

It may be that the program was written assuming that all variables / arrays are initialised to zero when the program starts, in which case then perhaps all you need to do is initialise the arrays to zero before they are used.

You should still compile under Intel Fortran Debug mode with all compile and runtime checks enabled.

Les

0 Kudos
Ivan_S_
Beginner
1,267 Views

Les Neilson wrote:

... If this really was intentional then the code does not conform to the Fortran standards and presumably relies on that particular behaviour from that particular compiler and OS combination.

I think you are the only one who understands properly.

I need time to test and answer.

0 Kudos
andrew_4619
Honored Contributor III
1,267 Views

It look like you need to added some branches like:

IF ( I5 < 1 .OR.  I6 < 1) THEN
     SPR  = 0.
ELSE.
     SPR=SP*PDP(I5,I6)
ENDIF

 

0 Kudos
andrew_4619
Honored Contributor III
1,267 Views

or maybe for less coding changes replace all PDP refs with FPDP and "use" the module PDPSORTER

MODULE PDPSORTER
   IMPLICIT NONE
   DOUBLE PRECISION PDP(37,38)

   CONTAINS
   FUNCTION FPDP(I,J)
      INTEGER I,J
      DOUBLE PRECISION FPDP
      IF( I < 1 .OR. J < 1) THEN
         FPDP=0.D0
      ELSE
         FPDP=PDP(I,J)
      ENDIF
   END FUNCTION FDPD
END MODULE PDPSORTER

 

0 Kudos
John_Campbell
New Contributor II
1,267 Views

Ivan,

Most replies suggest that addressing the arrays "out of bounds" is the likely source of your problem. You need to understand what this means.

Compiling with all runtime checks enabled is the easiest way to test this, although with multi-dimensioned arrays, there is the problem of addressing outside the storage area vs addressing outside the range of each subscript.

You could take app4619's approach a step further and test upper bound limits of each subscript, eg

function fpdp (I,J, line_number)
   if ( i < 1 .or. i > 37 .or. j < 1 .or. j > 38 ) then   !  PDP(37,38)
   write (*,*) 'addressing PDP out of bounds at ',line_number, ' : subscripts =',i,j
  fpdp = 0
  else
  fpdp = pdp(i,j)
  end if
end function fpdp

This approach would allow the program to continue to completion, reporting all occurrences.

John

0 Kudos
Reply