Reputation: 715
I am an absolute beginner to FORTRAN and am painstakingly converting a 1000 line FORTRAN source file to MATLAB for my own use. I have been going fine so far by putting in heaps of PRINT
statements to keep track of variables and ensure the maths is working correctly. I have come to a strange happening in FORTRAN which I cannot work out.
There is a subroutine which is defined as so
subroutine addprc
complex tmat,b,ci,c1,c2,cim,ab1(50),ab2(50),acans(10,2),fg1(50),fg2(50)
common dtr,rtd,pi
common /mtxcom/ nrank,nranki,tmat(50,50),b(50,50),cmxnrm(25)
common /cmvcom/ nm,kmv,cmv,twm,prodm
There is a bit more common
and dimension
allocations below but they shouldn't be relevant. The very first time the ab1(50)
array is defined is in this subroutine. For my MATLAB script I have initialized it as ab1=zeros(1,50);
. It is then used in this loop (in FORTRAN):
do 20 n = 1,nrank
np = n+nrank
cn = real(n)
n1 = n+1
c1 = 4.0*ci**n
c2 = 4.0*ci**n1
p1 = cn*costh*pnmllg(n1)-(cn+cmv)*pnmllg(n)
p2 = cmv*pnmllg(n1)
ab1(n-ij) = c1*p2*uu1
ab1(np-ijt) = -c2*p1*uu1
ab2(n-ij) = -c1*p1*uu2
ab2(np-ijt) = c2*p2*uu2
I have checked the values of all the other variables at this point and they agree with my MATLAB script. Working backwards I have discovred the problem that somehow the ab1
already contains values. A print command just before the loop e.g.
PRINT *,'before ab1', SUM(ab1)
do 20 n = 1,1
returns (107.500008, 5.38305187)
. It is a complex number so the two values are fine, but whats not fine is the fact it has anything in it at all? Infact the only time ab1
is used at all is in this block of code.
Is there anything I am missing here? I looked in the source file (ctrl-f: ab1) to find any instances of it. The original source is a .for file, and I have compiled them under Eclipse using gfortran. Thanks for your time.
Upvotes: 0
Views: 438
Reputation: 74455
ab1
is small array (50 * 8 = 400 bytes) and is therefore most likely allocated on the program stack. The stack is used to store local variables as well as the return address of the caller whenever a subroutine is called. Initially the stack pages contain all zeros but as subroutines get called it grows and is populated with some numbers. Later when the subroutine returns the stack pointer is changed but the values remain on the stack and are later overwritten by the new calls. When ab1
is allocated, its memory would initially be populated with old stack values that come from previously called subroutines. Most FORTRAN compilers do not generate by default instructions to initialise stack variables as it could be an expensive operation.
If your program is completely deterministic, i.e. there are no subroutine calls that depend on the value of some (pseudo-)random numbers or the initial PRNG seed is always the same, then sans the return addresses all other content of the stack is going to be the same between many executions of your program, e.g. one in the evening and one in the morning.
That's why SUM(ab1)
always returns (107.500008, 5.38305187)
. And it is actually a GoodThing(tm) - it shows that your computer is a deterministic device, i.e. it reproduces the output given the same algorithm and the same input and therefore could be used to execute programming tasks. This is also a BadThing(tm) since predictable stack values lie in the base of many attacks on the OS security, but that lies way outside the scope of your problem.
Upvotes: 2
Reputation: 53644
Just wondering: what you would expect there instead?
These values come from memory. When you call something (function/program/subroutine) that defines a variable some piece of memory is associated with defined variable, but until you assign something to the variable it will use whatever was present in memory before. As computer memory is constantly being reused without being reset you may get there value from a variable from the other called function/subroutine that already ended, a piece of memory from other process (with the exception of some pages that must be emptied by kernel as they may contain private data) or anything else. The general rule is that nobody will do such an expensive operation as setting memory to some value unless he deadly needs this (e.g. like here where you do set memory associated with variables to numbers you need or when not erasing memory is a potential security flaw).
As a summary: these values come from uninitialized memory. Exact contents is undefined.
You do not get errors at accessing uninitialized memory because checking whether memory is initialized is a very expensive operation. But there are tools that will show you errors in this case:
valgrind
. Note that such checks are very expensive: under valgrind you easily get your program running worse then an order of magnitude slower.Upvotes: 1