Fortran infinite loop when calling a function - fortran

Why am I in an infinite loop?
PROGRAM tayls
USE kertoma
USE tforexp
IMPLICIT NONE
INTEGER :: n= 5
INTEGER :: i
REAL :: x
WRITE(*,*) "f1(x)= (e**x-1)/x"
DO i=1,10
x= 0.01*i
WRITE(*,*)x, (taylexp(x,n)-1)/x
END DO
END PROGRAM tayls
with
MODULE tforexp
USE kertoma
IMPLICIT NONE
CONTAINS
FUNCTION taylexp(x,ord)
REAL :: taylexp, x, sum
INTEGER :: ord, i
sum= 1.0
DO i=1,ord
sum= sum+ x**i/fact(i)
END DO
taylexp= sum
END FUNCTION taylexp
END MODULE tforexp
and
MODULE kertoma
IMPLICIT NONE
CONTAINS
FUNCTION fact(n)
INTEGER :: fact,n,y=1
DO WHILE (n>1)
y= y*n
n= n-1
END DO
fact = y
END FUNCTION fact
END MODULE kertoma
The infinite loop starts right after the first print "f1(x)=...".
So I think it goes to infinite loop when calling the taylexp-function for the first time, but I don't understand why.
I think it has got something to do with fortran using public variables, but I'm clueless how to consistently avoid this.
First I tried to call the function without defining x, just using "0.01*i", and I thought maybe the problem was that this function used the same name for the dummy index, but it clearly it didn't solve the problem.

