Você está na página 1de 7

Complex Data Type

This intrinsic data type has the same precision as default REAL and has comparable properties to other intrinsic data types. A COMPLEX object is made up from two default REAL cells and is declared as follows:
COMPLEX :: z, j, za(1:100)

Symbolic constants are expressed as a co-ordinate pair:


COMPLEX, PARAMETER :: i = (0.0,1.0)

Real-valued literals and symbolic constants, and complex valued literals and symbolic constants can all be used in a COMPLEX object initialisation statement (for example, PARAMETER statement), but it is not permissible to allow a constructed value containing real-valued symbolic constants as components. So,
INTEGER, COMPLEX, COMPLEX, COMPLEX, PARAMETER PARAMETER PARAMETER PARAMETER :: :: :: :: a1 = 1, a2 = 2 i = (1.0,2.0) ii = i iii = a1

is OK, but is
COMPLEX, PARAMETER :: iv = (a1,a2) no good. The CMPLX constructor cannot be used

in initialisation expressions.

Complex values can be constructed elsewhere using the CMPLX intrinsic function,
z = CMPLX(x,y)

This format must be used if the RHS is not a literal constant. It is recommended that the CMPLX intrinsic be used even when the RHS is a literal value (except in PARAMETER statements) as this makes the program more consistent and highlights the type conversion,
z = CMPLX(3,6.9)

Type coercion behaves exactly as for the REAL data type, for example, if a COMPLEX literal contained integers, (1,1), these would be promoted to REAL values before assignment to the COMPLEX variable. Complex expressions can be used in the same way as other types
REAL :: x; COMPLEX :: a, b, c, ... a = x*((b+c)*CMPLX(0.1,-0.1)) b = 1

The real value x will be promoted to the complex value CMPLX(x,0). b will be set to CMPLX(1.0,0). If necessary all other data types are promoted to complex values. When a noncomplex value is coerced a 0.0 is placed in the complex part of the coordinate pair.

Switch/Case selectcase(var) case(a) print*, 'var=', a case(b) print*, 'var=', b end select

POINTERS

Pointers have always been a key feature in the C programming language. One reason is the way C passes arguments to functions. As you may recall Fortran passes a function the address of an argument, so that both function and calling routine agree on the location of the corresponding variable in the argument list. C simply passes the value of the argument to the function. If variable "ivar" is an argument to a C function, the function itself has no idea where the original variable is located, and cannot change its value. The C function can only use its value as passed through a separate memory location. As you may imagine this also could play havoc with use of arrays as arguments to C functions. The answer in C is the pointer variable, which can be set to contain the actual memory address of a normal C variable. The C declaration: int *pvar Sets the variable "pvar" as a pointer to integer type variables. It's the "*" before "pvar", that says we are dealing with a pointer variable. If "ivar" is an integer variable then the statement pvar = &ivar results in "pvar" containing an integer giving the address in memory of "ivar". I can then pass "pvar" as an argument to the function, giving it knowledge of the actual location of "ivar" (just as a Fortran function would have), and the ability to use and change the contents of that memory location (ivar), and subsequent locations if "ivar" is an array.. The pointer variable provides more than expanded power in C functions. It gives detailed control over complex data structures. At one time or another most heavy Fortran users have needed this type of capability to efficiently manipulate complex data, and equivalents to the C pointer have been provided on most machines as extensions to Fortran 77. When the Fortran 90 standard was being established, there was a request for this feature. What we got was something a little different, in many respects more powerful, and in some respects intentionally crippled. One underlying theme of new Fortran 90 constructs has been isolation of users from the details of memory allocation. If you will be running on parallel computers, this is not a bad thing. As a result, the Fortran 90 POINTER does point to variables of your choice, but it won't directly tell

you the memory address of that variable. On the surface it behaves like an executable EQUIVALENCE statement, but actually does quite a bit more. I have mixed emotions on this restrictive approach to memory use. I will gratefully write the vast majority of my new code within the constraints of the new Fortran 90 constructs, to obtain maximum portability between different computers. However, as a scientist, I want to understand the workings of my experimental apparatus (the computer performing numerical simulations), and at times tune it for maximum performance. This may require a little more control over physical layout of my data structure. The first step in using Fortran pointers is to determine the variables to which you will need to associate pointers. They must be given the TARGET attribute in a type statement. For example
real, target :: a, b(1000), c(10,10) integer, target :: i, j(100), k(20,20)

Why can't you associate Fortran pointers with any variable having the same type (as in C)? Maybe a cruel joke by the standards committee. More likely, another level of protection against programming errors, to limit the probability that a typo will associate a pointer with the wrong variable.

Now you define some pointers


real, pointer :: pa, aptr, pb(:), pc1(:), pc2(:,:)

The type of the pointer must match the type of the intended target, and the rank of the pointer must match the rank of the portion of the target to which it will be associated. I use the term portion because we will find that "pb" or "pc1" can be associated with a row or a column in "c" for the above examples. The use of isolated colons for pointers is mandatory, because the actual size of the pointer object is not set until the pointer is associated with its target. A pointer behaves a lot like an allocated variable, except you are allocating specific existing memory rather than a new, unused piece of memory.

