fortran result variable Not initiallized - fortran

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.

Related

Why do I always get the same result when using function and contains in fortran

I'm trying to do a basic calculation by calling a function using contains
Program main
implicit none
integer*8 Nmax,i
Parameter (Nmax=5)
real*8 x, f(Nmax), n
do i=1, Nmax
n=i
f=func(n,Nmax)
write(*,*) f(i)
end do
Contains
real*8 function func(x,Nmax)
integer*8 Nmax,i
real*8 x, f(Nmax)
do i=1, Nmax-1
f(i)=i**2d0-4d0*i-7d0
end do
end function
end program main
I get this result:
-9.255963134931783E+061
-9.255963134931783E+061
-9.255963134931783E+061
-9.255963134931783E+061
-9.255963134931783E+061
I think I'm making the wrong variable definitions. Thank you for your help.
There are multiple problems with your program.
First, you probably meant to write:
f(i)=func(n,Nmax)
in the main program. Without the subscript you assign the same value to each element of the array. You might think that explains the results, but it doesn't as you'd still see what you expect.
Another problem is highlighted by the following warning I get when I compile your code with Intel Fortran:
t.f90(14): warning #6178: The return value of this FUNCTION has not been defined. [FUNC]
real*8 function func(x,Nmax)
-------------------^
You never assign the value of func, so you get whatever garbage happens to be in the return register.
The function you have isn't really what you want, either. You probably want one that computes and returns a scalar (single) value and hence there is no need for an array inside func.
A third problem is that func is ignoring the n argument (which, contrary to convention, you have declared as a real.)
If you want a loop in the main program, have the function compute and return a single result based on the argument passed to it. There is no need to pass both the loop index and nmax each time. Other options, slightly more advanced, would be to keep the array assignment in the main program but do away with the loop there and either have the function return an array or make the function ELEMENTAL. I will leave it as an exercise for you once you figure out what you really intend here.
Lastly, I would discourage you from using nonstandard syntax such as "real*8". Please learn about KIND specifiers and the SELECTED_REAL_KIND intrinsic function.

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 : Initialize all variables to a specific default value

I am working on a ~40 years old Fortran spaghetti code with lots of variables that are implicitly declared. So there is not a simple way to even know what variables exist in the code in order to initialize their values. Now, is there a way to tell the compiler (for example Intel Fortran) to initialize all variables in the code to a specific default value (e.g., -999) other than zero or a very large number, as provided by Intel compiler?
gfortran provides some options for this. Integers can be intialized with -finit-integer=n where n is an integer. For real numbers you can use -finit-real=<zero|inf|-inf|nan|snan>. Together with -ffpe-trap=denormal this can be very helpful, to get uninitialized reals.
You probably want :
ifort -check uninit
Note per the man page this only checks scalars
Also, based on some quick testing it is a pretty weak check. It doesn't catch this simple thing for example:
program test
call f(i)
end
subroutine f(j)
write(*,*)j
end
returns 0 ..
I suppose its better than nothing though.

If i call a function in fortran, without defining a variable, what happens?

So i have a program, which has something like this in it:
integer :: mgvn, stot, gutot, iprint, iwrit, ifail, iprnt
...
call readbh(lubnd,nbset,nchan,mgvn,stot,gutot,nstat,nbound,rr,bform,iprnt,iwrit,ifail)
And then inside readbh:
CALL GETSET(LUBND,NSET,KEYBC,BFORM,IFAIL)
IF(IFAIL.NE.0) GO TO 99
...
99 WRITE(IWRITE,98) NBSET,LUBND
IFAIL = 1
RETURN
Where all the other variables are defined, but ifail is not. If i add in write(*,*) ifail before the function call, i get the undefined variable error, but if i leave it out, it doesn't complain, and just runs away with the function, and always fails, with IFAIL=1.
Is this because it's just getting to the end of the arguments in the readbh function, reading in uninitialised memory - which is just random jibberish - and then casting those bits to an int - which is not going to be zero unless i'm very (un)lucky, and so nearly always making ifail.ne.0 true?
I'll choose to interpret what you call undefined variable as uninitialised variable. Generally speaking Fortran, and many other compiled programming languages, will quite happily carry on computing with uninitialised variables. It/they are programming languages for grown-ups, it's on our own head if you program this sort of behaviour. It is not syntactically incorrect to write a Fortran program which uses uninitialised variables so a compiler is not bound by the language standard to raise a warning or error.
Fortran does, though, have the facility for you to program functions and subroutines to ensure that output arguments are given values. If you use the intent(out) attribute on arguments which ought to have values assigned to them inside a procedure, then the compiler will check that an assignment is made and raise an error if one is not.
Most compilers have an option to implement run-time checking for use of uninitialised variables. Intel Fortran, for example, has the flag -check:uninit. Without this check, yes, your program will interpret whatever pattern of bits it finds in the region of memory labelled ifail as an integer and carry on.
You write that your function always fails with ifail == 1. From what you've shown us ifail is, just prior to the return at (presumably) the end of the call to readbh, unconditionally set to 1.
From what you've revealed of your code it looks to me as if ifail is intended as an error return code from getset so it's not necessarily wrong that it is uninitialised on entry to that subroutine. But it is a little puzzling that readbh then sets it to 1 before returning.

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.