The problem is inside then function fact(n):
n= n-1
changes the argument and, therefore, the loop counter i in taylexp. In your code i never exceeds 2. I'm surprised the compiler didn't issue a warning (mine didn't either), because anything might happen in this case.
Better specify the intent of dummy arguments to avoid issues like this in the future:
FUNCTION fact(n)
integer,intent(in) :: n
INTEGER :: fact,nn,y
y=1 ! Avoid the implicit save and assign variables separately
nn=n
DO WHILE (nn>1)
y= y*nn
nn= nn-1
END DO
fact = y
END FUNCTION fact

With gfortran, it is possible to catch this error with
the -fcheck=all option:
$ gfortran -fcheck=all 1.f90
$ ./a.out
f1(x)= (e**x-1)/x
At line 22 of file 1.f90
Fortran runtime error: Loop variable has been modified

Related

Trouble with declaring a Fortran Function that returns a list [duplicate]

This question already has an answer here:
Function in fortran, passing array in, receiving array out
(1 answer)
Closed 4 years ago.
INTEGER FUNCTION NUMTOLIST(NUM) RESULT(LI)
IMPLICIT NONE
! FUNCTION TO CONVERT NUMBERS INTO ARRAYS OF NUMBERS, BY DIGIT
! PROBLEM 1: X IS NOT BEING PASSED
INTEGER :: NUM
INTEGER :: I,J
INTEGER :: LI(0:5) ! G95 COMPILER SAYS THAT 'LI ALREADY HAS BASIC TYPE INTEGER', DOESN'T RECOGNISE AS ARRAY
PRINT *,'NUM: ',NUM ! DEBUGGING LINE, CONFIRMS THAT X IS NOT BEING PASSED INTO THE FUNCTION
DO I = 0,5
J = 0
DO WHILE (J*10**(5-I)<=NUM)
J = J+1
END DO
J = J-1
LI(I) = J
NUM = NUM-(J*10**(5-I))
END DO
PRINT *,'LI: ',LI ! DEBUGGING LINE, SHOWS THAT FUNCTION IS AS IS SUPPOSED TO, EXCEPT FOR ON SOME SORT OF DEFAULT INTEGER
RETURN
END FUNCTION NUMTOLIST
PROGRAM NUMTOLISTTEST
IMPLICIT NONE
INTEGER FUNCTION, NUMTOLIST
INTEGER :: X
INTEGER :: F(1:6)
READ *,X
PRINT *,X
F = NUMTOLIST(X)
! PROBLEM 2: THE RESULT OF NUMTOLIST SHOULD BE A LIST, BUT F IS JUST BEING ASSIGNED NUM, NOT THE OUTPUT OF NUMTOLIST
PRINT *,F
READ *,X
END PROGRAM NUMTOLISTTEST
Here is my full code. As the name suggests, this is a test for a function of a larger code. There are several problems but the one that is most pressing is that for some reason a variable is not being passed to a function. I am using the silverfrost compiler, and for some reason although everything in the function itself is working as it should, it neither inputs nor returns properly. The input itself is completely disregarded, leading to num being undefined, and the return isn't being read as a list type, as F, when printed, is a list of the arbitrary number num took on. It's completely beyond me why any of this is happening, and I've been on and off looking at this for a couple of days.
Much more trivially, when I try to compile using G95, it won't. It claims that 'Li already has basic type 'Integer'', and then won't recognise Li as a list. The method I'm using to declare an integer as a list has worked in the past for me, and fits the documentation I've seen, so I'm confused why it's throwing an error.
I've been stuck on this for a while, and I just can't seem to fix it on my own. Whatever help is offered will be greatly appreciated, and thank you in advance.
You are indeed declaring a type for the variable LI twice in the function. Look:
INTEGER FUNCTION NUMTOLIST(NUM) RESULT(LI)
! (...)
INTEGER :: LI(0:5)
Notice the INTEGER keyword before function declaration. It applies to the variable name declared as result in result(LI). The second declaration of LI gives the error.
Solutions:
Remove the INTEGER from the function declaration (preferred);
Remove the second type declaration of LI. You can specify a dimension without type declaration, with the dimension specification statement.
like this:
DIMENSION LI(0:5)
Besides that, to call a function with an array as a returning value, you will need an explicit interface.

How to create functions in Fortran?

I'm sure the solution to this is extremely basic, but I'm having a hard time figuring out how to use functions in Fortran. I have the following simple program:
PROGRAM main
IMPLICIT NONE
INTEGER :: a,b
a = 3
b = 5
PRINT *,funct(a,b)
END PROGRAM
FUNCTION funct(a,b)
IMPLICIT NONE
INTEGER :: funct
INTEGER :: a,b
funct = a + b
END FUNCTION
I've tried several variations of this, including assigning a data type before FUNCTION, assigning the result of funct to another variable in the main program and printing that variable, and moving the FUNCTION block above the PROGRAM block. None of these worked. With the current program I get an error on line 6 (the line with the PRINT statement):
Error: Return type mismatch of function 'funct' (UNKNOWN/INTEGER(4))
Error: Function 'funct' has no IMPLICIT type
From all of the guides I've tried, I seem to be doing it right; at least one of the variations, or a combination of some of them, should have worked. How do I need to change this code to use the function?
Simply putting the function in the file will not make it accessible to the main program.
Traditionally, you could simply declare a function as external and the compiler would simply expect to find a suitable declaration at compile-time.
Modern Fortran organizes code and data in "modules". For your purpose, however, it is simpler to "contain" the function within the scope of the main program as follows:
PROGRAM main
IMPLICIT NONE
INTEGER :: a,b
a = 3
b = 5
PRINT *,funct(a,b)
CONTAINS
FUNCTION funct(a,b)
IMPLICIT NONE
INTEGER :: funct
INTEGER :: a,b
funct = a + b
END FUNCTION funct
END PROGRAM main
A simpler solution can be the following code
PROGRAM main
IMPLICIT NONE
INTEGER :: a,b, funct
a = 3
b = 5
PRINT *,funct(a,b)
END PROGRAM
FUNCTION funct(a,b)
IMPLICIT NONE
INTEGER :: funct
INTEGER :: a,b
funct = a + b
END FUNCTION
where the only difference is in the third line, where I have declared funct as an integer. It compiles and it prints 8 as result.

Unused dummy argument and Return value of function not set

This is my Fortran 90 program for Newton-Raphson method. However, it did not compile properly and gave this warning in geany
newraph.f90:18.17:
real function f(x)
1
Warning: Unused dummy argument 'x' at (1)
newraph.f90:18.15:
real function f(x)
1
Warning: Return value of function 'f' at (1) not set
Compilation finished successfully.
program newton_raphson
implicit none
real,parameter::error=1e-4
integer::i
real::xo,x1,f,fd
read*,xo
i=1
10 x1=xo-(f(xo)/fd(xo))
if(abs((x1-xo)/x1)<error) then
print*,"root is", x1,"no. of iteration=",i
else
xo=x1
i=i+1
goto 10
endif
end
real function f(x)
real::x
end
real function fd(x)
real::x
fd=3*x**2-1
end
You have just two warnings. Both just inform you that the function f does nothing:
real function f(x)
real::x
end
Change it to return something useful and the warnings will vanish.
real function f(x)
real, intent(in) :: x
f = x**2
end function
and then change fd to return the derivative of f, like fd = 2*x.
Other than that, try to use some decent programming style. Use indentation, use loops instead of go to where possible. Use vertical spacing (empty lines). Also it is better to use end function, end subroutine and end program for clarity.

Fortran Function error about conflicting with a name in the encompassing scoping unit

I'm new in Fortran. what's the problem with this simple code?
program combinatorial
Implicit none
integer :: m, n, Fact
integer :: Com
Write (*,*) 'inter 2 number for m and n'
Read (*,*) m,n
Com = Fact (m)/(Fact(n)*Fact(m-n))
Contains
integer Function Fact(t)
Implicit none
Integer, intent(IN) :: t
integer :: i, Ans
Ans = 1
Do i=1, t
Ans=Ans * i
End do
Fact = Ans
End Function Fact
End program combinatorial
The error that i encounter is :
combinatorial.f90(10): error #6626: The name of the internal procedure conflicts with a name in the encompassing scoping unit. [FACT]
integer Function Fact(t)
-------------------------^
compilation aborted for combinatorial.f90 (code 1)
Since Fact is contained within the program the compiler will generate an interface to it automatically. By also declaring an integer thing called Fact you're giving the compiler conflicting instructions and it don't like that. Just drop Fact from the line
integer :: m, n, Fact
The encompassing scoping unit referred to by the compiler is the program which contains (or encompasses) the function.
And, as an aside, you don't need to use the variable Ans in your definition of the function. You could simply write
integer Function Fact(t)
Implicit none
Integer, intent(IN) :: t
integer :: i
Fact = 1
Do i=1, t
Fact = Fact * i
End do
End Function Fact
Unless you use a result clause on the function statement the compiler will behave as if it creates a variable of the same name as the function for returning the function's result.

aliasing in fortran with intent in

is it legal (or can it give trubles) to call a fortran subroutine with aliasing if the dummy variables are intent(IN)? I have to do something like this in my code:
program myprogram
......
......
call check(itstrt, itstrt )
do k= itstrt,itend
call check(itstrt, k)
enddo
end
subroutine check(itstrt, k)
integer , intent(in) :: itstrt, k
if(k==itstrt) write(*,*) 'I gotta do something'
end
I know I can easily use an extra variable varPROV=itstrt to call the first check as call check(itstrt, varPROV) but I d like to know what the standard says and which are the trouble of doing that.
thanks
A.
It is legal. The problem with aliasing and with INTENT(IN) (separately) relate to the program trying to define a dummy variable - perhaps by the variable appearing on the left hand side of an assignment statement or similar.