Error with parentheses when assigning to complex variable - fortran

I have the following set of commands in my Fortran code:
COMPLEX*16, DIMENSION(4,1) :: INSTATE_BASISSTATES
INSTATE_BASISSTATES(:,:) = (0.0D0,0.0D0)
INSTATE_BASISSTATES(1,1) = ((1.0D0/SQRT(2)),0.0D0)
INSTATE_BASISSTATES(3,1) = ((1.0D0/SQRT(2)),0.0D0)
When I run/compile the program using gfortran on cygwin, I get the error
INSTATE_BASISSTATES(1,1) = (1.0D0/DREAL(SQRT(2.0D0)),0.0D0)
1
Error: Expected a right parenthesis in expression at (1)
INSTATE_BASISSTATES(3,1) = (1.0D0/DREAL(SQRT(2.0D0)),0.0D0)
1
Error: Expected a right parenthesis in expression at (1)
What could be the issue? Aren't my brackets correct?

On the right hand side of the assignment statement you are trying to use a complex literal constant. However,
(1.0D0/DREAL(SQRT(2.0D0)),0.0D0)
isn't a valid form for such a constant.
For a complex literal, the real and imaginary components must be either named constants or literal constants. 1.0D0/DREAL(SQRT(2.0D0)) is neither of those things. For the line where you had no complaint, both components of (0.0D0,0.0D0) are literal constants.
As in this other answer you could make a named constant with the value wanted and use that. Alternatively, as you are just doing a boring assignment (which doesn't have various restrictions which apply to initialization, etc.,) you can use the cmplx intrinsic to return a complex value
INSTATE_BASISSTATES(1,1) = CMPLX(1.0D0/DREAL(SQRT(2.0D0)),0.0D0)
Here the real and imaginary components don't need to be constants. You could even note that
INSTATE_BASISSTATES(1,1) = CMPLX(1.0D0/DREAL(SQRT(2.0D0)))
works just as well: if the imaginary component value isn't provided, the returned complex has imaginary component zero.
There is a slight complication, though. cmplx by default returns a complex number with kind of the default real. To return something matching complex*16 (which isn't standard Fortran, but let's assume it corresponds to double precision) you'll need CMPLX(..., [...], KIND=KIND(0d0)) (or KIND=KIND(INSTATE_BASISSTATES))
As a side note, as Vladimir F comments dreal isn't standard Fortran. You could use dble, or real with a suitable kind number. But we can also see that sqrt(2d0) already returns a double precision real, so even those are redundant: 1/sqrt(2d0) has the same (mathematical) result as the original more cumbersome expression. As do 2d0**(-0.5) and sqrt(2d0)/2.
You could even replace the right hand side with
SQRT((5d-1,0))
as we see that sqrt also accepts a complex argument (in this case a complex literal constant). This form also avoids the awkwardness of the kind= specifier: its value has kind as well as type of the argument.

this is indeed "by design", one could define the constant of interest first and then use it in the initialization. For example:
COMPLEX*16, DIMENSION(4,1) :: INSTATE_BASISSTATES
REAL*8, PARAMETER :: my_const = 1D0 / SQRT(2D0)
INSTATE_BASISSTATES(:,:) = (0.0D0,0.0D0)
INSTATE_BASISSTATES(1,1) = (my_const,0.0D0)
INSTATE_BASISSTATES(3,1) = (my_const,0.0D0)
However, the statement REAL*8, PARAMETER :: my_const = 1D0 / SQRT(2D0) seems to require at least Fortran2003 standard, otherwise, following error is produced Elemental function as initialization expression with non-integer/non-character arguments. One can specify the standard with gfortran with -std=f2003 although it should be probably active by default.

#J123 still hasn't answered the pressing question. Are you writing your code in fixed-form format with .f extension or free-form .f90? Also, what version of gfortran are you using? I've posted a complete fix below. You can foliate your arrays by direct assignment using named parameter constants, or as the return value of the intrinsic transformational function cmplx. Please note the liberal use of the kind parameter wp to control the floating-point precision.
program main
use iso_fortran_env, only: &
wp => REAL64, & ! Or REAL128 if your architecture supports it
compiler_version, &
compiler_options
! Explicit typing only
implicit none
! Variable declarations
complex(wp) :: instate_basisstates(4,1)
real (wp), parameter :: ZERO = 0 ! Assigning integers is safe
real (wp), parameter :: SQRT2 = sqrt(2.0_wp)
real (wp), parameter :: ONE_OVER_SQRT2 = 1.0_wp/SQRT2
! Executable statements
instate_basisstates(:,:) = ZERO
instate_basisstates(1,1) = (ONE_OVER_SQRT2, ZERO)
instate_basisstates(3,1) = cmplx(1.0_wp/sqrt(2.0_wp), 0.0_wp, kind=wp)
print '(/4a/)', &
'This file was compiled using ', compiler_version(), &
' using the options ', compiler_options()
end program main
This yields:
This file was compiled using GCC version 6.1.1 20160802 using the options -mtune=generic -march=x86-64 -O3 -Wall -std=f2008ts

Related

gfortran compiler error calling recursive log_gamma function

I uploaded a 2F1 hypergeometric function but it turns out that it does not compile on my computer. It is from this article. I use
GNU Fortran (Built by Jeroen for the R-project) 8.3.0
shiped with RTools 4.0. Can you figure out why it does not compile and how this could be solved? In the code below, I just kept the one line that generates the error. The error is given next.
MODULE HYP_2F1_MODULE
!--------------------------------------------------------------------
IMPLICIT NONE
INTEGER, PARAMETER :: PR=KIND(1.0D0)
REAL(PR) :: ONE=1.0D0
CONTAINS
!
END MODULE HYP_2F1_MODULE
!
!----------------------------------------------------------------------
RECURSIVE FUNCTION LOG_GAMMA(Z) RESULT(RES)
USE HYP_2F1_MODULE
IMPLICIT NONE
COMPLEX(PR),INTENT(IN) :: Z
COMPLEX(PR) :: RES
!
RES = LOG_GAMMA( ONE -z);
!
END FUNCTION LOG_GAMMA
Here is the error message
testZ.f90:18:22:
RES = LOG_GAMMA( ONE - Z);
1
Error: 'x' argument of 'log_gamma' intrinsic at (1) must be REAL
There is a Fortran 2008+ intrinsic of the same name
16.9.119 LOG_GAMMA (X)
1 Description. Logarithm of the absolute value of the gamma function.
2 Class. Elemental function.
3 Argument. X
shall be of type real. Its value shall not be a negative integer or
zero.
There is some sort of clash I do not completely understand here. The obvious workaround is to rename your function. What I can say is that without the result clause (which you need because of the recursive attribute) the intrinsic would be shadowed. It might be a compiler bug.
Also consider, whether the intrinsic of the same name couldn't also do what you need from your function.
In addition to #VladimirF's suggestions, you can add the compiler flag -std=f95 to enforce compliance with the Fortran 95 standard. Provided you haven't added -fall-intrinsics this will disable all intrinsics from standards after Fortran 95, and should make the legacy code work.

Have a function in fortran return a reference that can be placed on the left-hand-side of an assignment

As stated in the title, I want to directly modify data that I access through a pointer retrieved from a function. Having a reference returned by a function appearing on the l.h.s. of an assignment(=) is no issue in C++ but the following minimal example in fortran errors out:
module test_mod
implicit none
integer, target :: a=1, b=2, c=3 ! some member variables
contains
function get(i)
integer, pointer :: get
integer, intent(in) :: i
select case (i)
case (1)
get => a
case (2)
get => b
case (3)
get => c
end select
end function get
end module test_mod
program test
use test_mod
implicit none
integer, pointer :: i_p
!> prints out 1 2 3
print*, get(1), get(2), get(3)
!> this is what I want but I get the error
!> Error: 'get' at (1) is not a variable
get(2) = 5
!> this works but is not what I want
i_p => get(2)
i_p = 5
end program test
Is there any way to accomplish this behaviour; maybe I'm missing some attributes? I would like to bypass writing any setter routines such as
set(i,value)
since it should mimic the appearance of an array.
In my application, the member variables a,b,c are actually arrays of different size
a = [a1, a2, a3]
b = [b1, b2]
c = [c1]
and I want the getter get(i,j) to mimic a matrix of pointers
j = 1 2 3
i = 1: [[a1, a2, a3],
i = 2: [b1, b2, XX],
i = 3: [c1, XX, XX]]
wehre XX would be referencing to null().
Update:
I am using gfortran (version 5.2.0) and the deployment machines would have only versions starting from 4.6.x and upwards. Therefore, the suggested fortran 2008 standard features are unfortunately not available to me. Is it possible to mimic the behaviour described above without having a compiler supporting it out of the box?
Update 2:
So I ended up implementing a structure as follows
type Vec_t
integer, allocatable, dimension(:) :: vec
end type Vec_t
type(Vec_t), allocatable, dimension(:), target :: data
which I initialise like this (my triangular matrix application I mention at the end)
allocate(data(max))
do i=1,max
allocate(data(i)%vec(i))
end do
and I access & write to it through
print*, data(2)%vec(1)
data(2)%vec(1) = 5
which is not precisely what I was after but good enough for my application.
Let's look at what you want to do:
get(2)=5
and the error message
Error: 'get' at (1) is not a variable
That looks pretty comprehensive: you can't do what you want. Or, perhaps...
get(2) is indeed, under the rules of Fortran 2003, not a variable. In Fortran 2003 a variable is given by the rules R601 and R603, which is a list of designators.
The left-hand side of an assignment must be a variable.
But look at Fortran 2008 and its definition of a variable. Now a variable is either one of those same designators (or ones related to coarrays or complex parts), but it could also (C602 to R602) be a function reference which
shall have a data pointer result.
This is summarized in the introduction of Fortran 2008, detailing the extensions over Fortran 2003, as
A pointer function reference can denote a variable in any variable definition context.
get(2) is a reference to a function that has a data pointer result. get(2) then may appear on the left-hand side of an assignment statement under the rules of Fortran 2008.
Alas, this interpretation of Fortran is not widely supported by current compilers: at the time of answering just the Cray compiler.
This means that this answer is really saying that you have two options: switch compiler or wait until this feature is more widespread. As both of these are likely impractical, you probably want another answer which gives something slightly more portable as a workaround.
I prefer my link to that given by innoSPG, as although this latter is based on the former, the description of the appropriate field "Pointer functions - pointer function ref is a variable" is slightly more clear. This is, though, a more accessible document and a viable alternative.

How does automatic typecasting (type conversion) work in Fortran?

I am using gfortran compiler. Also tell me if gfortran uses something other than the Fortran standard while performing automatic typecasting (type conversion).
Assignment is defined by Fortran 2008 Section 7.2. Of note is Cl. 7.2.1.3 paragraph 8:
For an intrinsic assignment statement where the variable is of numeric type, the expr may have a different numeric
type or kind type parameter, in which case the value of expr is converted to the type and kind type parameter
of the variable according to the rules of Table 7.9.
Table 7.9: Numeric conversion and the assignment statement
Type of variable Value Assigned
integer INT(expr , KIND = KIND (variable))
real REAL(expr , KIND = KIND (variable))
complex CMPLX(expr , KIND = KIND (variable))
This means that any expression (expr) will be implicitly converted to the type and kind of the variable it is being assigned to. For character types, derived types and anything else, please see the standard.
Also note that Fortran only performs conversions like this during assignment and initialization but not contexts like procedure calls. For example, consider this procedure:
subroutine sub1(a)
implicit none
integer :: a
print *, a
end subroutine
This procedure has a dummy argument of type integer. You cannot, for example, do this:
call sub1(1.d0)
because this results in a mismatch of type between the actual and dummy arguments.
You can, however, do this:
integer :: a
a = 1.d0 !implicitly interpreted as: a = INT(1.d0, kind=kind(a))
call sub1(a)
because the implicit conversion is defined for the assignment.
The only documented extension to the standard for implicit type conversion in gfortran (5.1.0) is between logical and integer types during assignment.
See: https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gfortran/Implicitly-convert-LOGICAL-and-INTEGER-values.html#Implicitly-convert-LOGICAL-and-INTEGER-values
Logical .true. is converted to integer 1
Logical .false. is converted to integer 0
Integer 0 is converted to .false.
Any other integer is converted to .true.
Do note that if you can do without legacy extensions then don't use them. Using them means your program is not standard Fortran and thus any compiler is free to reject it for being incorrect. This extensions is meant to allow legacy code to compile with modern compilers and not for use in new code.

fortran 64 bit hex BOZ

in C++ this is accepted:
uint64_t mask = 0x7FC0000FF80001FFLL;
but in fortran
integer(kind=8), parameter :: mask = Z'7FC0000FF80001FF'
does not work with gfortan.
I think both of them are 64bit values? or not?
gfortran complains:
arithmetic overflow from converting INTEGER(16) to INTEGER(8)
EDIT:
So, sorry for the confusion, here is some more extended problem description.
I will do some bit shifting in Fortran and have some sample code in c++.
There in the sample c++ code the masks are defines like:
typedef uint64_t mask;
static const mask dilate_2 = (mask)0x7FC0000FF80001FFLL ;
static const mask dilate_1 = (mask)0x01C0E070381C0E07LL ;
static const mask dilate_0 = (mask)0x9249249249249249LL ;
From my poor c++ understanding, I think that the hex values are 64bit
integer values (they have LL in the ending).
Now in Fortran my problem first was, that the definition with
integer(kind=8), parameter ...
did not work, as Vladimir said, because
integer(kind=8), ...
might be no 64bit integer.
Than I tested Alexanders solution, which works for the first and the
second (dilate_2, dilate_1) constant.
Also Vladimirs solution works for these two.
Now for dilate_0 none of these solutions work. I would suppose that Vladimirs solution will cast 0x9249249249249249LL (what is actually
a greater integer than allowed in INT64) into a INT64
if I do:
integer(INT64), parameter :: dilate_0 = int(Z'9249249249249249', &
kind=kind(dilate_0)
But this also don't work and gfortran give me an error:
Error: Arithmetic overflow converting INTEGER(16) to INTEGER(8) at (1).
So my actual question is how to implement this constant in Fortran?
As Vladimir posted in his comment integer(kind=8) is not portable (and not of kind 16 as the compiler complains).
As a remedy I suggest to use the intrinsic module ISO_Fortran_env (Fortran 2003) which has many predefined constants for the compiler used. Using INT64 from this module solves your problem and results in portable code:
program test
use,intrinsic :: ISO_Fortran_env, only: INT64
integer(INT64), parameter :: mask = Z'7FC0000FF80001FF'
print *,mask
end program
Z'9249249249249249' is not representable as a an INT64 (which is equivalent to an INTEGER(kind=8) in gfortran) because
BOZ constants are signed numbers (the same as every other integer constant in Fortran)
This number is larger than 2**63-1, the largest representable number for an INT64
Gfortran therefore selects the smallest integer type which fits, which is INTEGER(KIND=16).
We then have parameter staement where an INTEGER(KIND=8) parameter should be assigned a value outside its range. This is what the compiler complains about. It would complain the same way about
INTEGER(KIND=4), PARAMETER :: N = 37094947285
If you want to get around this, you can use the -fno-range-check option to gfortran. Information about -fno-range-check is already included in the gfortran error message (the part you didn't show).
I would do this to stay standard conforming
integer(whatever), parameter :: mask = int(Z'7FC0000FF80001FF', &
kind=kind(mask))
where whatever is some kind constant of the required value. It could be int64.
The above will not work if the constant corresponds to a negative number. One then has to make a trick like:
integer(int32), parameter :: mask = transfer(int(Z'A0000000',int64),1_int32)
or
integer(int32), parameter :: mask = transfer(Z'A0000000',1_int32)
but I am not sure whether the last one is strictly standard conforming.

Convert logical type to double in Fortran

I'm looking for a bulletproof way of converting logical type variables to real type that will work in both ifort and gfortran. The following works in ifort, but not in gfortran:
logical :: a
real :: b
a = .true.
b = dble(a)
The error thrown in gfortran is
b = dble(a)
1
Error: 'a' argument of 'dble' intrinsic at (1) must be a numeric type
Obviously, .true. should map to 1.d0, and .false. to 0.d0. What's the best way of doing this?
In addition to writing a function to handle this, you could also directly use the intrinsic merge function: b = merge(1.d0, 0.d0, a). Or you could write a defined assignment subroutine that does this, so that you can just type b = a.
I am not sure if there is an intrinsic tool that does this. I do not know why ifort accepts this, and my guess would be that it is a compiler specific functionality.
Edit: As pointed out in https://stackoverflow.com/a/15057846/1624033 below, there is the intrinsic merge function which is exactly what is needed here.
an option to to this, specifically since you want this to be bullet proof, is to create your own function.
I have not tested this, but the following might work:
elemental pure double precision function logic2dbl(a)
logical, intent(in) :: a
if (a) then
logic2dbl = 1.d0
else
logic2dbl = 0.d0
end if
end function logic2dbl
Edit: I added elemental to the function declaration based on advice below. I also added pure to this function as it adds the extra ability to use this in parallel situations and it is good documentation. This however is just my opinion and it is not necessary.
In gfortran, I am using the TRANSFER intrinsic for that type of job.
Assuming a integer variable my_int then:
my_int = transfer(.false.,my_int)
the result of my_int is 0 as expected.
Just a note, TRANSFER(.true.,1) correctly returns the value of 1 with Gfortran and (incorrectly?) values of -1 with the current versions of Intel and Portland compilers. Interestingly, TRANSFER(-1,logical) returns TRUE with the latter two compilers while throws a syntax error with Gfortran.