Generic and specific functions to get real and imaginary parts of complex variables - fortran

In Fortran, I always work with double precision, so I have been using specific functions like dble and dimag to get real and imaginary parts of complex variables. However, for other functions like sin, I no longer use dsin because the former returns a value of proper kind (i.e., sin is a generic function). The same seems to hold for complex variables. So my question is:
1) What are the most recommended generic functions for getting real and imaginary parts?
-- It seems that real(z), aimag(z), and conjg(z) return a proper kind always (via experiments with gfortran), i.e., if z is double precision, those functions return double precision. Is this guaranteed? Also, is the behavior dependent on the standard used by the compiler? (i.e., Fortran 77 vs 90 or later, particularly for real(z)?)
2) If I (nevertheless) want to use specific functions that receives only double precision arguments and always return double precision values, what are the specific functions?
-- I have been using dble(z) and dreal(z), dimag(z), dconjg(z) up to now, but some web pages say that they are vendor extensions (though commonly supported by many compilers).
I have read various pages but the information is rather confusing (i.e., it is not very clear what is the "standard" way), so I would appreciate any advice on the choice of such functions.

As background, what do we mean by kinds of real and complex variables? Of course, you know what is meant by the kind of a real object.
A complex object consists of a real and an imaginary part. If a complex object has a given kind then each component is a real of kind corresponding to the kind of the complex object.
That's a long way of saying, if
complex(kind=k) z
then KIND(z%re) and KIND(z%im) both evaluate to k (using the complex part designators introduced by Fortran 2008 for clarity).
Now, the real intrinsic generic takes a complex expression and returns its real component. It does so subject to the following F2008 rule (13.7.138), where A is the argument:
If A is of type complex and KIND is not present, the kind type parameter is the kind type parameter of A.
So, yes: in current Fortran real without a requested kind will always give you a real of kind that of the complex's real component. Whether that's double precision or otherwise.
Similarly, aimag returns a real (corresponding to the imaginary part) of kind that of the complex number. Unlike real, aimag doesn't accept a kind= argument controlling the result kind.
Things are different for Fortran 77: there was no similar concept of kind, and just one complex.
dble is a standard intrinsic. Although this always returns a double precision it is still generic and will accept any numeric. dble(a) is the same as real(a,kind(0d0)), whatever the type of a. There is no (standard) specific.
dreal, dimag and dconjg are not standard intrinsics.
I suppose one could create specific wrappers around real if one cared greatly.

Related

Evaluate a function with different KIND

Consider a function that adds two number (e.g. integer, Real). I have to write the same function with the same code many times but with different precision and then create an interface.
Can somebody give me an example how to do the same with Fortran select type.
No... But it is possible in a module
All the math for scalars and doubles already does exactly what you want, so the procedures would be mostly for functions or subroutines that are doing significantly more bespoke work than a simple add or multiply.
Do you have any starting example?
Is this for a course you are taking?
If it is for a course then search for "module procedure interface".

In fortran: Is CONJG(Z) equivialent to DCONJG(Z) when compiling with -fdefault-real-8?

If in existing code there are calls to DCONJG(Z) where Z is declared to be COMPLEX*16. Can the DCONJG call be replaced with CONJG when the -fdefault-real-8 flag is added?
If Z is defined as double complex does this still apply?
In the existing code double complex and complex*16 have both been used to increase precision (and should be equivalent). With the -fdefault-real-8 flag applied, do double complex map to complex*32?
Can the DCONJG call be replaced with CONJG when the -fdefault-real-8
flag is added?
Yes, the standard conjg will return a value of the same kind as its argument, irrespective of the compilation settings. Kind-specific variants of intrinsic functions, such as dconjg, are generally deprecated precisely because they are not kind-indifferent.
If Z is defined as double complex does this still apply?
Yes.
And is double complex equivalent to complex with the flag applied
(same for double precision and real)?
If you mean does that compilation flag also affect the size of the real and imaginary components of a complex value then yes, it does.
EDIT
I don't know what gfortran means by the non-standard (never was, isn't, and probably never will be) kind specification complex*32. But the compiler is reasonably well documented so have a scout yourself. Personally I'd stick to one of the standard ways of specifying a complex number's kind, in which case the standard assures you that the kind specified, e.g. complex(real64), means the kind of each component of the complex number.

Creating custom or using built in types

