Is there locally saved data (like Fortran's) in Julia? - fortran

I am currently trying to re-write an entire Fortran 77 code into Julia. Within this Fortran code, there are various local variables with the SAVE attribute (from a SAVE statement or when explicitly initialized in a DATA statement).
The problem is: I haven't been able to reproduce the same outcome that one would expect with these saved variables in Fortran. For example, the code have many random generator programs extracted from the Numerical Recipies. In particular, ran3.f, called not only from within the main program, but from many different subroutines within it.
The ran3.f states:
FUNCTION ran3(idum)
c Returns a uniform random deviate between 0.0 and 1.0.
c Set idum to any negative value to initialize or reinitialize the sequence.
INTEGER idum
INTEGER MBIG,MSEED,MZ
REAL ran3,FAC
PARAMETER (MBIG=1000000000,MSEED=161803398,MZ=0,FAC=1./MBIG)
INTEGER i,iff,ii,inext,inextp,k
INTEGER mj,mk,ma(55)
SAVE iff,inext,inextp,ma
DATA iff /0/
if(idum.lt.0.or.iff.eq.0)then
CODE ... Etc, etc...
return
end
I have been able to reproduce the same results (random numbers) given a particular seed, and also to behave across the entire program and subroutines according to what is expected, but it was only by using a lot of returning variables and input variables.
How can the two lines
SAVE iff,inext,inextp,ma
DATA iff /0/
be replaced in Julia in order to acomplish the same behavior?

To translate the code using SAVEed data or COMMON blocks as closely as possible, we can probably use a constant, global, mutable struct variable (placed in the top-level scope), e.g.
mutable struct myfunc_common_t # or simply "type" in older versions
num :: Int
# constructors if necessary
end
const myfunc_common = myfunc_common_t( 0 )
function myfunc( idum )
com = myfunc_common
if idum < 0
com.num = 100
else
com.num += 1
end
#show com.num
end
function myshow()
#show myfunc_common.num
end
myfunc( -1 )
myfunc( 123 )
myfunc( 456 )
myfunc( 789 )
myshow()
which gives
com.num = 100
com.num = 101
com.num = 102
com.num = 103
myfunc_common.num = 103
The use of such constant globals are type-stable (as seen from #code_warntype) but it may be not suitable for parallel calculations (so be careful...). If possible, I think it would be nice to pass some type variable to a function explicitly (and mutate it within a function, or return a new type variable from the function). Indeed, "idum" is like a "state" variable, so we can replace it as a type variable :)

Related

Fortran DO loop, warning to use integer only

I installed gfortran on my Ubuntu 15.04 system. While compiling Fortran code, the DO loop asks to take integer parameters only and not real values or variables. That includes the loop variable and the step expression. Why can't it take real values too?
The following is a program taken from here, exercise 3.5 of the section nested do loops.
program xytab
implicit none
!constructs a table of z=x/y for values of x from 1 to 2 and
!y from 1 to 4 in steps of .5
real :: x, y, z
print *, ' x y z'
do x = 1,2
do y = 1,4,0.5
z = x/y
print *, x,y,z
end do
end do
end program xytab
The error shown after compiling is:
xytab.f95:8.4:
do y = 1,4,0.5
1
Warning: Deleted feature: Loop variable at (1) must be integer
xytab.f95:8.12:
do y = 1,4,0.5
1
Warning: Deleted feature: Step expression in DO loop at (1) must be integer
xytab.f95:7.3:
do x = 1,2
1
Warning: Deleted feature: Loop variable at (1) must be integer
The Fortran standard now requires that a do construct's loop control is given by (scalar) integer expressions and that the loop variable is a (scalar) integer variable. The loop control consists of the start, step, and stop expressions (your step expression is 0.5). See R818 and R819 (8.1.6.2) of the Fortran 2008 document. That, then, is the short and simple answer: the standard says so.
It's a little more complicated than that, as the messages from the compiler suggest. Using other forms for loop control was present in Fortran up until Fortran 95. That is, from Fortran 95 onward using real expressions is a deleted feature.
What harm is there in using real expressions? Used correctly, one could imagine, there is no harm. But there's real difficulty in portability with them.
Consider
do x=0., 1., 0.1
...
end do
How many iterations? That would be (under the rules of Fortran 90) MAX(INT((m2 ā€“ m1 + m3) / m3), 0) where (m1 is the start value (0.), m2 the stop value (1.) and m3 the step value (0.1)). Is that 10 or 11 (or even 9)? It depends entirely on your numeric representation: we recall that 0.1 may not be exactly representable as a real number and INT truncates in converting to integer. You'd also have to worry about repeated addition of real numbers.
So, use integers and do some arithmetic inside the loop
do y_loop = 0, 6
y = 1 + y_loop/2.
...
end do
or
y = 1
do
if (y>4) exit
...
y = y+0.5
end do
Finally, you mention .f90 and .f95 file suffixes. gfortran doesn't take the first to mean that the source code follows the Fortran 90 standard (where the code would be fine). Further, the messages from the compiler are merely warnings, and these can be suppressed using the -std=legacy option. Conversely, using -std=f95 (or later standards) these become errors.
As a bonus fun fact consider the following piece of Fortran 90 code.
real y
integer i
loop_real: do y=1, 4, 0.5
end do loop_real
loop_integer: do i=1, 4, 0.5
end do loop_integer
While the loop named loop_real is valid, that named loop_integer isn't. In the calculation of the iteration count the three expressions are converted to the kind, with kind parameters, of the loop variable. INT(0.5) is 0.

Scope of subroutine parameters in FORTRAN 77

I have a subroutine that declares i and passes it to other small subroutines. Within those small subroutines there are declared other variables with the same name, i.e i, and it is internally used. Once out of the small subroutines, one would expect to have the same i value that was originally passed, however that is not the real situation and i contains the value of the last parameter assigned within the small subroutines. Here is a brief example:
subroutine smallSub1(i)
integer i,start,end
start=i
end = start +10
do i=start, end
write(*,*) i
enddo
end subroutine smallSub1
subroutine caller
integer i
i = 1
call smallSub1(i)
write(*,*) i
end subroutine caller
My question is, how could I avoid this behavior in F77?
My concern here is: think about a situation where a subroutine is a black box, and you just need to pass an integer, but you do not want that integer value to change from the smallSub1 subroutine. The variables start and end would depend on the value of i however they should not replace the original value of i out of smallSub1
As noted in the other answer, Fortran typically passes by reference and when that is not possible it does things like copy-in/copy-out. As said succinctly by others in comments, if you don't want to change i then don't change i.
In your subroutine smallSub1, i is being used as a loop iteration variable and and you don't want its value changes visible to the caller. The reason changing i is visible to caller is because i isn't a local variable, it is a dummy argument. The solution is call the loop variable and the dummy argument by different names. One such solution is:
subroutine smallSub1(i_from_caller)
integer i,i_from_caller,start,end
start = i_from_caller
end = start +10
do i=start, end
write (*,*) i
end do
end subroutine smallSub1
In this case the dummy argument has been renamed to i_from_caller and is used to initialize start. Now the loop variable i is truly local to the subroutine (as it is no longer the name of a dummy argument) and changing i here won't change i in caller
To help avoid this kind of behavior you can give the compiler hints that dummy arguments are for input, output or both. If you had declared i as integer, intent(in) :: i in smallSub1 in your original example, the compiler would complain:
do i=start, end
1
Error: Dummy argument ā€˜iā€™ with INTENT(IN) in variable definition context (iterator variable) at (1)
making you aware that you are making unwanted changes to a dummy argument.
In the code example given there are two variables i: one in each subroutine. In subroutine caller the i is a local variable, and in the subroutine smallSub1 it is a dummy argument.
When you have call smallSub1(i) you are associating the two i variables with each other through argument association. In this simple case, then, any change to i in smallSub1 affects the i in caller. There is how argument association works here.
Traditionally one did have black-boxes where an argument is changed in the subroutine when that wasn't desired. Where it is used as a work-space, for example. In that case, one would do something like
inew = i
call smallSub1(inew)
... continue using i
In this case, however, one can easily (I imagine) change the subroutine. Introduce an extra local variable:
subroutine smallSub1(i)
integer i ! Dummy argument - we don't want to change it
integer start,end
integer j ! Local variable - we're quite free to change it
! In general, we'd have j=i at the start and use that instead
start=i
end = start +10
do j=start, end
write(*,*) j
enddo
end subroutine smallSub1
And with modern Fortran one even has the value attribute, which can be applied to the dummy argument allowing one to change it without impact on the actual argument.
from https://gcc.gnu.org/onlinedocs/gfortran/Argument-passing-conventions.html
Fortran passes most arguments by reference
Therefore, if you don't want the variable to change, don't change it in the subroutine. You are allowed to rename the variable smallSub1(i) to smallSub1(j)
you don't want to change the entire function.

fortran result variable Not initiallized

I met a surprsing problem about loacal variable initializing.
I got following function to calculate gammar
function gammar(z) result(gz)
implicit none
real(8),intent(out)::gz
real(8)::z,t,low,up
real(8),parameter::increment=1.0
real(8),parameter::lower_t=0.0,upper_t=10.0
integer(4)::i,n
!gz=0.0
n=(upper_t-lower_t)/increment
do i=1,n
low=lower_t+(i-1)*increment
up=lower_t+(i)*increment
gz=gz+(f(z,low)+f(z,up))*increment/2.0
end do
end function gammar
Then I call this function in main program like
df=9.0
t=0.0
write(*,*) gammar((df+1.0)/2.0)/sqrt(pi*df)/gammar(df/2.0)
I got wrong answer!! 0.126
I found the reason was after gammar((df+1.0)/2.0) was calculated, the local variable gz was not set to 0.
Hence ,when calculate gammar(df/2.0), the gz still retained old value 24. Eventually,gammar(df/2.0) got wrong answer 34..
If I add gz=0.0 in the gammar function, this problem was fixed.
This is really surprising. Why the local gz was not initiallized to zero when the gammar called every time?
Thanks a lot
Regards
Ke
Unless you have a statement to initialize a local variable in a procedure, such as the gz = 0 that you have commented out, those local variables are not initialized when the procedure is invoked. Their values are undefined. They could have a value left from a previous invocation, or some random value.
If you use full warning options of the compiler, it will likely tell you of this problem. gfortran warned of an uninitialized variable at compile time. ifort detected the problem at run time.
Another initialization method is with a declaration. That still doesn't repeat the initialization of additional invocations of the procedure. If you initialize a local variable in a procedure with a declaration, such as integer :: count = 0, that initialization is only done on the first invocation on the procedure. But ... the variable remains defined and on the next invocation will retain that value that it had when the previous invocation exited.
P.S. real(8) is not a portable way to obtain double precision reals. The language standard does not specify specific numeric values for kinds ... compilers are free to whatever value they wish. Most compilers use the number of bytes, but use other numbering methods. It is better to use selected_real_kind or the ISO_FORTRAN_ENV and (for double precision) real64. See quad precision in gfortran
P.P.S. Trying this code with gfortran, that compiler points out another problem with gz:
function gammar(z) result(gz)
1
Error: Symbol at (1) is not a DUMMY variable
So remove the intent(out) in the declaration.

equivalence statement

Code:
program CheckEquivalence
integer*8 intarray(4)
real*8 realarray(4)
equivalence(realarray,intarray)
realarray(3) = 3
intarray(4) = 4
realarray(1) = 1.0
realarray(2) = 2.0
do i = 1,4
write(,) 'All real ', realarray(i)
enddo
do i = 1,4
write(,) 'All int ', intarray(i)
enddo
do i = 1,3
write(,) 'Some real ', realarray(i)
enddo
write(,) 'Last int ', intarray(4)
end
output is:
All real 1.
All real 2.
All real 3.
All real 1.97626258E-323
All int 4607182418800017408
All int 4611686018427387904
All int 4613937818241073152
All int 4
Some real 1.
Some real 2.
Some real 3.
Last int 4
I tried one sample code to understand how equivalence works.
My query is in which format internally data is getting stored
and any algorithm from which I can get theoretical same value?
As answered here:
equivalence statements in fortran
There is no conversion between the two values. It is stored based on what you write to the variable and interpreted based on how you access it. So if you write to the REAL a real-value, and then try to print the integer variable, you will get garbage. And vice versa.
Generally speaking, do not use EQUIVALENCE statements. They are a bad idea and deprecated. If you are writing new code, don't put them in -- if you are trying to interpret old code, they are typically used to create compact storage in memory by reusing the same location for different purposes.
Yes, as already answered there is extremely little reason to use EQUIVALENCE. It was commonly used decades ago to conserve memory by overlapping arrays. It can also be used for low-level non-portable manipulations. If you store a real number and output as an integer, the results will be non-portable, outside of the language standard, depending on the numeric representation of the hardware that you are using. There are occasional reasons to do bit-level manipulations, e.g., if you read in binary data and then determine what type it is. Or to do byte-swapping. The modern replacement for EQUIVALENCE is the "transfer" intrinsic function.

Fortran SAVE statement

I've read about the save statement in the (Intel's) language reference document, but I cannot quite grasp what it does. Could someone explain to me in simple language what it means when the save statement is included in a module ?
In principal when a module goes out-of-scope, the variables of that module become undefined -- unless they are declared with the SAVE attribute, or a SAVE statement is used. "Undefined" means that you are not allowed to rely on the variable having the previous value if you again use the module -- it might have the previous value when you re-access the module, or it might not -- there is no guarantee. But many compilers don't do this for module variables -- the variables probably retain their values -- it isn't worth the effort for the compiler to figure out whether a module remains in scope or not and probably module variables are treated as global variables -- but don't rely on that! To be safe, either use "save" or "use" the module from the main program so that it never goes out of scope.
"save" is also important in procedures, to store "state" across invocations of the subroutine or function (as written by #ire_and_curses) -- "first invocation" initializations, counters, etc.
subroutine my_sub (y)
integer :: var
integer, save :: counter = 0
logical, save :: FirstCall = .TRUE.
counter = counter + 1
write (*, *) counter
if (FirstCall) then
FirstCall = .FALSE.
....
end if
var = ....
etc.
In this code fragment, "counter" will report the number of invocations of subroutine x. Though actually in Fortran >=90 one can omit the "save" because the initialization in the declaration implies "save".
In contrast to the module case, with modern compilers, without the save attribute or initialization-on-a-declaration, it is normal for local variables of procedures to lose their values across invocations. So if you attempt to use "var" on an later call before redefining it in that call, the value is undefined and probably won't be the value calculated on a previous invocation of the procedure.
This is different from the behavior of many FORTRAN 77 compilers, some of which retained the values of all local variables, even though this wasn't required by the language standard. Some old programs were written relying on this non-standard behavior -- these programs will fail on the newer compilers. Many compilers have an option to use the non-standard behavior and "save" all local variables.
LATER EDIT: update with a code example that shows incorrect usage of a local variable that should have the save attribute but doesn't:
module subs
contains
subroutine asub (i, control)
implicit none
integer, intent (in) :: i
logical, intent (in) :: control
integer, save :: j = 0
integer :: k
j = j + i
if ( control ) k = 0
k = k + i
write (*, *) 'i, j, k=', i, j, k
end subroutine asub
end module subs
program test_saves
use subs
implicit none
call asub ( 3, .TRUE. )
call asub ( 4, .FALSE. )
end program test_saves
Local variable k of the subroutine is intentionally misused -- in this program it is initialized in the first call since control is TRUE, but on the second call control is FALSE, so k is not redefined. But without the save attribute k is undefined, so the using its value is illegal.
Compiling the program with gfortran, I found that k retained its value anyway:
i, j, k= 3 3 3
i, j, k= 4 7 7
Compiling the program with ifort and aggressive optimization options, k lost its value:
i, j, k= 3 3 3
i, j, k= 4 7 4
Using ifort with debugging options, the problems was detected at runtime!
i, j, k= 3 3 3
forrtl: severe (193): Run-Time Check Failure. The variable 'subs_mp_asub_$K' is being used without being defined
Normally, local variables go out of scope once execution leaves the current procedure, and so have no 'memory' of their value on previous invocations. SAVE is a way of specifying that a variable in a procedure should maintain its value from one call to the next. It's useful when you want to store state in a procedure, for example to keep a running total or maintain a variable's configuration.
There's a good explanation here, with an example.
A short explanation could be: the attribute save says that the value of a variable must be preserved across different calls to the same subroutine/function. Otherwise normally when you return from a subroutine/function, "local" variables lose their values since the memory where those vars were stored is released. It is like static in C, if you know this language.