I have written a simple program in Fortran90 to calculate the area of a triangle. The user enters the three sides of the triangle, and then the program outputs the area. Simple enough.
MODULE Triangle_Operations
IMPLICIT NONE
CONTAINS
FUNCTION Area(x,y,z)
REAL :: Area ! function type
REAL, INTENT( IN ) :: x, y, z
REAL :: theta, height
theta = ACOS((x**2+y**2-z**2)/(2.0*x*y))
height = x*SIN(theta); Area = 0.5*y*height
END FUNCTION Area
END MODULE Triangle_Operations
PROGRAM Triangle
USE Triangle_Operations
IMPLICIT NONE
REAL :: a, b, c, Area
PRINT *, 'Welcome, please enter the &
&lengths of the 3 sides.'
READ *, a, b, c
PRINT *, 'Triangle''s area: ', Area(a,b,c)
END PROGRAM Triangle
When I compile this with gfortran gfortran triangle1.f90, this is the error I receive:
triangle1.f90:16.25:
REAL :: a, b, c, Area
1
triangle1.f90:14.8:
USE Triangle_Operations
2
Error: Symbol 'area' at (1) conflicts with symbol from module 'triangle_operations', use-associated at (2)
triangle1.f90:19.13:
READ *, a, b, c
1
Error: Symbol 'a' at (1) has no IMPLICIT type
triangle1.f90:19.16:
READ *, a, b, c
1
Error: Symbol 'b' at (1) has no IMPLICIT type
triangle1.f90:19.19:
READ *, a, b, c
1
Error: Symbol 'c' at (1) has no IMPLICIT type
Why exactly would there be an error thrown for variables a,b,c? I have explicitly defined these as reals.
The problem is that you've defined Area twice -- once in your main program and once in the module you import and the names conflict. You likely think you need to define Area in the main program as a holdover from earlier (darker) times when calling a function without an explicit interface. In modern Fortran, modules provide interfaces automatically and the statement use Triangle_operations is enough.
To fix your problem, remove the delcaration of Area from your main program, e.g. turn
REAL :: a, b, c, Area
into
REAL :: a, b, c
The subsequent errors in your compile output are a result of the first error concerning Area. That entire line gets invalidated so the type declarations of a, b, and c are not processed and this cause the compiler to complain about missing types the next time they are encountered. These errors will go away once you make the fix suggested above.
If your intent had been to have a variable named Area in your main program to store the result of the module's function call, you could rename the module symbol, e.g.
use triangle_operations, triangleArea => Area
and then do this:
real a, b, c, Area
Area = triangleArea(a,b,c)
in your main program.
Related
I am new to Fortran and I am trying on the common block. My code is simple
program main
implicit double precision (p)
real * 8 :: x, y
common /yvalue/ y
x = 3d0
y = 3d0
print *, power(x)
end program main
function power(x)
implicit none
real * 8 :: power
real * 8 :: x, y
common /yvalue/ y
power = x ** y
end function power
It works but if I comment out the second line, which implicitly declares variables starting with p to be double precision, the compiler complains the following
Error: Return type mismatch of function ‘power’ at (1) (REAL(4)/REAL(8))
I do get the point that the return value power is by default a single precision variable, but why declaring power as double precision in the function is not enough? And why writing real * 8 power in main would not work either?
When a procedure (function or subroutine) that you are trying to invoke in your code lays outside the body of your program and also is not part of any module, it's named an external function (or subroutine).
Fortran is a statically-typed language, so the types of all variables and functions must be known at compile-time. So, if you want to reference an external function in your program, there must be a way for the program to know its return type. You have 3 (bad) options for this, and I'll list them, starting from the worst:
WORST: Rely on an implicit-typing rule that happens to match the return type of the external function with the type associated with its identifier in the caller (as you did in your sample).
Why you shouldn't do that? Because it is cancer. It makes the meaning of the code obscure, you can't know what this name reference to. It may even look just like an array variable in some circumstances, instead of a function. Also, the compiler doesn't check argument conformance in this case, so if you don't have specific compiler options turned on, the code will fail at runtime, or worse, will give wrong results. Moreover, implicit-typing is very very rarely useful these days, most of the time it's an ask for trouble. Always use implicit none!
As you noted, by the default rules of implicit-typing, any variable with a name starting with p will be default real type (in your compiler, it is real(4)). As you declared the function result as real*8, that your compiler interpret as real(8) (see final note), the error arises.
BAD: Declare the function's name and type in the caller's specification area.
You'd do that just like you'd declare a variable, like this:
program main
implicit none
real*8 :: x, y, power
By the way, the attribute external may be applied to external procedures like yours. More than giving some properties to the procedure (can be passed as an actual argument, disambiguation from intrinsic procedures), it would make the origin of the identifier clearer.
program main
implicit none
real*8 :: x, y, power
external :: power
Why you shouldn't do that? There is no argument checking by the compiler either. This severely limits your options for communicating to external functions: the arguments cannot be assumed-shape, assumed-rank, polymorphic, parameterized, coarray, or be declared on the callee side as allocatable, optional, pointer, target, asynchronous, volatile or value; the return type cannot be an array, or pointer, or allocatable; the function cannot be passed as argument, be elemental and, if pure, can't be used in such contexts. And the reason for all this is the lack of an explicit interface.
ACCEPTABLE: Specify an interface for your external function in the caller.
Like this:
program main
implicit none
interface
real*8 function power(y)
real*8 :: y
end function
end interface
This way, the compiler is able to know all details of declaration and all the restrictions I mentioned won't apply. Total freedom and code clarity!
Why you shouldn't do that? Because there is a better way, that is using modules! Well, it's totally ok to do this in contexts were you can't go for modules, e.g. when working with already existent large old code. The downside is that, you have almost the same code in two different places, and they must always match.
Bonus: BETTER: Use modules.
program main
use :: aux_module
implicit none
real*8 :: x, y
common /yvalue/ y
x = 3d0
y = 3d0
print *, power(x)
end
module aux_module
implicit none
contains
function power(x)
real*8 :: power
real*8 :: x, y
common /yvalue/ y
power = x ** y
end
end
Why you should definitely do that? Because with modules, interfaces are automatically and implicitly available (less code duplication, no restrictions); modules can be recompiled separately and updated without breaking code. Also, you can declare shared variables in the scope of the module and avoid using common declarations. An even better version of your code would be:
program main
use aux_module
implicit none
real*8 :: x
x = 3d0
y = 3d0
print *, power(x)
end
module aux_module
implicit none
real*8 :: y
contains
function power(x)
real*8 :: power
real*8 :: x
power = x ** y
end
end
There is even the option to include your functions directly into your program, after contains. This is recommended only if you don't plan to reuse this function in other program units. #IanBush's answer covers this case.
Final note: take a look on this answer to see why the syntax real*8 is non-standard and should be avoided.
As stated in the comments simply declaring the function in not only its own scope but also the scope that it is called will solve your problem. However I also want to discourage you from using common, implicit typing, and the completely non-standard real*8. As such here is a version of your program in a more modern dialect
ian#eris:~/work/stackoverflow$ cat power.f90
Program power_program
Implicit None
Integer, Parameter :: wp = Selected_real_kind( 14, 70 )
Real( wp ) :: x, y
x = 3.0_wp
y = 3.0_wp
! Return type and kind of the function power in scope
! due to the implicit interface
Write( *, '( 3( a, 1x, f0.6, 1x ) )' ) &
'x =', x, 'y = ', y, 'x**y = ', power( x, y )
Contains
Pure Function power( x, y ) Result( r )
Real( wp ) :: r
Real( wp ), Intent( In ) :: x
Real( wp ), Intent( In ) :: y
r = x ** y
End Function power
End Program power_program
ian#eris:~/work/stackoverflow$ gfortran -std=f2003 -Wall -Wextra -O power.f90
ian#eris:~/work/stackoverflow$ ./a.out
x = 3.000000 y = 3.000000 x**y = 27.000000
ian#eris:~/work/stackoverflow$
I would like to compute the cross product of two vectors in Fortran 90. For example, in words, the cross product of (1, 2, 3) and (4, 5, 6) turns out to be (-3, 6, -3) in Cartesian coordinates. I wrote the following code (main program followed by function definition):
PROGRAM crosstest
IMPLICIT NONE
INTEGER, DIMENSION(3) :: m, n
INTEGER, DIMENSION(3) :: cross
INTEGER, DIMENSION(3) :: r
m=(/1, 2, 3/)
n=(/4, 5, 6/)
r=cross(m,n)
END PROGRAM crosstest
FUNCTION cross(a, b)
INTEGER, DIMENSION(3) :: cross
INTEGER, DIMENSION(3), INTENT(IN) :: a, b
cross(1) = a(2) * b(3) - a(3) * b(2)
cross(2) = a(3) * b(1) - a(1) * b(3)
cross(3) = a(1) * b(2) - a(2) * b(1)
END FUNCTION cross
But, I get an error message:
crosstest.f90:10.9:
r=cross(m,n)
1
Error: Rank mismatch in array reference at (1) (2/1)
where line 10 is r=cross(m,n). It seems that I must be specifying a dimension incorrectly. Here are a few ideas I have:
Perhaps the declaration of the function cross in the main program should be simply an integer variable, rather than a 1by3 integer array. So I tried deleting the , DIMENSION(3) in the INTEGER, DIMENSION(3) :: cross line in the main program. But I get an error message:
crosstest.f90:10.4:
r=cross(m,n)
1
Error: The reference to function 'cross' at (1) either needs an
explicit INTERFACE or the rank is incorrect
so this is even worse, probably.
Some (but not all) Fortran function examples on the web place an EXTERNAL statement after the function declaration in the main program. So I tried placing a line EXTERNAL cross after the declaration block in the main program. I get an error message:
crosstest.f90:8.16:
EXTERNAL cross
1
Error: EXTERNAL attribute conflicts with DIMENSION attribute at (1)
So this seems incorrect also.
Some (but not all) Fortran function examples on the web place a RETURN statement on the second-to-last line of the function definition. I tried this, but I get the original rank mismatch error:
crosstest.f90:10.9:
r=cross(m,n)
1
Error: Rank mismatch in array reference at (1) (2/1)
So this does not fix the problem.
Can you please help me see my error?
The best practice is to place your procedures (subroutines and functions) in a module and then "use" that module from your main program or other procedures. You don't need to "use" the module from other procedures of the same module. This will make the interface of the procedure explicit so that the calling program or procedure "knows" the characteristics of the arguments ... it allows the compiler to check for consistency between the arguments on both sides ... caller and callee .. this eliminates a lot of bugs.
Outside of the language standard, but in practice necessary: if you use one file, place the module before the main program that uses it. Otherwise the compiler will be unaware of it. so:
module my_subs
implicit none
contains
FUNCTION cross(a, b)
INTEGER, DIMENSION(3) :: cross
INTEGER, DIMENSION(3), INTENT(IN) :: a, b
cross(1) = a(2) * b(3) - a(3) * b(2)
cross(2) = a(3) * b(1) - a(1) * b(3)
cross(3) = a(1) * b(2) - a(2) * b(1)
END FUNCTION cross
end module my_subs
PROGRAM crosstest
use my_subs
IMPLICIT NONE
INTEGER, DIMENSION(3) :: m, n
INTEGER, DIMENSION(3) :: r
m= [ 1, 2, 3 ]
n= [ 4, 5, 6 ]
r=cross(m,n)
write (*, *) r
END PROGRAM crosstest
This is kind of a late answer, but since I stumbled upon this and there is no real explanation yet for why your error occurred, I figured I'd add an explanation for everybody else who stumbles upon this question:
In your program, you define an array called cross, which is of rank 1. Then you call the cross function you define further down. Since the cross function does not have an explicit interface (see M.S.B.'s answer), the compiler does not know about it at this point. What it does know about is the array you declared. If you write r = cross(m, n), the compiler thinks you want to access the element at position (m, n) of the array cross. Since this array is of rank 1, but you supplied two arguments, you get the error
rank mismatch in array reference at (1) (2/1)
which means that you supplied two coordinates when the compiler was expecting one.
You can place the subroutines used in a program after a contains keyword within the program. This eliminates the need for creating a module or adding the interface definition.
PROGRAM crosstest
IMPLICIT NONE
INTEGER, DIMENSION(3) :: m, n
INTEGER, DIMENSION(3) :: r
m = (/1, 2, 3/)
n = (/4, 5, 6/)
r = cross(m,n)
print *, r
CONTAINS
PURE FUNCTION cross(a, b)
INTEGER, DIMENSION(3) :: cross
INTEGER, DIMENSION(3), INTENT(IN) :: a, b
cross(1) = a(2) * b(3) - a(3) * b(2)
cross(2) = a(3) * b(1) - a(1) * b(3)
cross(3) = a(1) * b(2) - a(2) * b(1)
END FUNCTION cross
END PROGRAM crosstest
The complier interpretes the cross in your main program as an array, rather than a function name. Therefore cross in your main program has nothing to do with the function you defined. To let the compiler know that cross is a function name, you can just define in your main program:
INTEGER :: cross
Then, when the compiler see the line r=cross(m,n), the compiler know that this is not array indexing since cross is not defined as an array in the main program. Then a remaining possiblity is that this is a function call, and Fortran compiler ususally adopt this possiblity.
For your case, the compiler finds out that the cross function returns an array rather than a scalar. For this case, the compiler insists that you provide an explicit interface for cross. So this workaround does not work for your case. As other anwsers suggest, you need to provide an explicit interface by either
containing the function definition in a module and use that module in your main program
or
containing the function definition in your main program.
Fortran uses parentheses for both function call and array indexing.
This design often causes confusion because a programmer can not figure out f(3) is a function call or array indexing without additional information.
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.
How do you check values in Fortran like in Matlab? For example in the little program under, why does it show c=0 in main when it is c=36 in the subroutine testing? How do you make it so c=36 in the main program?
Can you call on the value c in some sort of way? I understand that in the main program the variable c is either undefined or has value 0, but is there a way to save the value of c in the subroutine so you can use it again in other subroutines, without calculating it again?
When the program is quite large it is handy to check values as you go.
program main
use test
implicit none
integer :: a,b,c
call testing(a,b)
write(*,*)'Test of c in main program',c
end program main
module test
implicit none
contains
subroutine testing(a,b)
integer :: a,b,c
a=2
b=3
c=(a*b)**a
write(*,*)'Value of c in subroutine',c
end subroutine testing
end module test
It is important to learn about scope in programming languages.
Every name (identifier) has only a limited range of validity.
If you declare some variable inside a subroutine
subroutine s
integer :: i
end subroutine
than the i is valid only in that subroutine.
If you declare a variable in a module
module m
integer :: i
contains
subroutines and functions
end module
then the i is valid inside all those subroutines and functions and also in all program units that use that module.
However, that does not mean that you should declare the variable in the module and just share it. That would be more or less a global variable. This is reserved only for certain cases, where that is necessary, but not for getting results out of your subprograms.
If your subroutine just computes something and you want to get the result of that computation you have two possibilities:
1. pass it as an additional argument, which will be defined by the subroutine
subroutine testing(a, b, c)
integer, intent(in) :: a, b
integer, intent(out) :: c
c = (a*b) ** a
end subroutine
you then call it as
call testing(2, 3, c)
print *, "result is:" c
2. Make it a function
function testing(a, b) result(c)
integer, intent(in) :: a, b
integer :: c
c = (a*b) ** a
end function
and then you can use directly
c = testing(2, 3)
print *, "result is:", c
or just
print *, "result is:", testing(2, 3)
This is the desired behaviour. Basically the calling routine should know nothing about the subroutine except for how to call it and what to get back. This is called encapsulation.
You can make variables accessible to the calling routine by declaring it in the module itself, and not in the subroutine:
module test
implicit none
integer :: c
contains
subroutine testing(a, b)
implicit none
integer :: a, b
a = 2
b = 3
c = (a*b) ** a
write(*, *) "Value of c in the subroutine: ", c
end subroutine testing
end module test
program main
use test
implicit none
integer :: a, b
call testing(a, b)
write(*, *) "Test of c in the main program: ", c
end program main
Note that you must not declare c in the main program, as it will get the variable from the module.
You could also use a COMMON block, but modules are far superior.
Is there a way to check whether aliasing occurs in a Fortran subroutine, or at least to tell the compiler to issue a warning?
Consider this (rather simplistic) example:
module alias
contains
subroutine myAdd(a, b, c)
integer,intent(in) :: a, b
integer,intent(inout) :: c
c = 0
c = a + b
end subroutine
end module
program test
use alias
integer :: a, b
a = 1 ; b = 2
call myAdd(a, b, b)
print *, b, 'is not 3'
end program
Here, the result is set to zero in the subroutine. If the same variable is given as input and output, the result is (obviously) wrong. Is there a way to capture this kind of aliasing at run-time or at compile-time?
Yes, gfortran will detect some aliasing with the compiler option -Waliasing, however, the arguments must have intents in and out. It won't work with your example because you have declared argument c as intent(inout). In this example you can simply change the intent to out since the input value of c is not used. They try the compiler option! gfortran outputs:
alias.f90:17.16:
call myAdd(a, b, b)
1
Warning: Same actual argument associated with INTENT(IN) argument 'b' and INTENT(OUT) argument 'c' at (1)
I don't know of options in g95 or gfortran to detect the aliasing error at compile or run time. The programmer is responsible for avoiding such an error. You can pass the intent(in) arguments as expressions to ensure that they are not changed within the subroutine, as shown below.
module alias
contains
subroutine myAdd(a, b, c)
integer,intent(in) :: a, b
integer,intent(inout) :: c
c = 0
c = a + b
end subroutine myadd
end module alias
program test
use alias, only: myadd
integer :: a, b
a = 1 ; b = 2
call myAdd((a),(b),b) ! parentheses around arguments a and b
print*, b,"is 3"
call myAdd(a, b, b)
print*, b,"is not 3"
end program test