In some projects people create custom types for everything, and in others they just use ints and floats to represent temperatures, lengths and angles.
I can see advantages and draw backs to both, and I guess it depends on the type of project you are working on if is a good idea or not to create these kinds of types.
Here is what I'm thinking of:
class SomeClass
{
Physics::Temperature TemperatureOnMoon(Geometry::Distance distanceFromSun);
Geometry::Area Shadow(Geometry::Angle xAngle, Geometry::Angle yAngle, Geometry::Triangle triangle);
};
The Temperature type would have a Fahrenheit() and Celsius() method, the Area type would have a constructor that takes two Point types and so on.
This of gives great type safety and I think it increases readability, but it also creates a lot of dependencies. Suddenly everyone who uses SomeClass has to include all these other headers and so you have to do a lot more work when your creating unit tests. It also takes time to develop all the types.
The approach using built in types are much simpler to use and have fewer dependencies:
class SomeClass
{
double TemperatureOnMoon(double distanceFromSun);
double Shadow(double xAngle, double yAngle, double triangle);
};
My question is, to what degree do you create these kinds of types? Would you prefer them in larger projects? Are there ready made libraries for this kind of stuff?
I would avoid creating new types when it's unnecessary. Here are a few issues you will have to deal with:
It hides the information about precision - like in the case of a Distance, what can an distance be? is it an integer, is it a float is it a double?
You will have problems using standard libraries - for example in the case of can you use max(distance1, distance2)? how about sorting distances? you will have to create a compare function explicitly. It also depends on how you define your type. If it's a typedef of a primitive type, you may not need to create a new compare function or max function. But it will still be confusing. But if your Distance is now a class or a struct, then you will have to overload all the operators explicitly, + - = *.....
Since you don't know if it's a floating point type or an integer you don't know if you can safely use == to compare 2 distances. They can be floating points, and if manipulated differently they may end up with a different result than in theory due to precision issues.
The number of files to maintain is going to be bigger, the building process will be unnecessary longer.
I would create new types if they don't make sense as primitives at all, and you do want to overload all the operators or not allow some. I'm struggling to find a good example, but AN example can be "a binary number" so if you define a BinaryNumber as a class/struct instead of using it as an integer that would make sense since if you had a int binaryNumber1=1, binaryNumber2=1; and somewhere along the process you do binaryNumber1+binaryNumber2 you would expect the result to be 10 instead of 2, right? So you would define a BinaryNumber class/struct and overload the operator + - * / etc.

CABS(x) function for complex(8)

Is there an absolute value function for a complex value in double precision? When I try CABS() I get
V(1,j) = R(j,j) + (R(j,j)/cabs(R(j,j)))*complexnorm2(R(j:m,j))
"Error: Type of argument 'a' in call to 'cabs' at (1) should be
COMPLEX(4), not COMPLEX(8)"
I have read there's a function called CDABS() but I wasnt sure if that was the same thing?
There is no reason using anything else than ABS(). Generics for intrinsic procedures were already present in FORTRAN 77. You can use them for all intrinsic numeric types.
If you want to see the table of available specific functions of the generic ABS(), see https://gcc.gnu.org/onlinedocs/gfortran/ABS.html , but they are mostly useful only to be passed as actual arguments. You can see that CDABS() is a non-standard extension and I do not recommend to use it.
CABS is defined by the standard to take an argument of type default complex. In your implementation this looks like complex(kind=4). There is no standard function CDABS, although your implementation may perhaps offer one: read the appropriate documentation.
Further, there is no standard specific function for the generic function ABS which takes a double complex argument. Again, your implementation may offer one called something other than CDABS.
That said, the generic function ABS takes any integer, real, or complex argument. Use that.
COMPLEX*8 and complex(KIND=8) are not the same.
The first one, is 4 byte real and 4 byte imaginary.
The complex(KIND=8) or COMPLEX(KIND=C_DOUBLE) is actually a double precision real and double precision imaginary... So equivalent to COMPLEX*16.
As mentioned ABS() should be fine.

Fortran 90 kind parameter

