I need to declare an automatic array in a subroutine, whose bounds are
the same of another array which the subroutine gets through use
association of a module. For example:
module foo
real,dimension(10) :: MYARRAY = 0.0
end module foo
program myprog
call test
end myprog
subroutine test
use foo
real,dimension(size(MYARRAY)) :: TEMP
end subroutine test
However, if MYARRAY is an high rank array with a long name, the
declaration expression of TEMP becomes complicate, and it may extend
on more lines, like for example:
real,dimension(size(MYARRAYWITHALONGNAME,1),size(MYARRAYWITHALONGNAME,
2),size(MYARRAYWITHALONGNAME,3)...) :: temp
Isn't there a neater way to do this? Thank you,
deltaquattro
Sure. The facile way:
real,dimension(size(MYARRAYWITHALONGNAME,1), &
size(MYARRAYWITHALONGNAME,2), &
size(MYARRAYWITHALONGNAME,3), &
... ....) :: temp
Alternatively:
module foo
integer, parameter :: N = 10
real,dimension(N) :: MYARRAY = 0.0
end module foo
program myprog
call test
end myprog
subroutine test
use foo
real,dimension(N) :: TEMP
end subroutine test
with
real,dimension(N, N, N, ...) :: temp
IMO, there really is no reason to do something like
real,dimension(10) :: MYARRAY = 0.0
as opposed to
integer, parameter :: N = 10
real,dimension(N) :: MYARRAY = 0.0
I try to avoid literal constant as much as possible. In fact, I would even do something like
module foo
integer, parameter :: N = 10
real, parameter :: ZERO = 0.0
real :: MYARRAY(N) = ZERO
end module foo
I usually have a "parameters" module for apps where I define literal constants I will be
using frequently. Then I can always be sure they are the precision I want, e.g.
module myparams
use type_kinds, only: fp
real(fp), parameter :: ZERO = 0.0_fp
real(fp), parameter :: ONE = 1.0_fp
real(fp), parameter :: POINT1 = 0.1_fp
.....etc...
end module myparams
The ZERO and ONE are probably overkill, but, eh.
cheers,
paulv
> real,dimension(size(MYARRAYWITHALONGNAME,1),size(MYARRAYWITHALONGNAME,
> 2),size(MYARRAYWITHALONGNAME,3)...) :: temp
> Isn't there a neater way to do this? Thank you,
Not unless assumed-shape arrays fit your needs. Well, if there are
several arrays you can use 'specification variables' (I just now made
that term up).
character(0) sv1(size(MYARRAYWITHLONGNAME,1))
character(0) sv2(size(MYARRAYWITHLONGNAME,2))
character(0) sv3(size(MYARRAYWITHLONGNAME,3))
then the variable above could be declared as
real temp(ubound(sv1,1),ubound(sv2,1),ubound(sv3,1))
So you have shorter names for these quantities. Note that getting
fancy with specification expressions as in the above crashes
compilers all over the place.
It looks like it's crashing both gfortran and ifort. Check out
this example:
C:\Program Files\Microsoft Visual Studio 8\James\clf\len_test>type
len_test.f90
program len_test
implicit none
character(-10) x
character(0) y(-10)
write(*,*) len(x)
write(*,*) ubound(y,1)
end program len_test
C:\Program Files\Microsoft Visual Studio 8\James\clf\len_test>ifort
len_test.f90
Intel(R) Fortran Compiler for Intel(R) EM64T-based applications, Version 9.1
Build 20061104
Copyright (C) 1985-2006 Intel Corporation. All rights reserved.
Microsoft (R) Incremental Linker Version 8.00.40310.39
Copyright (C) Microsoft Corporation. All rights reserved.
-out:len_test.exe
-subsystem:console
len_test.obj
C:\Program Files\Microsoft Visual Studio 8\James\clf\len_test>len_test
0
0
C:\Program Files\Microsoft Visual Studio
8\James\clf\len_test>c:\gfortran\win64\
bin\x86_64-pc-mingw32-gfortran len_test.f90 -olen_test
len_test.f90:4.13:
character(0) y(-10)
1
Warning: CHARACTER variable has zero length at (1)
len_test.f90:3.13:
character(-10) x
1
Warning: CHARACTER variable has zero length at (1)
C:\Program Files\Microsoft Visual Studio 8\James\clf\len_test>len_test
0
0
Now, looking at the f90 standard, it seems that if the length of a
character variable is declared as negative, the length comes out as
zero, and both compilers are handling this case OK. However, I don't
see where the UBOUND is supposed to be normalized for zero-sized
arrays. In section 5.1.2.4.1, it says
"If the upper bound is less than the lower bound, the range is empty,
the extent in that dimension is zero, and the array is of zero size."
This seems to say that the bounds shouldn't be normalized away for
zero-sized arrays and that I should be getting -10 for the second line
of output in the above example, but both compilers are normalizing and
spitting out zero. Is there an interpretation that I'm not aware of or
are the compilers doing the wrong thing here?
--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end
Well, maybe there's a standard you're not aware of because in Ch. 13 of the
f95 standard it states clearly that the lower bound of a zero-size array is
one and its upper bound is zero.
Regards,
Mike Metcalf
> Well, maybe there's a standard you're not aware of because in Ch. 13 of
> the f95 standard it states clearly that the lower bound of a zero-size
> array is one and its upper bound is zero.
To clarify what we're talking about, section 13.14.113 of f95 says:
"For an array section or for an array expression, other than a whole array
or
array structure component, UBOUND(ARRAY,DIM) has a value equal to the number
of elements in the given dimension; otherwise, it has a value equal to the
upper bound for subscript DIM of ARRAY if dimension DIM of ARRAY does not
have size zero and has the value zero if dimension DIM has size zero."
I had just looked at the first and last parts of this passage and didn't
realize that the last clause about normalizing to zero happens for all
arrays, not just array sections or expressions. Thank you for the
correction,
Mike!
That means that my code was in error, but it doesn't seem to me that a
complete fix is possible. Here is my new example:
C:\Program Files\Microsoft Visual Studio 8\James\clf\len_test>type
len_test.f90
program len_test
implicit none
character(-10) x
character(0) y(-10)
character(0) z(-10:huge(1))
write(*,*) len(x)
write(*,*) ubound(y,1)
write(*,*) lbound(z,1)
end program len_test
C:\Program Files\Microsoft Visual Studio
8\James\clf\len_test>c:\gfortran\win64\
bin\x86_64-pc-mingw32-gfortran len_test.f90 -olen_test
len_test.f90:5.13:
character(0) z(-10:huge(1))
1
Warning: CHARACTER variable has zero length at (1)
len_test.f90:4.13:
character(0) y(-10)
1
Warning: CHARACTER variable has zero length at (1)
len_test.f90:3.13:
character(-10) x
1
Warning: CHARACTER variable has zero length at (1)
C:\Program Files\Microsoft Visual Studio 8\James\clf\len_test>len_test
0
0
-10
C:\Program Files\Microsoft Visual Studio 8\James\clf\len_test>ifort
len_test.f90
Intel(R) Fortran Compiler for Intel(R) EM64T-based applications, Version 9.1
Build 20061104
Copyright (C) 1985-2006 Intel Corporation. All rights reserved.
Microsoft (R) Incremental Linker Version 8.00.40310.39
Copyright (C) Microsoft Corporation. All rights reserved.
-out:len_test.exe
-subsystem:console
len_test.obj
C:\Program Files\Microsoft Visual Studio 8\James\clf\len_test>len_test
0
0
-10
Bingo! Well, partial Bingo!... The problem with this last example is
that it's possible for default integers to be bigger than HUGE(1). I
can't see a way to work around this and that is why I (optimistically)
tried the UBOUND stuff that, as Mike pointed out, doesn't work. I guess
one could create a module with HUGE_ik1, HUGE_ik2, ... constants that
are the 'truly huge' representatives of their respective KINDs but how
then would those values be generated by initialization expressions
within the module in such a way that programmer input wouldn't be
required? I don't know about any current machines that have a problem
with HUGE(1) (perhaps Crays?) so it doesn't seem to be a big problem
at the current time. Oh, but there is a way to do it:
integer, parameter, public :: TRULY_HUGE_ik1 =
minval([INTEGER(KIND=ik1)::],1)
But the above fails for two reasons:
1) gfortran and ifort don't like this syntax for zero-size array
constructors,
but even when you fix it to
integer, parameter, public :: TRULY_HUGE_ik1 = minval([(1_ik1,i=1,0)],1)
2) Most transformational intrinsics such as MINVAL aren't allowed in
initialization expressions. So you could use them in specification
expressions:
C:\Program Files\Microsoft Visual Studio 8\James\clf\len_test>type
len_test_3.f9
0
module test
implicit none
contains
function my_string(x)
integer i
real, intent(in) :: x(:)
character(0) h4(1:minval([(1,i=1,0)],1))
character(0) sv1(size(x,1):size(h4))
character(0) sv2(2*lbound(sv1,1):size(h4))
character(lbound(sv2,1)-3) my_string
do i = 1, len(my_string)
my_string(i:i) = achar(modulo(i-1,10)+iachar('0'))
end do
end function my_string
end module test
program len_test
use test
implicit none
real x(7)
write(*,*) my_string(x)
end program len_test
C:\Program Files\Microsoft Visual Studio
8\James\clf\len_test>c:\gfortran\win64\
bin\x86_64-pc-mingw32-gfortran len_test_3.f90 -olen_test_3
len_test_3.f90:9.19:
character(0) sv2(2*lbound(sv1,1):size(h4))
1
Warning: CHARACTER variable has zero length at (1)
len_test_3.f90:8.19:
character(0) sv1(size(x,1):size(h4))
1
Warning: CHARACTER variable has zero length at (1)
len_test_3.f90:7.19:
character(0) h4(1:minval([(1,i=1,0)],1))
1
Warning: CHARACTER variable has zero length at (1)
len_test_3.f90:19.11:
use test
1
Warning: CHARACTER variable has zero length at (1)
len_test_3.f90:19.11:
use test
1
Warning: CHARACTER variable has zero length at (1)
len_test_3.f90:19.11:
use test
1
Warning: CHARACTER variable has zero length at (1)
len_test_3.f90:19.11:
use test
1
Warning: CHARACTER variable has zero length at (1)
len_test_3.f90:19.11:
use test
1
Warning: CHARACTER variable has zero length at (1)
len_test_3.f90:19.11:
use test
1
Warning: CHARACTER variable has zero length at (1)
len_test_3.f90:19.11:
use test
1
Warning: CHARACTER variable has zero length at (1)
len_test_3.f90: In function 'MAIN__':
len_test_3.f90:23: internal compiler error: in make_decl_rtl, at
varasm.c:1263
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://gcc.gnu.org/bugs.html> for instructions.
C:\Program Files\Microsoft Visual Studio 8\James\clf\len_test>ifort
len_test_3.f
90
Intel(R) Fortran Compiler for Intel(R) EM64T-based applications, Version 9.1
Build 20061104
Copyright (C) 1985-2006 Intel Corporation. All rights reserved.
len_test_3.f90(4) : Severe: **Internal compiler error: internal abort**
Please r
eport this error along with the circumstances in which it occurred in a
Software
Problem Report. Note: File and line given may not be explicit cause of
this er
ror.
function my_string(x)
---------------^
compilation aborted for len_test_3.f90 (code 3)
So now we have a program that achieves its goal on at least two compilers!
It's rather long, though: real men shouldn't need more than 3 bytes to
achieve ICE!
> So now we have a program that achieves its goal on at least two compilers!
> It's rather long, though: real men shouldn't need more than 3 bytes to
> achieve ICE!
What, END? Five with the line terminator... :-)
Amusing - I'll pass this one on to the ifort developers.
Steve
What about:
subroutine test
use foo, someShortAlias => MYARRAYWITHALONGNAME
real,dimension(size(someShortAlias, 1), &
size(someShortAlias, 2), &
... ...) :: TEMP
end subroutine test
module foo
type foo_type
real,dimension(:),allocatable :: contents
end type
type(foo_type),save :: MYARRAY
integer,parameter,save :: N_ARRAY=10
contains
subroutine(init)
allocated(MYARRAY%contents(N_ARRAY))
MYARRAY%contents = 0.0
end subroutine
end module foo
program myprog
use foo
call init()
call test()
end myprog
subroutine test
type(foo_type) :: TEMP
TEMP = MYARRAY
end subroutine test
TEMP%contents is now allocated (10 in this case) and contains the
values of MYARRAY%contents (all elements are 0.0 in this case).
arno
Eh :-) Paul, I'm not so naive as to use literal constants in actual
code. I just tried to keep the code snippet as simple as possible, so
I let out the fact that MYARRAY is an allocatable whose size is not
known at compile time. Using your suggestion, I can write:
module foo
integer :: n
real,allocatable,dimension(:) :: MYARRAY
end module foo
program myprog
read(*,*) n
allocate(MYARRAY(n))
MYARRAY=0.0
call test
end myprog
subroutine test
use foo
real,dimension(n) :: TEMP
end subroutine test
That should work fine. Thanks,
regards,
deltaquattro
That's a nice example of the usefulness of the renaming operator.Thank
you,
best regards,
deltaquattro
Hi, Arno,
that's really interesting: I wasn't aware of that. However, I found it
a bit strange that you didn't need to allocate TEMP before. So I read
the section about the allocatable TR on MR&C, and it says that it's
not needed. As a matter of fact, intrinsic assignment to a variable
VAR of a type with an ultimate allocatable component causes VAR to be
deallocated, if currently allocated, and then reallocated with same
bounds and values of the assignment expression.
What I expecially like of this solution is that in this way the
structure of TEMP is totally transparent to test and I can modify it
in foo, without touching the code in test. Something like data
encapsulation in OOP. For my problem, this is overkill, but it's good
to know it, anyway. Thanks,
bye,
deltaquattro
> On Nov 2, 12:27 pm, "James Van Buskirk" <not_va...@comcast.net> wrote:
>> So now we have a program that achieves its goal on at least two
>> compilers!
>> It's rather long, though: real men shouldn't need more than 3 bytes to
>> achieve ICE!
> What, END? Five with the line terminator... :-)
Have you been staying up too late watching 17P/Holmes? Your accuracy has
been off a bit: some compilers have been known to accept source files with
improper termination of the last line, and some are even capable of
generating such files.