I have the following short fortran code.
!==============================================
MODULE PREC
INTEGER, PARAMETER :: q=8
END MODULE PREC
!==============================================
MODULE MOD_FIT
USE prec ! q
TYPE spec
INTEGER HL,HR
COMPLEX(q), POINTER :: HMAT(:,:) ! (HL,HR)
END TYPE
END MODULE MOD_FIT
!==============================================
PROGRAM MAIN
USE prec
USE MOD_FIT ! spec
IMPLICIT NONE
!
TYPE(spec) SMP
write(*,*)'check associated:',associated(SMP%HMAT)
END
I compiled it with the newest version gfortran, and ran it. The following is what I got
check associated: T
Should it be F as I hadn't initialize it at all?
No, the status of your pointer is undefined. You are not allowed to inquire it using associated() because it can result in anything.
What you should always do is to use default initialization of all pointer components and initialize them to null().
TYPE spec
COMPLEX(q), POINTER :: HMAT(:,:) => null()
END TYPE
After that you are guaranteed to get the expected result false.
Related
Gfortran 8.1 and 9.1 give me an error about intrinsic assignment between two polymorphic components into a type variables. I don't have any problem using intel compiler but no in the case in gfortran. I'm asking if someone know any workaround.
Here an example that you can try to compile.
Program Check
implicit none
!> Type definitions
Type :: Atm_Type
End Type Atm_Type
Type, extends (Atm_type) :: Atm_Std_Type
End Type Atm_Std_Type
Type, extends (Atm_std_type) :: Atm_Ref_Type
End Type Atm_Ref_Type
Type :: AtList_Type
integer :: Natoms
class(Atm_Type), dimension(:), allocatable :: Atom
end Type AtList_Type
!> Variables
type(AtList_Type) :: list
call sub(list)
Contains
Subroutine Sub(List)
!---- Argument ----!
type (AtList_Type), intent(in out) :: List
!---- Local Variables ----!
integer :: i
type (AtList_Type), allocatable :: local
if (List%natoms <= 0 ) return
allocate(local%atom(List%natoms))
do i=1, List%natoms
local%atom(i)=list%atom(i)
end do
End Subroutine Sub
End Program Check
Here the workaround is very simple and appeared in one of the recent questions/answers. Just copy the whole array
local%atom = list%atom
However, it is not always possible to do that when you really need to access individual elements. If your real use case is like that, show the real use case.
If the number of possible types inside is limited, you can also use the select type type guard, but often that is not possible either.
I have this very small example of Fortran code which I would like to understand please.
subroutine test_iso_c
use ISO_C_BINDING
implicit real(c_double) (a-h,o-z)
real :: var, expression
interface
real(c_double) function test (y) bind( c )
use ISO_C_BINDING
real(c_double), value :: y
end
end interface
! call
var = test(expression) ! - expression is a real declared variable which is calculated using simple arithmetic operation.
end
Can you explain to me thee following (I assume c_double means double precision in a C code scope?)
1 - What does implicit real(c_double) (a-h,o-z)?
2 - what does value and bind(c) do in the function interface
3 - I saw this of code as part of a larger routine, can you say what this test function provide/do?
1 - What does implicit real(c_double) (a-h,o-z)?
The implied type of variables is an old Fortran feature where all variables starting with all characters except i, j, k, l,m, and n are considered to be of type REAL, so there is no need to declare them separately.
This property is considered harmful and therefore it is recommended to cancel it by specifying IMPLICIT NONE at the very beginning of the program.
This instruction specifies that all variables beginning with the characters a-h or o-z are of type REAL(c_double), which corresponds to the C double type.
The best solution is to use the IMPLICIT NONE directive and then declare all variables like this
REAL(c_double) :: x
2 - what does value and bind(c) do in the function interface
The bind(c) means that the function is C-function, so a compiler must formalize its call in the C language. This includes both the order in which arguments are placed on the stack and the formatting of the function name (for example, adding an underscore to the beginning).
The VALUE attribute means that the parameter is passed to the function by value (usually in Fortran, parameters are passed by reference)
I'm using ieee_arithmetic with Fortran on a Linux machine that runs gfortran version 5.4.0.
I'm getting an error of division by zero when trying to initialize values for Inf and NaN.
There doesn't seem to be an issue with ieee_arithmetic because elsewhere in the file I can successfully call ieee_is_finite() with no issues.
I thought that ieee_arithmetic allowed division by zero to be used for these specific cases, but I must be missing something. Below is a sample of code:
module rcrlib_gnu
use, intrinsic :: ieee_arithmetic ! requires gfortran version 5.0 or higher
implicit none
integer, parameter :: SP=kind(1.0), DP=selected_real_kind(9,99)
integer, parameter :: stderr=0
public SP, DP, is_finite, stderr, initialize
contains
subroutine initialize(infty,nan)
real(kind=DP), intent(out) :: infty, nan
infty = 1.0_dp/0.0_dp ! huge(1.0_dp)
nan = 0.0_dp/0.0_dp
end subroutine initialize
elemental function is_finite(x)
real(kind=DP), intent(in) :: x
logical :: is_finite
is_finite = ieee_is_finite(x) ! This call requires "ieee_arithmetic"
end function is_finite
end module rcrlib_gnu
It seems I'm missing something basic, so I would appreciate any help.
To reproduce the error, save the above code snippet as rcrlib_gnu_example.f90 and then execute the following line:
gfortran -o rcr rcrlib_gnu_example.f90
The resulting error output is
rcrlib_gnu_example.f90:12:18:
infty = 1.0_dp/0.0_dp ! huge(1.0_dp)
1
Error: Division by zero at (1)
rcrlib_gnu_example.f90:13:16:
nan = 0.0_dp/0.0_dp
1
Error: Division by zero at (1)
Thanks to Pascal Cuoq, I solved the problem.
The version of the initialize subroutine that compiles is below:
subroutine initialize(infty,nan)
real(kind=DP), intent(out) :: infty, nan
infty = huge(1.0_dp)+100
nan = infty-infty
end subroutine initialize
So basically set infinity to be the largest floating point number plus 100, then set NaN to be the difference between infinity and itself.
Thanks, all, for your quick responses and patience with my lack of FORTRAN experience.
When I try to compile my code using gfortran 4.4.7 I get the following error message:
Error: Type mismatch in argument 'intkind8' at (1); passed INTEGER(4)
to INTEGER(8).
With ifort it does compile, unless I demand the F2003 standard, in which case a similar error is given.
My code:
program kindDummy
implicit none
call takeIntKind4And8(0,0)
contains
subroutine takeIntKind4And8(intKind4, intKind8)
implicit none
integer(kind=4), intent(in) :: intKind4
integer(kind=8), intent(in) :: intKind8
print *, 'Integer(kind4): ', intKind4
print *, 'Integer(kind8): ', intKind8
end subroutine takeIntKind4And8
end program kindDummy
I was wondering if there's an elegant way to make the compiler "turn" the first 0 into a kind=4 integer, and the second one into a kind=8?
In
call takeIntKind4And8(0,0)
both zeros have the default kind. The kind numbers are not portable, but your default one is probably 4.
To produce 0 of kind 8 use 0_8:
call takeIntKind4And8(0_4,0_8)
I recommend to stay away from using 4 and 8 directly and use integer constants like 0_ip where ip is an integer constant with the right value. See Fortran: integer*4 vs integer(4) vs integer(kind=4) for more.
I took the following function ran0 from the text Numerical Recipes. I wrote my own program random2 to call ran0.
Why does this code cause a segmentation fault? Thanks for your time.
FUNCTION ran0(idum)
INTEGER idum,IA,IM,IQ,IR,MASK
REAL ran0,AM
PARAMETER (IA=16807,IM=2147483647,AM=1./IM,IQ=127773,IR=2836,MASK=123459876)
INTEGER k
idum=ieor(idum,MASK)
k=idum/IQ
idum=IA*(idum-k*IQ)-IR*k
if (idum.lt.0) idum=idum+IM
ran0=AM*idum
idum=ieor(idum,MASK)
return
END FUNCTION
PROGRAM random2
IMPLICIT NONE
REAL :: ran0
PRINT *, ran0(6)
END PROGRAM
You pass the constant 6.0 to your function as the IDUM dummy argument. You then (attempt to) modify this argument with lines such as idum = ieor(...) etc. You are effectively trying to modify a constant.
The value of 6.0 has been fixed for some time now - long enough that most programmers expect to find it somewhere between 5.0 and 7.0. Please don't try and change it.
Extending the answer of IanH, if you partially rewrite this in more modern Fortran:
module my_subs
contains
FUNCTION ran0(idum)
INTEGER, intent(inout) :: idum
INTEGER IA,IM,IQ,IR,MASK
REAL ran0,AM
PARAMETER (IA=16807,IM=2147483647,AM=1./IM,IQ=127773,IR=2836,MASK=123459876)
INTEGER k
idum=ieor(idum,MASK)
k=idum/IQ
idum=IA*(idum-k*IQ)-IR*k
if (idum.lt.0) idum=idum+IM
ran0=AM*idum
idum=ieor(idum,MASK)
return
END FUNCTION
end module my_subs
PROGRAM random2
use my_subs
IMPLICIT NONE
!REAL :: ran0
PRINT *, ran0(6)
END PROGRAM
Identifying the argument as being both input and output with the intent(inout) attribute and placing the subroutine in a module and using that module to allow the compiler to check the consistency of the arguments, the compiler is likely to find this problem. For example, gfortran outputs:
PRINT *, ran0(6)
1
Error: Non-variable expression in variable definition context (actual argument to INTENT = OUT/INOUT) at (1)