Type of a hardcoded argument - fortran

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.

Related

How to understand this negative index array variable declaration? [duplicate]

I need in a program to pass some allocatable arrays to subroutines, and i need to know if the way I do it are in the standard or not.
If you know where I can search for the standard of fortran, Tell me please.
Here is a little code that will better explain than words
program test
use modt99
implicit none
real(pr), dimension(:), allocatable :: vx
allocate(vx(-1:6))
vx=(/666,214,558,332,-521,-999,120,55/)
call test3(vx,vx,vx)
deallocate(vx)
end program test
with the module modt99
module modt99
contains
subroutine test3(v1,v2,v3)
real(pr), dimension(:), intent(in) :: v1
real(pr), dimension(0:), intent(in) :: v2
real(pr), dimension(:), allocatable, intent(in) :: v3
print*,'================================'
print*,v1(1:3)
print*,'================================'
print*,v2(1:3)
print*,'================================'
print*,v3(1:3)
print*,'================================'
end subroutine test3
end module modt99
on screen, I get
================================
666.000000000000 214.000000000000 558.000000000000
================================
214.000000000000 558.000000000000 332.000000000000
================================
558.000000000000 332.000000000000 -521.000000000000
================================
So are the three ways of dummy arguments in subroutine test3 legal (in what version of fortran, 90, 95, 2003?) and are their behavior normal?
The first version passes the array slice to the subroutine. Note that boundary information are not passed along in this way, arrays are assumed to start at 1 and go to size(array).
The second way is just like the first one, but you manually set the lower boundary to 0, that's why printing v3(1:3) gives you the values with an offset of 1.
The third way passes all array information to the subroutine (including boundaries), hence the "correct" indexing. Passing allocatable arrays was introduced with Fortran 2003.
Apart from the fact that you have an aliasing issue (passing the same variable to three different dummy arguments), all three versions are legal.
You can find all documents of the standards here.
Especially, take a look at the Fortran 2003 Standard, Ch. 5.1.2.5 DIMENSION attribute to see the differences between assumed shape and deferred shape arrays in dummy arguments.

PGI compilation error in Fortran: "forward reference to function"

I am a little puzzled with the PGI Fortran compiler.
When I try to compiler the following simple module stored in the file named test.f90, with pgfortran 19.10 I get errors that I do not understand. While compiling with gfortran or ifort run well.
The file test.f90:
MODULE CT
IMPLICIT NONE
integer, parameter :: si = SELECTED_INT_KIND(4)
integer(kind=si), public, parameter :: strlen = 256
type, public :: CMT
integer (kind=si) :: nbTot
character(len=strlen), dimension(:), allocatable :: condi
CONTAINS
procedure :: find_line_condi
endtype CMT
CONTAINS
PURE function find_line_condi( table, cara ) result(k)
IMPLICIT NONE
class(CMT), intent(in) :: table
character(len=*), intent(in) :: cara
integer (kind=si) :: k
integer (kind=si) :: j
k=-1
do j=1,table%nbTot
if (trim(table%condi(j)) .eq. cara) then
k=j
RETURN
else if ( j == table%nbTot ) then
k=-1
RETURN
endif
enddo
end function find_line_condi
END MODULE CT
The compilation with pgfortran -c test.f90 returns me the following error message:
/opt/pgi/linux86-64-llvm/19.10/share/llvm/bin/llc: error: /opt/pgi/linux86-64-llvm/19.10/share/llvm/bin/llc: /tmp/pgfortranr2qeZBujkwvA.ll:23:77: error: invalid forward reference to function 'ct_find_line_condi_' with wrong type: expected 'i32 (i64*, i64*, i64*, i64)*' but was 'i16 (i64*, i64*, i64*, i64)*'
#ct$cmt$td$vft = global [1 x i8*] [i8* bitcast(i16 (i64*, i64*, i64*, i64)* #ct_find_line_condi_ to i8*)]
Does anyone has some ideas where this problem comes from?
This is a bug in the compiler. Consider the module
MODULE CT
IMPLICIT NONE
type CMT
CONTAINS
procedure, nopass :: find_line_condi
endtype CMT
CONTAINS
function find_line_condi()
integer(SELECTED_INT_KIND(4)) find_line_condi
find_line_condi=0
end function find_line_condi
END MODULE CT
which is quite a bit simpler than that of that question. Compiled with pgfortran 19.10 there is a similar gibberish output. It's left as an exercise to the reader/PGI support desk whether this simpler code is valid Fortran which should be accepted but I would consider the poor diagnostic to be something PGI would prefer to avoid.
However, this appears to be a weakness in the LLVM frontend of PGI: consider compiling with pgfortran -c -Mnollvm .... There are also ways to rewrite the code to attempt to work around this bug, such as changing the kind of the function result.
More widely, PGI introduced in the 2019 releases the LLVM code generator. This seems to be going through a number of teething difficulties. If you have code unexpectedly failing with PGI 2019 (which may have worked with 2018), then compiling with -Mnollvm to use the non-LLVM generator is worth a try.

How can I resolve the problem about intrinsic assignment between two polymorphic components into a type variables using Gfortran?

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.

Calling function with configurable real precision

The goal:
Have a function work with configurable working precision.
When I try this:
program vierkantsvergelijking
implicit none
integer, parameter :: dp = kind(0.d0)
integer, parameter :: sp = kind(0.0)
print *, algoritme1(-5771.,2.,dp)
contains
function algoritme1(b,c,wp) result( solution)
integer :: wp ! working precision
real(kind=wp) :: b,c,D
real(kind=wp), dimension(2) :: solution
D = sqrt((b/2)**2 - c)
solution(1) = -b/2 + D
solution(2) = -b/2 - D
end function algoritme1
end program
I get:
Error: Type mismatch in argument 'b' at (1); passed REAL(4) to UNKNOWN
Why is this not working and how can I achieve my goal?
Yes, or rather no, that's not going to work, not no how. The Intel Fortran compiler complains, about this line:
real(kind=wp) :: b,c,D
that
A kind type parameter must be a compile-time constant. [WP]
It makes the same complaint about real(kind=wp), dimension(2) :: solution too. This is a deep-rooted feature of Fortran.
To do what you want you will have to define a generic interface, along these lines
interface algoritme1
procedure :: algoritme1_sp, algoritme1_dp
end interface
and write the code for both those procedures. The compiler can then determine which one is called by the function signature; presumably one would have sp arguments, the other dp arguments.
You might think that this all means that Fortran doesn't do generic procedures, I'll leave that question to the sophists and language nit-pickers. It would be worth your while to search around for generic programming in Fortran; even here on SO there are tricks and tips on how to better avoid writing multiple implementations of what the programmer believes (at odds with the compiler) to be the 'same' code.

Why does this Fortran random number generator cause a segmentation fault?

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)