I cannot work out the error in the script - fortran

I am very new to programming and I cannot debug my program. Whenever I run it it gives the same error:
return type mismatch of function f at (1)
My code is:
real function F(x)
implicit none
real:: x
F=exp(-x)-x
end function
program easycod
implicit none
real::xl,xu,xr,fu,test,xrold,fl,fr
integer ::i
do i=1,50
xr=xrold
xr=(xl+xu)/2.0
fr =F(xr)
fl =F(xl)
test=fl*fr
IF (test>0.0) then
xl=xr
fr=fl
else if (test<0.0) then
xu=xr
end if
if (test==0.0) exit
print*,xr
end do
end program

There are a few things wrong with your code.
First, you are getting a compiler error because you haven't declared your function F in your program:
program easycode
implicit none
real :: xl, xu, xr, fu, test, xrold, fl, fr
real :: F ! <----------------- Add this line
integer :: i
Then you are assigning xr twice, which makes the first one unnecessary. Finally, xold, xl and xr are not initialized and can therefore be given any value the compiler would like.

Related

When passing function name as argument, the function does not take array as input [duplicate]

This question already has answers here:
How to pass array to a procedure which is passed as an argument to another procedure using Fortran
(2 answers)
Closed 1 year ago.
I'm writing a subroutine that can take function names are argument.
In my example, it is call call_test(ga), where ga is a function ga(x).
My old practice works fine if x is a scalar.
The problem is the program failed if x is an array.
The minimal sample that can reproduce the problem is the code below:
module fun
implicit none
private
public :: ga, call_test
contains
subroutine call_test(fn)
double precision,external::fn
double precision::f
double precision,dimension(0:2)::x0
x0 = 0.111d0
print*,'Input x0=',x0
print*,'sze x0:',size(x0)
f = fn(x0)
print*,'fn(x0)=',f
end subroutine call_test
function ga(x) result(f)
double precision,dimension(0:) :: x
double precision::f
print*,'size x inside ga:',size(x)
print*,'x in ga is:=',x
f = sum(x)
end function ga
end module
program main
use fun
call call_test(ga)
end program main
Using latest ifort, my execution result is:
Input x0= 0.111000000000000 0.111000000000000 0.111000000000000
sze x0: 3
size x inside ga: 140732712329264
forrtl: severe (174): SIGSEGV, segmentation fault occurred
Image PC Routine Line Source
a.out 000000010C6EC584 Unknown Unknown Unknown
libsystem_platfor 00007FFF20610D7D Unknown Unknown Unknown
a.out 000000010C6C62B2 _MAIN__ 32 main.f90
a.out 000000010C6C5FEE Unknown Unknown Unknown
Using gfortran the result is
Input x0= 0.11100000000000000 0.11100000000000000 0.11100000000000000
sze x0: 3
size x inside ga: 0
x in ga is:=
fn(x0)= 0.0000000000000000
My question is why is this, and how to make it work. A functional code solution based on my code is highly appreciated.
#IanBush is right in his comment. You need an explicit interface as the function argument takes an assumed-shape dummy argument. Since you have some other deprecated features in your code, here is a modern reimplementation of it in the hope of improving Fortran community coding practice,
module fun
use iso_fortran_env, only: RK => real64
implicit none
private
public :: ga, call_test
abstract interface
function fn_proc(x) result(f)
import RK
real(RK), intent(in) :: x(0:)
real(RK) :: f
end function fn_proc
end interface
contains
subroutine call_test(fn)
implicit none
procedure(fn_proc) :: fn
real(RK) :: f
real(RK) :: x0(0:2)
x0 = 0.111_RK
write(*,"(*(g0,:,' '))") 'Input x0 =',x0
write(*,"(*(g0,:,' '))") 'sze x0:',size(x0)
f = fn(x0)
write(*,"(*(g0,:,' '))") 'fn(x0) =', f
end subroutine call_test
function ga(x) result(f)
real(RK), intent(in) :: x(0:)
real(RK) :: f
write(*,"(*(g0,:,' '))") 'size x inside ga:',size(x)
write(*,"(*(g0,:,' '))") 'x in ga is:',x
f = sum(x)
end function ga
end module
program main
use fun
call call_test(ga)
end program main
Note the use of the abstract interface. The import statement merely imports the symbol RK for usage within the abstract. Without it, you will have to use iso_fortran_env to declare RK as real64. Do not use double precision, it is deprecated and does not necessarily mean 64bit real number. Also, note the conversion of 0.111d0 to 0.111_RK. Also, I strongly recommend not using single-letter variable names. They are ugly, error-prone, and non-informative. Modern Fortran allows variable names up to 63 characters long. There is no harm in having long but descriptive variable names. Here is the code output,
$main
Input x0 = 0.11100000000000000 0.11100000000000000 0.11100000000000000
sze x0: 3
size x inside ga: 3
x in ga is: 0.11100000000000000 0.11100000000000000 0.11100000000000000
fn(x0) = 0.33300000000000002

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.

Fortran infinite loop when calling a function

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

How to use a function inside a subroutine in Fortran?

Could anyone please tell me why this simple program give me a segmentation fault?
I'm using gfortran, and I need to use a function inside a subroutine.
program tst
implicit none
real z,x,y
x=10.
y=2.
call s(10.,10.,z)
print*,z
end program
real function c(x,y)
implicit none
real x, y
c = x*y
return
end
subroutine s(x,y,z)
implicit none
real x, y
real z
real c
z = c(x,y)
end
Better to put your procedures into a module so that their interfaces will be known to each other and any procedure or program useing the module:
module MyStuff
contains
function c(x,y)
implicit none
real :: c
real :: x, y
c = x*y
return
end
subroutine s(x,y,z)
implicit none
real :: x, y, z
z = c(x,y)
end
end module MyStuff
program tst
use MyStuff
implicit none
real z,x,y
x=10.
y=2.
call s(10.,10.,z)
print*,z
end program
It works, giving answer 100.

Need to read a file and assign its content to a function

I am a novice to Fortran 90 and stack overflow, and I have a simple question (I think).
I have a file, named Eq1, containing the following Fortran mathematical expression:
x**2
The objective is to input this expression from the file, and use it in a function inside fortran. I have tried the following
REAL FUNCTION f(x)
IMPLICIT NONE
REAL (kind =8), INTENT(IN) :: x
open(1,file = 'Eq1',status='old')
read(1,*) f
close(1)
END FUNCTION f
and when I do
print *, f(0.1d+0)
inside the main program, I get the following error message:
Fortran runtime error: Bad real number in item 1 of list input
Thanks for the help!
Cheers
Fortran does not have a string evaluation functionality as some script languages, e.g. Python's eval().
You have to write your own string to expression parser, which is not a trivial task.
One simple workaround is to call Python's eval() with SYSTEM and use it's output:
REAL FUNCTION f(x)
IMPLICIT NONE
REAL (kind =8), INTENT(IN) :: x
CHARACTER(LEN=200) EXP
CHARACTER(LEN=400) CMD
open(1,file = 'Eq1',status='old')
read(1,*) exp
close(1)
WRITE(CMD, "(A,f14.7, A, A, A)") 'python -c "x=',x,';print ',trim(exp), '" > out.txt'
CALL system(CMD)
open(2,file = 'out.txt',status='old')
read(2,*) f
close(2)
END FUNCTION f
program calc
implicit none
real f
print *, f(0.1d+0)
print *, f(2.0d+0)
print *, f(3.0d+0)
print *, f(4.0d+0)
end program calc
Output:
9.9999998E-03
4.000000
9.000000
16.00000