 |
forums.silverfrost.com Welcome to the Silverfrost forums
|
View previous topic :: View next topic |
Author |
Message |
christyleomin
Joined: 08 Apr 2011 Posts: 155
|
Posted: Wed Apr 03, 2013 3:37 pm Post subject: Fortran intrinsic function for getting size of array |
|
|
Please can anyone tell me which is the FORTRAN intrinsic function to get the size of the array?
I'd like to get size of a one,two,three diemnsional arrays
any help?Thanks a lot
Christy |
|
Back to top |
|
 |
simon
Joined: 05 Jul 2006 Posts: 299
|
Posted: Wed Apr 03, 2013 7:14 pm Post subject: |
|
|
Try Size will give you the total dimension, but SHAPE is more useful if you want the individual dimensions. But you may need calls to LBOUND and UBOUND if the lower limit is not 1. |
|
Back to top |
|
 |
JohnCampbell
Joined: 16 Feb 2006 Posts: 2615 Location: Sydney
|
Posted: Thu Apr 04, 2013 12:31 am Post subject: |
|
|
If you are asking for the number of elements of the array, then SIZE can help, providing the dimensions of the array are available.
If you are using a derived type, I am not sure if SIZE can cope with this.
If you want the memory size (in bytes), F2008 introduced STORAGE_SIZE to give this. It would be great if this was included in FTN95 as an extension.
However, to write this in FTN95, you also need a generic function which gives you the number of bytes in each kind of variable. This would be a generic function, which might be easy to write.
STORAGE_SIZE (A) = SIZE (A) * BYTE_SIZE (A)
My attempt for Integer and Real is: Code: | module byte_info
!
interface byte_size
module procedure byte_size_i1, byte_size_i2, byte_size_i4, byte_size_i8, &
byte_size_r4, byte_size_r8, byte_size_r10
end interface byte_size
!
contains
!
integer*4 function byte_size_i1 (x)
integer*1 :: x
byte_size_i1 = 1
end function byte_size_i1
!
integer*4 function byte_size_i2 (x)
integer*2 :: x
byte_size_i2 = 2
end function byte_size_i2
!
integer*4 function byte_size_i4 (x)
integer*4 :: x
byte_size_i4 = 4
end function byte_size_i4
!
integer*4 function byte_size_i8 (x)
integer*8 :: x
byte_size_i8 = 8
end function byte_size_i8
!
integer*4 function byte_size_r4 (x)
real*4 :: x
byte_size_r4 = 4
end function byte_size_r4
!
integer*4 function byte_size_r8 (x)
real*8 :: x
byte_size_r8 = 8
end function byte_size_r8
!
integer*4 function byte_size_r10 (x)
real*10 :: x
byte_size_r10 = 10
end function byte_size_r10
!
end module byte_info
use Byte_info
!
real*8 array_r8(4,3)
integer*2 array_i2(4,3)
!
write (*,*) 'array_r8', size(array_r8) * byte_size (array_r8), byte_size (array_r8)
write (*,*) 'array_i2', size(array_i2) * byte_size (array_i2), byte_size (array_i2)
!
end
|
{ Woops, doesn't work !! }
This is the same as KIND for most other compilers.
The significant change in F2008 was to include derived types.
John |
|
Back to top |
|
 |
JohnCampbell
Joined: 16 Feb 2006 Posts: 2615 Location: Sydney
|
Posted: Thu Apr 04, 2013 1:20 am Post subject: |
|
|
The following works, but does not realy provide the required functionality
It appears that MODULE PROCEDURE must agree with both intrinsic type and rank. Code: | module byte_info
!
interface byte_size
module procedure byte_size_i1, byte_size_i2, byte_size_i4, byte_size_i8
end interface byte_size
!
contains
!
integer*4 function byte_size_i1 (x)
integer*1 :: x
byte_size_i1 = 1
end function byte_size_i1
!
integer*4 function byte_size_i2 (x)
integer*2 :: x
byte_size_i2 = 2
end function byte_size_i2
!
integer*4 function byte_size_i4 (x)
integer*4 :: x
byte_size_i4 = 4
end function byte_size_i4
!
integer*4 function byte_size_i8 (x)
integer*8 :: x
byte_size_i8 = 8
end function byte_size_i8
!
end module byte_info
use Byte_info
!
integer*8 array_i8(4,3)
integer*4 array_i4(4,3)
integer*2 array_i2(4,3)
integer*1 array_i1(4,3)
!
write (*,*) 'array_i8', size (array_i8) * byte_size (array_i8(1,1)), byte_size (array_i8(1,1)), kind (array_i8)
write (*,*) 'array_i4', size (array_i4) * byte_size (array_i4(1,1)), byte_size (array_i4(1,1)), kind (array_i4)
write (*,*) 'array_i2', size (array_i2) * byte_size (array_i2(1,1)), byte_size (array_i2(1,1)), kind (array_i2)
write (*,*) 'array_i1', size (array_i1) * byte_size (array_i1(1,1)), byte_size (array_i1(1,1)), kind (array_i1)
!
end
|
It would be good if there was a generic BYTE_SIZE, that worked in conjunction with SIZE, as does KIND for intrinsic types.
It was not until F2008 that this functionality is provided. This works for both intrinsic and derived types. |
|
Back to top |
|
 |
JohnCampbell
Joined: 16 Feb 2006 Posts: 2615 Location: Sydney
|
Posted: Thu Apr 04, 2013 2:11 am Post subject: |
|
|
Trying to write BYTE_SIZE has identified a lot of restrictions.
While KIND accepsts both scalar and array arguments,
SIZE only accepts array arguments
BYTE SIZE would require support for scalar, array and derived type.
MODULE PROCEDURE appears to be very restrictive.
My latest version supports INTEGER and REAL intrinsic types for scalar or rank 1 or 2 arrays only.
Hopefully this works and is small enough to post !!
Code: | module byte_info
!
interface byte_size
module procedure byte_size_i1_0, byte_size_i1_1, byte_size_i1_2, &
byte_size_i2_0, byte_size_i2_1, byte_size_i2_2, &
byte_size_i4_0, byte_size_i4_1, byte_size_i4_2, &
byte_size_i8_0, byte_size_i8_1, byte_size_i8_2, &
byte_size_r4_0, byte_size_r4_1, byte_size_r4_2, &
byte_size_r8_0, byte_size_r8_1, byte_size_r8_2, &
byte_size_r10_0, byte_size_r10_1, byte_size_r10_2
end interface byte_size
!
contains
!
integer*4 function byte_size_i1_0 (x) ; integer*1 :: x ; byte_size_i1_0 = 1 ; end function byte_size_i1_0
integer*4 function byte_size_i1_1 (x) ; integer*1 :: x(:) ; byte_size_i1_1 = 1 ; end function byte_size_i1_1
integer*4 function byte_size_i1_2 (x) ; integer*1 :: x(:,:) ; byte_size_i1_2 = 1 ; end function byte_size_i1_2
!
integer*4 function byte_size_i2_0 (x) ; integer*2 :: x ; byte_size_i2_0 = 2 ; end function byte_size_i2_0
integer*4 function byte_size_i2_1 (x) ; integer*2 :: x(:) ; byte_size_i2_1 = 2 ; end function byte_size_i2_1
integer*4 function byte_size_i2_2 (x) ; integer*2 :: x(:,:) ; byte_size_i2_2 = 2 ; end function byte_size_i2_2
!
integer*4 function byte_size_i4_0 (x) ; integer*4 :: x ; byte_size_i4_0 = 4 ; end function byte_size_i4_0
integer*4 function byte_size_i4_1 (x) ; integer*4 :: x(:) ; byte_size_i4_1 = 4 ; end function byte_size_i4_1
integer*4 function byte_size_i4_2 (x) ; integer*4 :: x(:,:) ; byte_size_i4_2 = 4 ; end function byte_size_i4_2
!
integer*4 function byte_size_i8_0 (x) ; integer*8 :: x ; byte_size_i8_0 = 8 ; end function byte_size_i8_0
integer*4 function byte_size_i8_1 (x) ; integer*8 :: x(:) ; byte_size_i8_1 = 8 ; end function byte_size_i8_1
integer*4 function byte_size_i8_2 (x) ; integer*8 :: x(:,:) ; byte_size_i8_2 = 8 ; end function byte_size_i8_2
!
integer*4 function byte_size_r4_0 (x) ; real*4 :: x ; byte_size_r4_0 = 4 ; end function byte_size_r4_0
integer*4 function byte_size_r4_1 (x) ; real*4 :: x(:) ; byte_size_r4_1 = 4 ; end function byte_size_r4_1
integer*4 function byte_size_r4_2 (x) ; real*4 :: x(:,:) ; byte_size_r4_2 = 4 ; end function byte_size_r4_2
!
integer*4 function byte_size_r8_0 (x) ; real*8 :: x ; byte_size_r8_0 = 8 ; end function byte_size_r8_0
integer*4 function byte_size_r8_1 (x) ; real*8 :: x(:) ; byte_size_r8_1 = 8 ; end function byte_size_r8_1
integer*4 function byte_size_r8_2 (x) ; real*8 :: x(:,:) ; byte_size_r8_2 = 8 ; end function byte_size_r8_2
!
|
not the case !! more below |
|
Back to top |
|
 |
JohnCampbell
Joined: 16 Feb 2006 Posts: 2615 Location: Sydney
|
Posted: Thu Apr 04, 2013 2:15 am Post subject: |
|
|
Code: | !
integer*4 function byte_size_r10_0 (x) ; real*10 :: x ; byte_size_r10_0 = 10 ; end function byte_size_r10_0
integer*4 function byte_size_r10_1 (x) ; real*10 :: x(:) ; byte_size_r10_1 = 10 ; end function byte_size_r10_1
integer*4 function byte_size_r10_2 (x) ; real*10 :: x(:,:) ; byte_size_r10_2 = 10 ; end function byte_size_r10_2
!
end module byte_info
use Byte_info
!
integer*8 array_i8(4,3)
integer*4 array_i4(4,3)
integer*2 array_i2(4,3)
integer*1 array_i1(4,3)
real*4 x(2,2)
!
write (*,*) 'array_i8', size (array_i8) * byte_size (array_i8), byte_size (array_i8), kind (array_i8)
write (*,*) 'array_i4', size (array_i4) * byte_size (array_i4), byte_size (array_i4), kind (array_i4)
write (*,*) 'array_i2', size (array_i2) * byte_size (array_i2), byte_size (array_i2), kind (array_i2)
write (*,*) 'array_i1', size (array_i1) * byte_size (array_i1), byte_size (array_i1), kind (array_i1)
write (*,*) 'x(2,2) ', size (x ) * byte_size (x ), byte_size (x ), kind (x )
!
end
|
I've probably missed something in this, so if anyone knows better, I'd be pleased to learn more.
Why wasn't BYTE_SIZE or STORAGE_SIZE provided for scalar and arrays ( and derived types) before F2008 ?
John |
|
Back to top |
|
 |
davidb
Joined: 17 Jul 2009 Posts: 560 Location: UK
|
Posted: Thu Apr 04, 2013 8:47 am Post subject: Re: |
|
|
JohnCampbell wrote: |
I've probably missed something in this, so if anyone knows better, I'd be pleased to learn more.
John |
Sometimes less code is more John! I just do this sort of thing inline:
Code: |
integer :: byte_size
real :: var ! < real in this example, but can be any variable type/kind
! Get size of variable var in bytes
byte_size = size(transfer(var, (/'A'/)))
|
Works with everything, derived type variables, and arrays too!
This in-line code creates a temporary array of ASCII characters large enough to contain the variable, then returns the size of that. It relies on the fact that the default (ASCII) characters are 1 byte in size.
(/'A'/) is a rank-one array of ASCI characters of size 1. 'A' is an ASCII character of course. _________________ Programmer in: Fortran 77/95/2003/2008, C, C++ (& OpenMP), java, Python, Perl |
|
Back to top |
|
 |
JohnCampbell
Joined: 16 Feb 2006 Posts: 2615 Location: Sydney
|
Posted: Thu Apr 04, 2013 9:21 am Post subject: |
|
|
David,
Thanks for that. I tried a few variations of 'A'.
I then tried larger arrays, before failing with an allocatable array 'x'.
The local array 'b' can go up to about 800mb and still work (showing it might not be using the stack for teh temporary array), while moderate versions of 'x' fail with the stack.
John
Code: | Real*8 a(6)
real*4 b(8000,4000)
real*4, allocatable :: x(:,:)
!
integer*4 byte_size, i
integer*1 i_1, j_1(1)
!
byte_size = size ( transfer (a, (/ 'A' /)) )
write (*,2001) Byte_size," transfer (a, (/ 'A' /))"
!
byte_size = size ( transfer (a, (/ i_1 /)) )
write (*,2001) Byte_size,' transfer (a, (/ i_1 /))'
!
byte_size = size ( transfer (a, J_1) )
write (*,2001) Byte_size,' transfer (a, J_1)'
!
byte_size = size ( transfer (b, J_1) )
write (*,2001) Byte_size,' transfer (b, J_1)'
!
do i = 10000, 80000, 10000
write (*,*) (i*1000*4.)/1000000.
allocate (x(i,1000))
byte_size = size ( transfer (x, J_1) )
write (*,2001) Byte_size,' transfer (x, J_1)'
deallocate (x)
end do
!
2001 format (b'z,zzz,zzz,zz#',a)
end |
|
|
Back to top |
|
 |
davidb
Joined: 17 Jul 2009 Posts: 560 Location: UK
|
Posted: Thu Apr 04, 2013 9:39 am Post subject: |
|
|
The temporary array is created on the stack so this method can indeed fail for large arrays.
I think for arrays you should just get the size in bytes of one element and then multiply by the number of elements in the array, like this:
Code: |
integer byte_size
real :: a(1000)
! Get size in bytes
byte_size = size(a) * size(transfer(a(1),(/'A'/)))
|
This will always be more efficient than using transfer on the whole array. And you won't have a stack size issue. _________________ Programmer in: Fortran 77/95/2003/2008, C, C++ (& OpenMP), java, Python, Perl |
|
Back to top |
|
 |
JohnCampbell
Joined: 16 Feb 2006 Posts: 2615 Location: Sydney
|
Posted: Thu Apr 04, 2013 1:44 pm Post subject: |
|
|
David,
Thanks for this. It looks like a useful approach.
John |
|
Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|