Unexpected Statement Function at 1 in Fortran - fortran

I am new to Fortran and writing this small program to write out 100 ordered pairs for a circle.
But I get the error mentioned above and I don't know how to resolve.
implicit real*8(a-h,o-z)
parameter(N=100)
parameter(pi = 3.14159265358979d0)
integer*8 k
dtheta=2*pi/N
r=1.0d0
x00=0.0d0
y00=0.0d0
do k=0,N-1
xb(k)=r*cos(k*dtheta)-x00
yb(k)=r*sin(k*dtheta)-y00
enddo
open(64,file='xbyb.m',status='unknown')
write(64,*) (xb(k),k=0,N-1),(yb(k),k=0,N-1)
close(64)
end

You do not declare the arrays xb and yb.
Although not technically FORTRAN 77 I still suggest using implicit none or at least an equivalent compiler option to be forced to declare everything explicitly. Implicit typing is evil and leads to bugs.
As High Performance Mark reminds, the syntax
f(k) = something
declares a feature (now obsolescent in Fortran 95 and later) called a statement function. It declares a function of one argument k. The only way for the compiler to recognize you mean an array reference instead is to properly declare the array. The compiler complains the statement function is unexpected because the declaration must be placed before the executable statements.
Your implied do loop in the write statement is Fortran 90 anyway, so no need to stick to FORTRAN 77 in the 21st century.
Other tips:
status='unknown' is redundant, that is the default, just leave it out.
You can just write r = 1 and x00 = 0.

Related

gfortran compiler error calling recursive log_gamma function

I uploaded a 2F1 hypergeometric function but it turns out that it does not compile on my computer. It is from this article. I use
GNU Fortran (Built by Jeroen for the R-project) 8.3.0
shiped with RTools 4.0. Can you figure out why it does not compile and how this could be solved? In the code below, I just kept the one line that generates the error. The error is given next.
MODULE HYP_2F1_MODULE
!--------------------------------------------------------------------
IMPLICIT NONE
INTEGER, PARAMETER :: PR=KIND(1.0D0)
REAL(PR) :: ONE=1.0D0
CONTAINS
!
END MODULE HYP_2F1_MODULE
!
!----------------------------------------------------------------------
RECURSIVE FUNCTION LOG_GAMMA(Z) RESULT(RES)
USE HYP_2F1_MODULE
IMPLICIT NONE
COMPLEX(PR),INTENT(IN) :: Z
COMPLEX(PR) :: RES
!
RES = LOG_GAMMA( ONE -z);
!
END FUNCTION LOG_GAMMA
Here is the error message
testZ.f90:18:22:
RES = LOG_GAMMA( ONE - Z);
1
Error: 'x' argument of 'log_gamma' intrinsic at (1) must be REAL
There is a Fortran 2008+ intrinsic of the same name
16.9.119 LOG_GAMMA (X)
1 Description. Logarithm of the absolute value of the gamma function.
2 Class. Elemental function.
3 Argument. X
shall be of type real. Its value shall not be a negative integer or
zero.
There is some sort of clash I do not completely understand here. The obvious workaround is to rename your function. What I can say is that without the result clause (which you need because of the recursive attribute) the intrinsic would be shadowed. It might be a compiler bug.
Also consider, whether the intrinsic of the same name couldn't also do what you need from your function.
In addition to #VladimirF's suggestions, you can add the compiler flag -std=f95 to enforce compliance with the Fortran 95 standard. Provided you haven't added -fall-intrinsics this will disable all intrinsics from standards after Fortran 95, and should make the legacy code work.

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.

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.

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.

Determining type of variables not declared at top of Fortran subroutine

I am working with a legacy Fortran 77 code subroutine where the parameter types are not declared at the top of the code block.
Here is a snippet showing the very top of the subroutine.
SUBROUTINE BPASS(F1,F2,F3,F4,SI,N,A,IERR)
REAL * 4 A( N ),FV( 4 )
From the above, I think that A is an array of length N with type REAL *4, equivalent in size to a C float. Alternately, FV(4) is an array of length 4 with type REAL *4.
However, what are the types of F1,F2,F3,F4,SI,N,IERR, if the types are not listed? It appears that N should be an integer.
I need to know the types so that I can call the subroutine from C++ code. Is there a Fortran convention for the types that are not declared?
By default Fortran will assign the type integer to variables whose names begin with the letters I,J,K,L,M,N and type real to all other undeclared variables.
I agree with your parsing of the definitions of A and FV.
Modern Fortran provides the expression implicit none for ensuring that the default rules are not applied, but when working with old codes it's sometimes not possible to avoid familiarity with the old dark ways.
In FORTRAN77, by default variables starting with I, J, K, L, M, or N are INTEGER, otherwise they are REAL. FORTRAN90, and some variants of FORTRAN77, provide a mechanism to disable this by using IMPLICIT NONE.