I have a subroutine called several times in an if-then-goto loop.The subroutine has two input arguments:
1.is a constant
2.is an array of definite size(i.e 200X1) whose elements change in a do loop right before the subroutine is called.
The problem is that subroutine doesn't understand that change and returns the same results every time it is called (i.e the results of the first time that it is called).It seems as if the values of all variables that are calculated inside the sudroutine are somehow saved and do not change although input atgument no.2 changes..
Is something wrong with my code?Is there a Fortran bug i'm not aware of?
My code looks like this:
PROGRAM calcul.f
REAL aa(100000),dd(100000),mm(100000),yy(100000),hh(100000),mn(100000),ss(100000),ml(100000),m0(100000)
INTEGER N,snv
DOUBLE PRECISION m0(100000),excerpt(1000),k1(100000),sqsum,s2,vk1,mk1,sdk1,v
filelength=610
W=200
OPEN (1,file='filename.dat')
DO i=1,filelength
READ (1,*) aa(i),dd(i),mm(i),yy(i),hh(i),mn(i),ss(i),ml(i),m0(i)
END D0
CLOSE (1)
10 FORMAT(g12.6)
11 FORMAT(I5,1x,g12.6)
c1=1
c2=W
snv=0
14 IF ((c2.LT.filelength).AND.(c1.LT.(filelength-(W-1)))) THEN
DO i=c1,c2
excerpt(i)=m0(i)
END DO
CALL calk1(W,excerpt)
OPEN (3,file='meank1.dat')
READ (3,*) N,mk1
OPEN (2,file='resultsk1.dat')
DO i=1,N
READ (2,*) k1(i)
END DO
sqsum=0.0d0
DO i=1,N
sqsum=dble(sqsum+((k1(i)-mk1)**2))
s2=sqsum
END DO
vk1=(s2)/N
sdk1=dsqrt(vk1)
OPEN (4,file='resultsv.dat')
v=dble(sdk1/mk1)
snv=snv+1
WRITE (4,11) snv,v
CLOSE (2)
CLOSE (3)
mk1=0.0d0
vk1=0.0d0
sdk1=0.0d0
v=0.0d0
c1=c1+1
c2=c2+1
GOTO 14
END IF
CLOSE (4)
END
My subroutine is:
SUBROUTINE calk1(winlength,sm)
DOUBLE PRECISION sm(100000),sumk1,sum,s,x,x2,k1,sk1,mk1
INTEGER snk1
OPEN (2,file='resultsk1.dat')
10 FORMAT (g12.6)
start=1
w=winlength
c3=6
snk1=0
sumk1=0.0d0
sk1=0.0d0
13 IF (c3.LE.w) THEN
l1=1
l2=c3
c=c3
12 IF ((l1.LE.(w-5)).AND.(l2.LE.w)) THEN
sum=0.0d0
s=0.0d0
DO k=l1,l2
sum=sum+sm(k)
s=sum
END DO
av=0.0d0
av2=0.0d0
x=0.0d0
x2=0.0d0
DO k=l1,l2
av=av+dble(((k)/(c))*(sm(k)/s))
av2=av2+dble((((k)/(c))**2)*(sm(k)/s))
x=av
x2=av2
END DO
k1=x2-((x)**2)
sumk1=sumk1+k1
snk1=snk1+1
WRITE (2,10) k1
l1=l1+1
l2=l2+1
k1=0.0d0
GOTO 12
ELSE
c3=c3+1
GOTO 13
END IF
END IF
CLOSE (2)
N=snk1
sk1=sumk1
mk1=dble((sk1)/N)
OPEN (3,file='meank1.dat')
WRITE (3,10) N,mk1
CLOSE (3)
RETURN
END
I haven't attempted to compile the code (I see there are still some errors that would upset a compiler), but I can suggest a problem.
However, the first thing to say is: if this is your code you'll make things much easier for yourself if you use much more modern Fortran features.
You say that excerpt changes each time before the subroutine is entered. This is true, but not in a meaningful way. Let's look at what is happening to the array.
This is all looped:
c1=1
c2=W
DO i=c1,c2
excerpt(i)=m0(i)
END DO
CALL calk1(W,excerpt)
c1=c1+1
c2=c2+1
Well, W isn't changed in an interation. In this first iteration you are (using array syntax) setting excerpt(1:W)=m0(1:W); in the second setting excerpt(2:W+1)=m0(2:W+1), and so on. That is: each time you call calk1, excerpt(1:W) is still exactly m0(1:W) which hasn't changed. The only change to excerpt is after the W-th element, which you suggest won't be used in the subroutine anyway.
As to what you should do instead with that excerpt setting loop, I can't say: it depends on what you want to happen. Perhaps
DO i=c1,c2
excerpt(i-c1+1) = m0(i)
END DO
?
But use modern Fortran instead.
When I try to compile this I get numerous compiler warnings and errors. I suggest using maximum compile-time warning options from our compiler and clean up those problems. That will clear out some problems with minimal effort. With gfortran, try -O2 -ffixed-form -ffixed-line-length-none -W -Wall -pedantic -fimplicit-none -Wsurprising -Waliasing -Wimplicit-interface -Wunused-parameter -fcheck=all -pedantic -fbacktrace.
Indenting your code with help you understand it. And why use FORTRAN 77 in 2014? Fortran 95/2003 is much easier to program in.
Related
I am working on a large Fortran code, where parts are written in FORTRAN77.
There is a piece of code, which causes debugger to raise errors like:
Fortran runtime error:
Index '2' of dimension 1 of array 'trigs' above upper bound of 1
but when compiled without debugging options runs and does not crash the program. Debugging options used:
-g -ggdb -w -fstack-check -fbounds-check\
-fdec -fmem-report -fstack-usage
The logic of the problematic piece of code is following: in file variables.cmn I declare
implicit none
integer factors,n
real*8 triggers
parameter (n=32)
common /fft/ factors(19), triggers(6*n)
Variables factors and triggers are initialized in procedure initialize:
include 'variables.cmn'
...
CALL FFTFAX(n,factors,triggers)
...
FFTFAX is declared in another procedure as:
SUBROUTINE FFTFAX(N,IFAX,TRIGS)
implicit real*8(a-h,o-z)
DIMENSION IFAX(13),TRIGS(1)
CALL FAX (IFAX, N, 3)
CALL FFTRIG (TRIGS, N, 3)
RETURN
END
and lets look at procedure FFTRIG:
SUBROUTINE FFTRIG(TRIGS,N,MODE)
implicit real*8(a-h,o-z)
DIMENSION TRIGS(1)
PI=2.0d0*ASIN(1.0d0)
NN=N/2
DEL=(PI+PI)/dFLOAT(NN)
L=NN+NN
DO 10 I=1,L,2
ANGLE=0.5*FLOAT(I-1)*DEL
TRIGS(I)=COS(ANGLE)
TRIGS(I+1)=SIN(ANGLE)
10 CONTINUE
DEL=0.5*DEL
NH=(NN+1)/2
L=NH+NH
LA=NN+NN
DO 20 I=1,L,2
ANGLE=0.5*FLOAT(I-1)*DEL
TRIGS(LA+I)=COS(ANGLE)
TRIGS(LA+I+1)=SIN(ANGLE)
20 CONTINUE
In both FFTFAX and FFTRIG procedures there are different bounds for dimensions of arguments than the actual input array size (for TRIGS it is 1 and 19, respectively).
I printed out TRIGS after calling FFTFAX in no-debugger compilation setup:
trigs: 1.0000000000000000 0.0000000000000000\
0.99144486137381038 0.13052619222005157 0.96592582628906831\
0.25881904510252074 0.92387953251128674 0.38268343236508978\
...
My questions are:
Is notation :
DIMENSION TRIGS(1)
something more than setting bound of an array?
Why is the program even working in no-debugger mode?
Is setting:
DIMENSION TRIGS(*)
a good fix if I want variable trigs be a result of the procedure?
In f77 statements like the DIMENSION TRIGS(1) or similar or ..(*) with any number, if pertaining an argument of the procedure just tells the compiler
the rank of the array, the length in memory must be assigned to the array which is given in the call of the subroutine, normally f77 does not check this!
My recommendation either use (*) or better reformat (if necessary) the f77 sources to f90 (the bits shown would compile without change...).
and use dimension computed using n in the declaration within the subroutines/procedures.
Fortan passes arguments by address (i.e. trigs(i) in the subroutine just
will refer on the memory location, which corresponds to the address of trigs(1) + i*size(real*8).
A more consisted way to write the subroutine code could be:
SUBROUTINE FFTRIG(TRIGS,N,MODE)
! implicit real*8(a-h,o-z)
integer, intent(in) :: n
real(kind=8) :: trigs(6*n)
integer :: mode
! DIMENSION TRIGS(1)
.....
PI=2.0d0*ASIN(1.0d0)
.....
or with less ability for the compiler to check
SUBROUTINE FFTRIG(TRIGS,N,MODE)
! implicit real*8(a-h,o-z)
integer, intent(in) :: n
real(kind=8) :: trigs(:)
integer :: mode
! DIMENSION TRIGS(1)
.....
PI=2.0d0*ASIN(1.0d0)
.....
To answer your question, I would change TRIGS(1) to TRIGS(*), only to more clearly identify array TRIGS as not having it's dimension provided. TRIGS(1) is a carry over from pre F77 for how to identify this.
Using TRIGS(:) is incorrect, as defining array TRIGS in this way requires any routine calling FFTRIG to have an INTERFACE definition. This change would lead to other errors.
Your question is mixing the debugger's need for the array size vs the syntax excluding the size being provided. To overcome this you could pass the array TRIGS's declared dimension, as an extra declared argument, for the debugger to check. When using "debugger" mode, some compilers do provide hidden properties including the declared size of all arrays.
The following code compiles, but I do not think that it should. As you can see, the output is garbage.
This is a minimal failing example of something that bit me hard in a large project I work on.
My question is - why does the compiler not complain? Is this a compiler limitation, or is this somehow "expected behaviour", and I've missed something?
I'm using gfortran 4.6.3.
module dataModule
integer :: datum1 = int(1)
integer :: datum2 = int(2)
end module dataModule
program moduleTest
use dataModule, only: datum1
write(*,*) "datum 1 is", datum1
write(*,*) "datum 2 is", datum2
end program moduleTest
Example output:
datum 1 is 1
datum 2 is 4.58322689E-41
Your code is at fault, not the compiler. If datum2 were use associated despite the only clause and if the explicit initialization of datum2 were ignored, then yes, that would be a naughty compiler.
The answer is much more mundane, though.
datum2 is not use associated: in the absence of implicit none it is an implicitly typed variable in the main program. The "garbage" comes from the fact that it is not defined, by initialization or assignment, before its value is referenced and that it's implicitly (default) real. The compiler isn't required to detect this mistake at compile (or run) time.
So I want this to find me the roots of a polynomial. However, everytime I run it, it never gives me any roots, even if I use an obvious one like 2x-2. Why won't it work?
Input "Degree?",θ
Disp "Left to right"
Disp "coefficients"
1→V
For(Z,0,θ)
Input A
Q→R
P→Q
O→P
N→O
M→N
L→M
K→L
J→K
I→J
H→I
G→H
F→G
E→F
D→E
C→D
B→C
A→B
If V=1
Then
A→S
V=0
End
End
For(T,–A,A)
For(U,–W,W)
If T≠0
U/T→X
RX+Q→Y
YX+P→Z
ZX+O→Y
YX+N→Z
ZX+M→Y
YX+L→Z
ZX+K→Y
YX+J→Z
ZX+I→Y
YX+H→Z
ZX+G→Y
YX+F→Z
ZX+E→Y
YX+D→Z
ZX+C→Y
YX+B→Z
If Z=0
Then
Disp X
End
End
End
prgmRESET
RESET just resets the variable values. What is wrong with it?
Request: I have absolutely no idea what operation you are working off of, if you could please state that
Observation: You're using a lot of variables that haven't had any value assigned to them or initially cleared, I can see that you're trying to create a 'stream' of variables to work with, but if you do this without clearing the variables ahead of time then you create problems in your later calculations.
Coding Recommendations:
You state V=0, which does nothing in this context, instead of assigning it a value
You can change 'If T≠0' into just 'If T'
In your third 'For()' statement, "W" is undefined in the code.
You can change 'If Z=0:Then:Disp X:End', near the end of your code, into just 'If not(Z:Disp X'
Move prgmRESET to the top of your program
To be honest, I'm not entirely sure how you code is supposed to find the routes of a polynomial. Your error is most likely occurring somewhere in your mess of variable assigning/reassigning/swapping. I would redo your code using lists instead of basic variables.
If all you want to do is find the routes of a polynomial, I can give you a program for that.
:Prompt L1,X
:Repeat 1=dim(L1
:dim(L1->dim(L3
:seq(L1(A)(Ans-A),A,1,Ans-1->L2
:Repeat abs(Ans)<10^(-7
:L1(1->L3(1
:For(A,2,dim(L1
:XL3(A-1)+L1(A->L3(A
:End
:Ans->B
:L2(1->L3(1
:For(A,2,dim(L2
:XL3(A-1)+L2(A->L3(A
:End
:Ans^-1(AnsX-B->X
:B
:End
:Disp X
:L1(1->L2(1
:For(A,2,dim(L1)-1
:XL2(A-1)+L1(A->L2(A
:End
:L2->L1
:End
I'm not quite sure what you're trying to do here. You use a whole lot of variables without ever clearing or defining them, which probably means that all of your values will be 0.
Also, recommendation for future TI-BASIC questions:
PLEASE explain your variables. There's nothing worse than having a mess of variables and expecting the reader to do detective work to find out what they're supposed to do. Plus, it's helpful for you as well when you decide to come back to it for troubleshooting.
When I compile the following Fortran code with gfortran and run it, it gives me 'signal SIGBUS: Access to undefined portion of a memory object', whenever n>=180. I'm running this on a Mac OSX Mavericks.
PROGRAM almatrix
IMPLICIT NONE
INTEGER :: i,j,n
REAL,ALLOCATABLE :: a(:,:)
READ(*,*)n
ALLOCATE(a(n+1,n+1))
DO i=0,n
DO j=0,n
a(i,j)=0.0
END DO
END DO
DEALLOCATE(a)
END PROGRAM almatrix
I understood that instead of
ALLOCATE(a(n+1,n+1))
this
ALLOCATE(a(n+1,n+1),STAT=err)
IF(err /= 0) STOP
would prevent crashing. It didn't, however. Why?
I tried to look at similar problems, but so far they haven't helped.
I tried to compile with -Wall, -g, -fcheck=all, as suggested in another answer, but those didn't give me warnings.
I've also noticed before, that unlike with C, Fortran usually does not give bus errors when using small dynamic arrays and not deallocating them.
The problem isn't directly with the allocate statement, but with accessing the resulting array. [Note also that that an array 181x181 is not "large".] As there is nothing wrong with the allocation, err will indeed be zero.
From that allocate one is left with an array a which has elements a(1,1), a(2,1), ..., a(n+1,1), ..., a(n+1,n+1). So, a(0,0) (the first access in the loop) is not valid.
There are two options: request that the array elements be a(0,0) to a(n,n) as the loop wants, or change the loop:
allocate(a(0:n,0:n))
or
do i=1,n+1
do j=1,n+1
a(j,i) = 0 ! Note I've changed the order to Fortran-friendly
end od
end do
Finally, those loops aren't even necessary:
allocate(a(0:n,0:n))
a = 0.
or even
allocate(a(0:n,0:n), source=0.)
if you have a compiler later than Fortran 95.
I'm currently working on converting some Fortran code into parallel using openMP. I'm trying to use omp_get_wtime() to calculate how much actual time passes, but its returning ******. Other OpenMP functions work, yet for some reason this doesn't. I've removed all the code from in between the timer just to try to get something different. Removing the finish, and just displaying the start gives the same result. Any ideas of what I'm doing wrong would be much appreciated.
C$ USE OMP_LIB
DOUBLE PRECISION START,FINISH
START = OMP_GET_WTIME()
FINISH=OMP_GET_WTIME()
WRITE(OUT,850) FINISH-START
850 FORMAT(25X,'ELAPSED TIME',I6)
Your problem has nothing to do with the OMP_GET_WTIME function. Rather it stems from the fact that the I edit descriptor is used to display integers and you are feeding it with a double precision number instead. You should use one of the floating-point edit descriptors like, e.g. F10.6:
$ cat wtime.f
USE OMP_LIB
IMPLICIT NONE
DOUBLE PRECISION START,FINISH
START = OMP_GET_WTIME()
CALL SLEEP(1)
FINISH=OMP_GET_WTIME()
WRITE(*,850) FINISH-START
850 FORMAT(25X,'ELAPSED TIME',F10.6)
END
$ ifort -openmp -o wtime.exe wtime.f
$ ./wtime.exe
ELAPSED TIME 1.000277