I am having trouble understanding Fortran 90's kind parameter. As far as I can tell, it does not determine the precision (i.e., float or double) of a variable, nor does it determine the type of a variable.
So, what does it determine and what exactly is it for?
The KIND of a variable is an integer label which tells the compiler which of its supported kinds it should use.
Beware that although it is common for the KIND parameter to be the same as the number of bytes stored in a variable of that KIND, it is not required by the Fortran standard.
That is, on a lot of systems,
REAl(KIND=4) :: xs ! 4 byte ieee float
REAl(KIND=8) :: xd ! 8 byte ieee float
REAl(KIND=16) :: xq ! 16 byte ieee float
but there may be compilers for example with:
REAL(KIND=1) :: XS ! 4 BYTE FLOAT
REAL(KIND=2) :: XD ! 8 BYTE FLOAT
REAL(KIND=3) :: XQ ! 16 BYTE FLOAT
Similarly for integer and logical types.
(If I went digging, I could probably find examples. Search the usenet group comp.lang.fortran for kind to find examples. The most informed discussion of Fortran occurs there, with some highly experienced people contributing.)
So, if you can't count on a particular kind value giving you the same data representation on different platforms, what do you do? That's what the intrinsic functions SELECTED_REAL_KIND and SELECTED_INT_KIND are for. Basically, you tell the function what sort of numbers you need to be able to represent, and it will return the kind you need to use.
I usually use these kinds, as they usually give me 4 byte and 8 byte reals:
!--! specific precisions, usually same as real and double precision
integer, parameter :: r6 = selected_real_kind(6)
integer, parameter :: r15 = selected_real_kind(15)
So I might subsequently declare a variable as:
real(kind=r15) :: xd
Note that this may cause problems where you use mixed language programs, and you need to absolutely specify the number of bytes that variables occupy. If you need to make sure, there are enquiry intrinsics that will tell you about each kind, from which you can deduce the memory footprint of a variable, its precision, exponent range and so on. Or, you can revert to the non-standard but commonplace real*4, real*8 etc declaration style.
When you start with a new compiler, it's worth looking at the compiler specific kind values so you know what you're dealing with. Search the net for kindfinder.f90 for a handy program that will tell you about the kinds available for a compiler.
I suggest using the Fortran 2008 and later; INT8, INT16, INT32, INT64, REAL32, REAL64, REAL128. This is done by calling ISO_FORTRAN_ENV in Fortran 2003 and later. Kind parameters provides inconsistent way to ensure you always get the appropriate number of bit representation
Just expanding the other (very good) answers, specially Andrej Panjkov's answer:
The KIND of a variable is an integer label which tells the compiler
which of its supported kinds it should use.
Exactly. Even though, for all the numeric intrinsic types, the KIND parameter is used to specify the "model for the representation and behavior of numbers on a processor" (words from the Section 16.5 of the standard), that in practice means their bit model, that's not the only thing a KIND parameter may represent.
A KIND parameter for a type is any variation in its nature, model or behavior that is avaliable for the programmer to choose at compile time. For example, for the intrinsic character type, the kind parameter represents the character sets avaliable on the processor (ASCII, UCS-4,...).
You can even define your own model/behaviour variations on you defined Derived Types (from Fortran 2003 afterwards). You can create a Transform Matrix type and have a version with KIND=2 for 2D space (in which the underlying array would be 3x3) and KIND=3 for 3D space (with a 4x4 underlying array). Just remember that there is no automatic kind conversion for non-intrinsic types.
From the Portland Group Fortran Reference, the KIND parameter "specifies a precision for intrinsic data types." Thus, in the declaration
real(kind=4) :: float32
real(kind=8) :: float64
the variable float64 declared as an 8-byte real (the old Fortran DOUBLE PRECISION) and the variable float32 is declared as a 4-byte real (the old Fortran REAL).
This is nice because it allows you to fix the precision for your variables independent of the compiler and machine you are running on. If you are running a computation that requires more precision that the traditional IEEE-single-precision real (which, if you're taking a numerical analysis class, is very probable), but declare your variable as real :: myVar, you'll be fine if the compiler is set to default all real values to double-precision, but changing the compiler options or moving your code to a different machine with different default sizes for real and integer variables will lead to some possibly nasty surprises (e.g. your iterative matrix solver blows up).
Fortran also includes some functions that will help pick a KIND parameter to be what you need - SELECTED_INT_KIND and SELECTED_REAL_KIND - but if you are just learning I wouldn't worry about those at this point.
Since you mentioned that you're learning Fortran as part of a class, you should also see this question on Fortran resources and maybe look at the reference manuals from the compiler suite that you are using (e.g. Portland Group or Intel) - these are usually freely available.
One of the uses of kind could be to make sure that for different machine or OS, they truly use the same precision and the result should be the same. So the code is portable. E.g.,
integer, parameter :: r8 = selected_real_kind(15,9)
real(kind=r8) :: a
Now this variable a is always r8 type, which is a true "double precision" (so it occupies 64 bits of memory on the electronic computer), no matter what machine/OS the code is running on.
Also, therefore you can write things like,
a = 1.0_r8
and this _r8 make sure that 1.0 is converted to r8 type.
To summarize other answers: the kind parameter specifies storage size (and thus indirectly, the precision) for intrinsic data types, such as integer and real.
However, the recommended way now is NOT to specify the kind value of variables in source code, instead, use compiler options to specify the precision we want. For example, we write in the code: real :: abc and then compile the code by using the compiling option -fdefault-real-8 (for gfortran) to specify a 8 byte float number. For ifort, the corresponding option is -r8.
Update:
It seems Fortran experts here strongly object to the recommended way stated above. In spite of this, I still think the above way is a good practice that helps reduce the chance of introducing bugs in Fortran codes because it guarantees that you are using the same kind-value throughout your program (the chance that you do need use different kind-values in different parts of a code is rare) and thus avoids the frequently encountered bugs of kind-value mismatch between dummy and actual arguments in a function call.