At any point in my program I can associate a pointer with a target with a statement such as:
pa => a

After this statement I can write a normal assignment such as:


b(i) = pa*c(i,i)

which is identical in effect to


b(i) = a*c(i,i)

I could also write


pa = 1.23456 print *, 'a = ', a

and have a printed result of "1.23456" because changing "pa" changes "a". They refer to the same location in the computer's memory.

The pointer can be re-associated with another variable at any time:

pa => b(1)

or it can be forced to be disassociated from any variable with the NULLIFY statement:
nullify (pa)

You can inquire if a pointer is associated with any target, by using the logical valued intrinsic function ASSOCIATED.
if (associated(pa)) then print *, 'pa is currently associated' endif

For more details you can use the optional TARGET argument to see if the pointer is currently associated with a specific target.
if (associated(pa, target=a)) then print *, 'pa is currently associated with "a"' endif

You can check to see if two pointers are associated with the same target using:
if (associated(pa, target=aptr)) then print *, 'pa and aptr point to the same target' endif

Look at the example associated.f and its results for more information on simple pointer association, the ASSOCIATED intrinsic function, and the NULLIFY statement. Array Pointers Now we get to the interesting part, making associations with arrays or portions of arrays. If I use the statement
pb => b

Any reference to "pb" is identical to a reference to "b". "pb" effectively has 1000 elements. However, I can also write
pb => b(101:200)

In this case "pb" is an array with only 100 elements, and pb(1) is the same as b(101). I could also do the following
pb => c(5,1:10)

In this case we get the curious result that pb(1) is equivalent to c(5,1), pb(2) is equivalent to c(5,2), etc. If you think about this, sequential elements in the object "pb" are actually spaced 10 real words apart in memory. The compiler has hidden a skipping factor (stride) away in the definition of "pb" that can make your programming a little simpler than dealing with "c" directly.

Similar memory strides are involved when a rank two pointer is used to pick up a rectangular portion of a rank 2 array. The statement
pc2 => c(3:5, 4:6)

results in pc2 behaving as an array with 3 rows and 3 columns ( real pc2(3,3)), for which element pc2(1,1) shares memory with c(3,4), pc2(2,1) is the same as c(4,4), on through pc2(3,3) with the same memory location as c(5,6).

A second method exists for allocating space to a pointer. You can use the ALLOCATE statement just as you would for an ALLOCATABLE array. The statement
allocate (pc1(20))

results in addition of memory for a 20 element real array, that can only be accessed through use of pointer "pc1".

For more practice with array pointers, take a look at the results of pointers.f. and try some programs of your own. You are not likely to need pointers in the near future, but try to maintain some memory of this capability. It is very important for complex programming applications in just about any language. Confused? This is the easy part. When pointers are combined with ALLOCATE and derived data types, you have an excellent way to create and manipulate linked lists. Jobs like sorting can be made a little simpler, and some very powerful data structures can be created.
INTEGER, POINTER :: PTR(:) INTEGER, TARGET :: TARG(5) PTR => TARG PTR(1) = 5 PRINT *, FUNC() CONTAINS REAL FUNCTION FUNC() POINTER :: FUNC . . . END FUNCTION END

! PTR is associated with TARG and is ! assigned an array specification of (5) ! TARG(1) has value of 5

! Function result is a pointer

STRUC
module GGCM type record integer :: id integer :: dataLen integer, pointer :: pFile real*8, pointer :: data integer :: ofs end type record contains end module

6.2.1 STRUCTURE and RECORD

Structures are user-defined aggregate data types; this functionality was standardized in Fortran 90 with an different syntax, under the name of derived types. Here is an example of code using the non portable structure syntax:
! Declaring a structure named ``item'' and containing three fields: ! an integer ID, an description string and a floating-point price. STRUCTURE /item/ INTEGER id CHARACTER(LEN=200) description REAL price END STRUCTURE ! Define two variables, an single record of type ``item'' ! named ``pear'', and an array of items named ``store_catalog'' RECORD /item/ pear, store_catalog(100) ! We can directly access the fields of both variables pear.id = 92316 pear.description = "juicy D'Anjou pear" pear.price = 0.15 store_catalog(7).id = 7831 store_catalog(7).description = "milk bottle" store_catalog(7).price = 1.2 ! We can also manipulate the whole structure store_catalog(12) = pear print *, store_catalog(12)

This code can easily be rewritten in the Fortran 90 syntax as following:


! ``STRUCTURE /name/ ... END STRUCTURE'' becomes ! ``TYPE name ... END TYPE'' TYPE item INTEGER id CHARACTER(LEN=200) description REAL price END TYPE ! ``RECORD /name/ variable'' becomes ``TYPE(name) variable'' TYPE(item) pear, store_catalog(100) ! Instead of using a dot (.) to access fields of a record, the ! standard syntax uses a percent sign (%) pear%id = 92316 pear%description = "juicy D'Anjou pear" pear%price = 0.15 store_catalog(7)%id = 7831 store_catalog(7)%description = "milk bottle" store_catalog(7)%price = 1.2 ! Assignments of a whole variable do not change store_catalog(12) = pear print *, store_catalog(12)

Você também pode gostar