Fortran PACK issue

The Fortran PACK intrinsic appears to return a rank one array of the same size as its source, regardless of the MASK used. The excess array elements appear uninitialized.

For example:

PACK ((/1,2,3,4/),mask=(/.false.,.true.,.true.,.false./))

will return something that looks like:

(/2,3,-3345345,-5905780/)

when I believe it should return:

(/2,3/)

Is this not correct?

If the current PACK is correct, how do I know how many elements matching my MASK are returned?

Hi tsalem,

I’ll need a bit more information on what you’re doing since I show PACK returning a two element array (/2,3/).

% cat test.f90
        integer, dimension(8) :: iarr
        iarr = 10
        print *, PACK ((/1,2,3,4/),(/.false.,.true.,.true.,.false./))
        iarr = PACK ((/1,2,3,4/),(/.false.,.true.,.true.,.false./))
        print *, iarr
        end
% pgf90 test.f90 ; a.out
            2            3
            2            3            0            0            0            0
       121841            0

In the second case where I’m storing the result of PACK into iarr using an array assignment, this is actually a bug in my code since the arrays are non-conforming. To fix, I really should be using an array section.

% cat test.f90
        integer, dimension(8) :: iarr
        iarr = 10
        print *, PACK ((/1,2,3,4/),(/.false.,.true.,.true.,.false./))
        iarr(1:2) = PACK ((/1,2,3,4/),(/.false.,.true.,.true.,.false./))
        print *, iarr
        end
% pgf90 test.f90
% a.out
            2            3
            2            3           10           10           10           10
           10           10

Perhaps you have the same coding error?

  • Mat

Hi Mat.

I was using a simplified version of what I was trying to do.

In your first approach, you’ll notice the apparently uninitialized 7th array element.

The problem with using the approach you outlined in your second example is that you have to know how many elements are in the “packed” array prior to the pack in order to accomplish what you did. That means I’ve got to PACK, count, and PACK again - not very efficient if he array is large.

According to section 17.5.2 of “Fortran 95/2003 Explained” by Metcalf, et al, one should be able to make this assignment for an allocatable array x,
x = pack(y,mask=zzz)
x will then be sized just large enough to hold the packed values of y.

Now, I know that this means that PGI fortran need to be 2003 compliant. I just thought there might be an easy way to do what I want using the 2003 PACK intrinsic.

Hi tsalem,

In your first approach, you'll notice the apparently uninitialized 7th array element.

Yes. As I noted, the two element temp array returned by PACK and iarr are non-conformable. This is a bug in the code. Array assignments essentially get turned into a DO loop. Since the temp array is smaller than the iarr array, the code is copying data beyond bounds of the temp array thus getting garbage values.

According to section 17.5.2 of “Fortran 95/2003 Explained” by Metcalf, et al, one should be able to make this assignment for an allocatable array x,
x = pack(y,mask=zzz)
x will then be sized just large enough to hold the packed values of y.

While not on by default, adding the flag “-Mallocatable=03” will get you F2003 allocatable semantics. The caveat is that it may have a detrimental impact on performance.

% cat test.f90

        integer, allocatable :: iarr(:)
        print *, PACK ((/1,2,3,4/),(/.false.,.true.,.true.,.false./))
        iarr = PACK ((/1,2,3,4/),(/.false.,.true.,.true.,.false./))
        print *, iarr
        end
% pgf90 test.f90 -Mallocatable=03 
% a.out
            2            3
            2            3

Hope this helps,
Mat