Real and imaginary parts of complex number

What’s the most modern way to extract the real/imaginary parts of a complex number in Fortran? I’m aware of real and aimag, and %re/%im - what’s the most preferred method?

2 Likes

I recommend %re/%im since passing them as actual arguments will be more likely to do what you want; passing real(z) will pass the address of a copy of the data.

4 Likes

Indeed, with compilers conformant with Fortran 2008 and later revisions, %RE and %IM is the way to go in my “book” too. Note, however, it is processor-dependent whether one gets direct reference to the data, or the address of a copy of it when it comes to the more common scenarios with complex numbers and which is arrays of them.

module m
   use, intrinsic :: iso_c_binding, only : c_loc, c_size_t
   character(len=*), parameter :: fmtz = "(g0,1x,z0)"
   integer(c_size_t), parameter :: mold = 0
contains
   impure elemental function cmag( x, y ) result(r)
      real, intent(in), target :: x, y
      real :: r
      print fmtz, "mag: address of x (hex): ", transfer( c_loc(x), mold=mold )
      r = sqrt(x**2 + y**2)
   end function
end
   use m
   complex, target :: z(3)
   real :: q( size(z) )
   z%re = [ 1.0, 2.0, 3.0 ]
   z%im = 0.0
   print fmtz, "main: address of z(1)%re (hex): ", transfer( c_loc(z(1)%re), mold=mold )
   print fmtz, "main: address of z(2)%re (hex): ", transfer( c_loc(z(2)%re), mold=mold )
   print fmtz, "main: address of z(3)%re (hex): ", transfer( c_loc(z(3)%re), mold=mold )
   q = cmag( z%re, z%im )
   print *, q
end

C:\Temp>ifort /standard-semantics i.f90 -o i.exe
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.2.0 Build 20210228_000000
Copyright (C) 1985-2021 Intel Corporation. All rights reserved.

Microsoft (R) Incremental Linker Version 14.28.29337.0
Copyright (C) Microsoft Corporation. All rights reserved.

-out:i.exe
-subsystem:console
i.obj

C:\Temp>i.exe
main: address of z(1)%re (hex): 72478FFAE8
main: address of z(2)%re (hex): 72478FFAEC
main: address of z(3)%re (hex): 72478FFAF0
mag: address of x (hex): 72478FFAF4
mag: address of x (hex): 72478FFAF4
mag: address of x (hex): 72478FFAF4
1.000000 2.000000 3.000000

C:\Temp>gfortran i.f90 -o gcc-i.exe

C:\Temp>gcc-i.exe
main: address of z(1)%re (hex): 87FDB0
main: address of z(2)%re (hex): 87FDB8
main: address of z(3)%re (hex): 87FDC0
mag: address of x (hex): 87FDB0
mag: address of x (hex): 87FDB8
mag: address of x (hex): 87FDC0
1.00000000 2.00000000 3.00000000

C:\Temp>

3 Likes

Thanks to you both. I noticed that you can’t do the following, though: (a+b)%re which is unfortunate. At least, gfortran calls that an unclassifiable statement.

1 Like

Fortran allows the somewhat more verbose ASSOCIATE block with type-inference:

      associate ( t => a + b )
         ! consume t%re as read-only here
      end associate
3 Likes

If you want to convert the real or imaginary part of the complex data entity to a different KIND, I would use REAL or AIMAG. Otherwise, %re and %im are the new, shiny approach.