Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

"Ugly" declaration of high rank automatic arrays

9 views
Skip to first unread message

deltaquattro

unread,
Nov 2, 2007, 12:11:33 PM11/2/07
to
Hi,

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

Paul van Delst

unread,
Nov 2, 2007, 12:39:17 PM11/2/07
to

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

James Van Buskirk

unread,
Nov 2, 2007, 1:10:49 PM11/2/07
to
"deltaquattro" <deltaq...@gmail.com> wrote in message
news:1194019893.5...@o80g2000hse.googlegroups.com...

> 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


Michael Metcalf

unread,
Nov 2, 2007, 2:11:19 PM11/2/07
to

"James Van Buskirk" <not_...@comcast.net> wrote in message
news:_dqdnSnea-mIx7ba...@comcast.com...

> "deltaquattro" <deltaq...@gmail.com> wrote in message
> 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?
>

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


James Van Buskirk

unread,
Nov 2, 2007, 3:27:03 PM11/2/07
to
"Michael Metcalf" <michael...@compuserve.com> wrote in message
news:bLJWi.12$Cc.6@trndny09...

> 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!

Steve Lionel

unread,
Nov 2, 2007, 7:07:31 PM11/2/07
to
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... :-)

Amusing - I'll pass this one on to the ifort developers.

Steve

jwm

unread,
Nov 3, 2007, 3:30:52 AM11/3/07
to

What about:

subroutine test
use foo, someShortAlias => MYARRAYWITHALONGNAME
real,dimension(size(someShortAlias, 1), &
size(someShortAlias, 2), &
... ...) :: TEMP
end subroutine test

Arno

unread,
Nov 5, 2007, 4:48:24 AM11/5/07
to
not a solution, but it might be of interest to you; derived types
containing arrays (even allocatable arrays) are automatically of the
size of the original when copied.

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

deltaquattro

unread,
Nov 5, 2007, 5:55:16 AM11/5/07
to
On 2 Nov, 17:39, Paul van Delst <Paul.vanDe...@noaa.gov> wrote:
> deltaquattro wrote:
[..]

>
> 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.

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

deltaquattro

unread,
Nov 5, 2007, 5:58:28 AM11/5/07
to
On 3 Nov, 08:30, jwm <jwmwal...@gmail.com> wrote:
[..]

> What about:
>
> subroutine test
> use foo, someShortAlias => MYARRAYWITHALONGNAME
> real,dimension(size(someShortAlias, 1), &
> size(someShortAlias, 2), &
> ... ...) :: TEMP
> end subroutine test- Nascondi testo tra virgolette -
>
> - Mostra testo tra virgolette -

That's a nice example of the usefulness of the renaming operator.Thank
you,

best regards,

deltaquattro

deltaquattro

unread,
Nov 5, 2007, 6:32:53 AM11/5/07
to
On 5 Nov, 10:48, Arno <arnoinp...@hotmail.com> wrote:
> not a solution, but it might be of interest to you; derived types
> containing arrays (even allocatable arrays) are automatically of the
> size of the original when copied.
[..]

> 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

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


James Van Buskirk

unread,
Nov 5, 2007, 12:24:04 PM11/5/07
to
"Steve Lionel" <steve....@intel.com> wrote in message
news:1194044851....@d55g2000hsg.googlegroups.com...

> 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.

0 new messages