Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Efficient conversion / interpretation

Simon_Geard
New Contributor I
708 Views

I need to interpret a 2-element integer(4) array as an integer(8) scaler. Currently I'm using

! One of the next two is a dummy argument
integer(4) :: pos(2)
integer(8) :: cpos

cpos = transfer(pos,cpos)

! or

pos = transfer(cpos,pos)

These two expressions work as expected but I know from experience that transfer can be slow so I was wondering if there is a nifty trick with pointers I could use instead.

Thanks.

0 Kudos
10 Replies
Arjen_Markus
Honored Contributor I
708 Views

You could do it numerically instead:

cpos = pos(1) * 2_8**32 + pos(2)

and:

pos(1) = mod( cpos, 2_8**32 )

pos(2) = cpos / 2_8**32

not as elegant perhaps, but it should not suffer from slowness. If you use the right bit manipulation functions, it could be even faster, I guess.

 

0 Kudos
Steven_L_Intel1
Employee
708 Views

For data this small, TRANSFER will be faster than anything else. If you had a lot of data to reinterpret, you can do a "cast" like this:

use, intrinsic :: ISO_C_BINDING
integer(8), pointer, dimension(:) :: i8p
...
call C_F_POINTER(C_LOC(pos),i8p,[100])
! i8p now points to the storage of pos as an array of 100 elements

 

0 Kudos
Simon_Geard
New Contributor I
708 Views

Well I'm all for keeping things simple so I'll leave this case as transfer. Thanks for the other ideas.

0 Kudos
Steven_L_Intel1
Employee
708 Views

I forgot - you should put the TARGET attribute on anything you'll be referencing through a pointer.

0 Kudos
jimdempseyatthecove
Honored Contributor III
708 Views

You can also use UNION, MAP.

If you do this often, place the map in a user defined type then reference the appropriate mapping via %

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
708 Views

No, please don't use extensions UNION/MAP unless there is no alternative. Besides, these have to go in a derived type (STRUCTURE/RECORD) which requires significant coding changes based on Simon's request.

Heck, if you're going there, use EQUIVALENCE, but that's not allowed on dummy arguments and is not recommended either.

0 Kudos
FortranFan
Honored Contributor II
708 Views

Simon Geard wrote:

..  I know from experience that transfer can be slow ..

@Simon Geard,

Will it be possible for you to elaborate further on your "transfer can be slow" comment?  It is "slow" relative to what?  Do you have any performance measures you can share, however qualitative or sketchy, in terms of what you meant by above.  For example, for the size of datasets of interest to you, have you compared a similar operation with C union or anything else (perhaps EQUIVALENCE) relative to Fortran TRANSFER and taken stock of some penalty with the TRANSFER option?  If so, what is your observation? 

Thanks much,

0 Kudos
jimdempseyatthecove
Honored Contributor III
708 Views

Steve,

I am aware that the perfectly good UNION is frown upon with code "modernization". IMHO "modernization" is failing if it does not include a means to convienently cast types.

I haven't tried this, but would you happen to know if your "cast" in post #3, when placed in a function, completely inlines to the point were no code is generated? (e.g. no temporary pointer or temporaries)

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
708 Views

Yes, it generates code. But not much, and I would not worry about it unless a performance analysis shows it's a bottleneck.

0 Kudos
mecej4
Honored Contributor III
708 Views

Here is an example where the use of TRANSFER has no overhead. Compiled with gfortran -O3 -c, the following two versions of a pass-through subroutine yield the same object code (except for the '4'/'8' difference in the subroutine names).

Version A:

subroutine sub4(i4)
integer(4) :: i4(2)
integer(8) :: i8
!
call sub(transfer(i4,i8))
return
end subroutine

Version B:

subroutine sub8(i8)
integer(8) :: i8,k8
!
k8=i8
call sub(k8)
return
end subroutine

 

0 Kudos
Reply