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.
You could do it numerically instead:
cpos = pos(1) * 2_8**32 + pos(2)
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.
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,) ! i8p now points to the storage of pos as an array of 100 elements
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 %
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.
Simon Geard wrote:
.. I know from experience that transfer can be slow ..
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?
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)
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).
subroutine sub4(i4) integer(4) :: i4(2) integer(8) :: i8 ! call sub(transfer(i4,i8)) return end subroutine
subroutine sub8(i8) integer(8) :: i8,k8 ! k8=i8 call sub(k8) return end subroutine