|
|
 |
 |
 |
 |
Fortran Programming Language
|
 |
 |
 |
 |
 |
 |
 |
 |
Lower index bound confusion
I'm confused by the rules for lower array index bound. In some situations the index bound is retained, in other it is "shifted" so that the lower bound becomes 1. By experiment I noticed that if A(:) and B(:) are array pointers then e.g. ALLOCATE(B(10:20)) A => B WRITE(*,*) LBOUND(A,1) A => B(10:20) WRITE(*,*) LBOUND(A,1) ... yields 10 1 Is this guaranteed by the standard or is it compiler-dependent? Also i noticed for dummy variables the lower index bound is by default shifted to 1, even for array pointer actual argument, unless the dummy variable is a pointer array, then the lower bound is retained. At least on my compiler. Is there some golden rule or thought behind all this that I fail to see?
On May 25, 9:49 am, Kurt <nob@nowhere.org> wrote:
> I'm confused by the rules for lower array index bound. In some > situations the index bound is retained, in other it is "shifted" so that > the lower bound becomes 1. > By experiment I noticed that if A(:) and B(:) are array pointers then e.g. > ALLOCATE(B(10:20)) > A => B > WRITE(*,*) LBOUND(A,1) > A => B(10:20) > WRITE(*,*) LBOUND(A,1) > ... yields > 10 > 1 > Is this guaranteed by the standard or is it compiler-dependent? Also i > noticed for dummy variables the lower index bound is by default shifted > to 1, even for array pointer actual argument, unless the dummy variable > is a pointer array, then the lower bound is retained. At least on my > compiler. > Is there some golden rule or thought behind all this that I fail to see?
Yes, there is. On pointer assignment, the bounds of the pointer are determined as if LBOUND and UBOUND were applied to the target. Thus, pointer assignment to a whole array variable inherits its lower bounds, whereas assigment to a subobject gets the bounds of the subobject, and every subobject has the default lower bounds, i.e. 1. You can find more here: http://en.wikipedia.org/wiki/Fortran_language_features#Pointers_as_dy...
On 25 mei, 10:12, highegg <high@gmail.com> wrote:
> On May 25, 9:49 am, Kurt <nob @nowhere.org> wrote: > > I'm confused by the rules for lower array index bound. In some > > situations the index bound is retained, in other it is "shifted" so that > > the lower bound becomes 1. > > By experiment I noticed that if A(:) and B(:) are array pointers then e.g. > > ALLOCATE(B(10:20)) > > A => B > > WRITE(*,*) LBOUND(A,1) > > A => B(10:20) > > WRITE(*,*) LBOUND(A,1) > > ... yields > > 10 > > 1 > > Is this guaranteed by the standard or is it compiler-dependent? Also i > > noticed for dummy variables the lower index bound is by default shifted > > to 1, even for array pointer actual argument, unless the dummy variable > > is a pointer array, then the lower bound is retained. At least on my > > compiler. > > Is there some golden rule or thought behind all this that I fail to see? > Yes, there is. On pointer assignment, the bounds of the pointer are > determined as if LBOUND and UBOUND were applied to the target. > Thus, pointer assignment to a whole array variable inherits its lower > bounds, whereas assigment to a subobject gets the bounds of the > subobject, and every subobject has the default lower bounds, i.e. 1. > You can find more here:http://en.wikipedia.org/wiki/Fortran_language_features#Pointers_as_dy...
Note that similar problems occur if you pass an array like B(10:20) to a subroutine: subroutine mysub( b ) real, dimension(:) :: b write(*,*) lbound(b) end subroutine The lbound in the subroutine is 1, regardless of the lbound of the actual argument. I can think of a rationale for this behaviour (not sure if that is correct, though): in this way subroutines and functions do not need to take care of non-default lower bounds, by far the most common case. If you need a different lower bound, then you can pass it as an explicit argument: subroutine mysub2( b, lower ) integer :: lower real, dimension(lower:) :: b write(*,*) lbound(b) end subroutine Regards, Arjen
highegg wrote: > On May 25, 9:49 am, Kurt <nob @nowhere.org> wrote: >> I'm confused by the rules for lower array index bound. In some >> situations the index bound is retained, in other it is "shifted" so that >> the lower bound becomes 1. >> By experiment I noticed that if A(:) and B(:) are array pointers then e.g. >> ALLOCATE(B(10:20)) >> A => B >> WRITE(*,*) LBOUND(A,1) >> A => B(10:20) >> WRITE(*,*) LBOUND(A,1) >> ... yields >> 10 >> 1 >> Is this guaranteed by the standard or is it compiler-dependent? Also i >> noticed for dummy variables the lower index bound is by default shifted >> to 1, even for array pointer actual argument, unless the dummy variable >> is a pointer array, then the lower bound is retained. At least on my >> compiler. >> Is there some golden rule or thought behind all this that I fail to see? > Yes, there is. On pointer assignment, the bounds of the pointer are > determined as if LBOUND and UBOUND were applied to the target. > Thus, pointer assignment to a whole array variable inherits its lower > bounds, whereas assigment to a subobject gets the bounds of the > subobject, and every subobject has the default lower bounds, i.e. 1. > You can find more here: > http://en.wikipedia.org/wiki/Fortran_language_features#Pointers_as_dy...
Ok, sounds like there is some rationality here after all. Another thing I noticed is that I can "shift" an array pointer with a simple function. Is there some kind of intrinsic that does this? If not - why not? I would like to avoid implementing one such function for each element type and for different array ranks ... FUNCTION SHIFT(X,I) RESULT(Z) INTEGER, POINTER :: Z(:) INTEGER, INTENT(IN) :: I INTEGER, POINTER :: X(:) Z => SET_LB(X,LBOUND(X,1)+I) END FUNCTION SHIFT FUNCTION SET_LB(Y,J) RESULT(Z) INTEGER, POINTER :: Z(:) INTEGER, INTENT(IN) :: J INTEGER, TARGET :: Y(J:) Z => Y END FUNCTION SET_LB
On May 25, 2:33 pm, Kurt <nob@nowhere.org> wrote:
> highegg wrote: > > On May 25, 9:49 am, Kurt <nob @nowhere.org> wrote: > >> I'm confused by the rules for lower array index bound. In some > >> situations the index bound is retained, in other it is "shifted" so that > >> the lower bound becomes 1. > >> By experiment I noticed that if A(:) and B(:) are array pointers then e.g. > >> ALLOCATE(B(10:20)) > >> A => B > >> WRITE(*,*) LBOUND(A,1) > >> A => B(10:20) > >> WRITE(*,*) LBOUND(A,1) > >> ... yields > >> 10 > >> 1 > >> Is this guaranteed by the standard or is it compiler-dependent? Also i > >> noticed for dummy variables the lower index bound is by default shifted > >> to 1, even for array pointer actual argument, unless the dummy variable > >> is a pointer array, then the lower bound is retained. At least on my > >> compiler. > >> Is there some golden rule or thought behind all this that I fail to see? > > Yes, there is. On pointer assignment, the bounds of the pointer are > > determined as if LBOUND and UBOUND were applied to the target. > > Thus, pointer assignment to a whole array variable inherits its lower > > bounds, whereas assigment to a subobject gets the bounds of the > > subobject, and every subobject has the default lower bounds, i.e. 1. > > You can find more here: > >http://en.wikipedia.org/wiki/Fortran_language_features#Pointers_as_dy... > Ok, sounds like there is some rationality here after all. > Another thing I noticed is that I can "shift" an array pointer with a > simple function. Is there some kind of intrinsic that does this? If not > - why not? I would like to avoid implementing one such function for each > element type and for different array ranks ... > FUNCTION SHIFT(X,I) RESULT(Z) > INTEGER, POINTER :: Z(:) > INTEGER, INTENT(IN) :: I > INTEGER, POINTER :: X(:) > Z => SET_LB(X,LBOUND(X,1)+I) > END FUNCTION SHIFT > FUNCTION SET_LB(Y,J) RESULT(Z) > INTEGER, POINTER :: Z(:) > INTEGER, INTENT(IN) :: J > INTEGER, TARGET :: Y(J:) > Z => Y > END FUNCTION SET_LB
Yes, some time ago I discovered this trick, too, and put it to the Wikipedia article I hyperlinked above. It seems the only F95 way to assign a pointer to a non-ALLOCATEd target with custom bounds. In F2003, you can directly specify lower bounds for the pointer: Z(LBOUND(X,1)+I:) => X I am missing the feature in F95, too, but there is a way, even standard-conforming, although clumsy, so I can live with it.
highegg wrote: > On May 25, 2:33 pm, Kurt <nob @nowhere.org> wrote: >> highegg wrote: >>> On May 25, 9:49 am, Kurt <nob @nowhere.org> wrote: >>>> I'm confused by the rules for lower array index bound. In some >>>> situations the index bound is retained, in other it is "shifted" so that >>>> the lower bound becomes 1. >>>> By experiment I noticed that if A(:) and B(:) are array pointers then e.g. >>>> ALLOCATE(B(10:20)) >>>> A => B >>>> WRITE(*,*) LBOUND(A,1) >>>> A => B(10:20) >>>> WRITE(*,*) LBOUND(A,1) >>>> ... yields >>>> 10 >>>> 1 >>>> Is this guaranteed by the standard or is it compiler-dependent? Also i >>>> noticed for dummy variables the lower index bound is by default shifted >>>> to 1, even for array pointer actual argument, unless the dummy variable >>>> is a pointer array, then the lower bound is retained. At least on my >>>> compiler. >>>> Is there some golden rule or thought behind all this that I fail to see? >>> Yes, there is. On pointer assignment, the bounds of the pointer are >>> determined as if LBOUND and UBOUND were applied to the target. >>> Thus, pointer assignment to a whole array variable inherits its lower >>> bounds, whereas assigment to a subobject gets the bounds of the >>> subobject, and every subobject has the default lower bounds, i.e. 1. >>> You can find more here: >>> http://en.wikipedia.org/wiki/Fortran_language_features#Pointers_as_dy... >> Ok, sounds like there is some rationality here after all. >> Another thing I noticed is that I can "shift" an array pointer with a >> simple function. Is there some kind of intrinsic that does this? If not >> - why not? I would like to avoid implementing one such function for each >> element type and for different array ranks ... >> FUNCTION SHIFT(X,I) RESULT(Z) >> INTEGER, POINTER :: Z(:) >> INTEGER, INTENT(IN) :: I >> INTEGER, POINTER :: X(:) >> Z => SET_LB(X,LBOUND(X,1)+I) >> END FUNCTION SHIFT >> FUNCTION SET_LB(Y,J) RESULT(Z) >> INTEGER, POINTER :: Z(:) >> INTEGER, INTENT(IN) :: J >> INTEGER, TARGET :: Y(J:) >> Z => Y >> END FUNCTION SET_LB > Yes, some time ago I discovered this trick, too, and put > it to the Wikipedia article I hyperlinked above. > It seems the only F95 way to assign a pointer to a non-ALLOCATEd > target with custom bounds. > In F2003, you can directly specify lower bounds for the pointer: > Z(LBOUND(X,1)+I:) => X > I am missing the feature in F95, too, but there is a way, even > standard-conforming, although clumsy, so I can live with it.
Thanks for responding again. I agree, nice to see it's in F2003. But do you know if it's standard conforming to ALLOCATE an array pointer, shift the index range as above, and then DEALLOCATE the shifted array? It seems to work with my compiler ...
On May 25, 3:58 pm, Kurt <nob@nowhere.org> wrote:
> highegg wrote: > > On May 25, 2:33 pm, Kurt <nob @nowhere.org> wrote: > >> highegg wrote: > >>> On May 25, 9:49 am, Kurt <nob @nowhere.org> wrote: > >>>> I'm confused by the rules for lower array index bound. In some > >>>> situations the index bound is retained, in other it is "shifted" so that > >>>> the lower bound becomes 1. > >>>> By experiment I noticed that if A(:) and B(:) are array pointers then e.g. > >>>> ALLOCATE(B(10:20)) > >>>> A => B > >>>> WRITE(*,*) LBOUND(A,1) > >>>> A => B(10:20) > >>>> WRITE(*,*) LBOUND(A,1) > >>>> ... yields > >>>> 10 > >>>> 1 > >>>> Is this guaranteed by the standard or is it compiler-dependent? Also i > >>>> noticed for dummy variables the lower index bound is by default shifted > >>>> to 1, even for array pointer actual argument, unless the dummy variable > >>>> is a pointer array, then the lower bound is retained. At least on my > >>>> compiler. > >>>> Is there some golden rule or thought behind all this that I fail to see? > >>> Yes, there is. On pointer assignment, the bounds of the pointer are > >>> determined as if LBOUND and UBOUND were applied to the target. > >>> Thus, pointer assignment to a whole array variable inherits its lower > >>> bounds, whereas assigment to a subobject gets the bounds of the > >>> subobject, and every subobject has the default lower bounds, i.e. 1. > >>> You can find more here: > >>> http://en.wikipedia.org/wiki/Fortran_language_features#Pointers_as_dy... > >> Ok, sounds like there is some rationality here after all. > >> Another thing I noticed is that I can "shift" an array pointer with a > >> simple function. Is there some kind of intrinsic that does this? If not > >> - why not? I would like to avoid implementing one such function for each > >> element type and for different array ranks ... > >> FUNCTION SHIFT(X,I) RESULT(Z) > >> INTEGER, POINTER :: Z(:) > >> INTEGER, INTENT(IN) :: I > >> INTEGER, POINTER :: X(:) > >> Z => SET_LB(X,LBOUND(X,1)+I) > >> END FUNCTION SHIFT > >> FUNCTION SET_LB(Y,J) RESULT(Z) > >> INTEGER, POINTER :: Z(:) > >> INTEGER, INTENT(IN) :: J > >> INTEGER, TARGET :: Y(J:) > >> Z => Y > >> END FUNCTION SET_LB > > Yes, some time ago I discovered this trick, too, and put > > it to the Wikipedia article I hyperlinked above. > > It seems the only F95 way to assign a pointer to a non-ALLOCATEd > > target with custom bounds. > > In F2003, you can directly specify lower bounds for the pointer: > > Z(LBOUND(X,1)+I:) => X > > I am missing the feature in F95, too, but there is a way, even > > standard-conforming, although clumsy, so I can live with it. > Thanks for responding again. I agree, nice to see it's in F2003. > But do you know if it's standard conforming to ALLOCATE an array > pointer, shift the index range as above, and then DEALLOCATE the shifted > array? > It seems to work with my compiler ...
I think so. The array object created by pointer allocation can be deallocated through any pointer that points to the same (entire) object.
Arjen Markus wrote: > On 25 mei, 10:12, highegg <high @gmail.com> wrote: >> On May 25, 9:49 am, Kurt <nob @nowhere.org> wrote: >>> I'm confused by the rules for lower array index bound. In some >>> situations the index bound is retained, in other it is "shifted" so that >>> the lower bound becomes 1. >>> By experiment I noticed that if A(:) and B(:) are array pointers then e.g. >>> ALLOCATE(B(10:20)) >>> A => B >>> WRITE(*,*) LBOUND(A,1) >>> A => B(10:20) >>> WRITE(*,*) LBOUND(A,1) >>> ... yields >>> 10 >>> 1 >>> Is this guaranteed by the standard or is it compiler-dependent? Also i >>> noticed for dummy variables the lower index bound is by default shifted >>> to 1, even for array pointer actual argument, unless the dummy variable >>> is a pointer array, then the lower bound is retained. At least on my >>> compiler. >>> Is there some golden rule or thought behind all this that I fail to see? >> Yes, there is. On pointer assignment, the bounds of the pointer are >> determined as if LBOUND and UBOUND were applied to the target. >> Thus, pointer assignment to a whole array variable inherits its lower >> bounds, whereas assigment to a subobject gets the bounds of the >> subobject, and every subobject has the default lower bounds, i.e. 1. >> You can find more here:http://en.wikipedia.org/wiki/Fortran_language_features#Pointers_as_dy... > Note that similar problems occur if you pass an array like B(10:20) to > a > subroutine: > subroutine mysub( b ) > real, dimension(:) :: b > write(*,*) lbound(b) > end subroutine > The lbound in the subroutine is 1, regardless of the lbound of the > actual argument. > I can think of a rationale for this behaviour (not sure if that is > correct, though): in this way subroutines and functions do not need > to take care of non-default lower bounds, by far the most common > case. If you need a different lower bound, then you can pass it > as an explicit argument: > subroutine mysub2( b, lower ) > integer :: lower > real, dimension(lower:) :: b > write(*,*) lbound(b) > end subroutine > Regards, > Arjen
The reason that you're confused is that you're concentrating on what looks like a simple case and ignoring the related hard cases. Remember, subscripts in arrays don't have to be simple. What should the lower bound for P be after something like P => ARRAY(12:2:-3) 12, 3, and 2 all look equally obvious (to me ;) ). Similarly for a CALL, what should the lower bound be for CALL SUB( ARRAY(1:5) + ARRAY(6:2:-1) ) again, no obvious answer. I think the standard consistently says that a whole array has it's declared bounds. Any expression or section of an array acts as if the bounds were declared to be 1:extent. That means that ARRAY and ARRAY(:) have different bounds. Maybe it would be possible to treat those two cases the same way, but then what would people want or expect for ARRAY(I:J:K)? Should that be special cased when I is equal to the lower declared bound, J to the declared upper bound, and K to 1? Or worse, ARRAY( VECTOR ) when VECTOR happens to span the declared bounds in order. The current rules, whole array OR not, for determining bounds is sometimes counter-intuitive (at least until you get comfortable with it) but it covers all of the cases in a regular way with no strange edge cases. Dick Hendrickson
Dick Hendrickson wrote:
(snip) > I think the standard consistently says that a whole array has > it's declared bounds. Any expression or section of an array acts > as if the bounds were declared to be 1:extent. That means that > ARRAY and ARRAY(:) have different bounds. Maybe it would be possible > to treat those two cases the same way, but then what would people > want or expect for ARRAY(I:J:K)? Should that be special cased when > I is equal to the lower declared bound, J to the declared upper > bound, and K to 1? Or worse, ARRAY( VECTOR ) when VECTOR happens > to span the declared bounds in order.
PL/I does consistently keep the lower bound to arrays, including as subroutine arguments. PL/I does not have the I:J:K form, so that problem doesn't come up. It does have *, for an array cross section. An expression like SUM(A(I,*) * B(*,J)) multiplies row I of A by column J of B and subs the result. They must have the same lower and upper bound. > The current rules, whole array OR not, for determining bounds is > sometimes counter-intuitive (at least until you get comfortable > with it) but it covers all of the cases in a regular way with no > strange edge cases.
PL/I does more general cases using the DEFINED attribute. Similar to EQUIVALENCE, a DEFINED array shares storage with another array, but isn't required to map contiguous storage. DCL (A(10,10), B(10) DEFINED A(1SUB,1SUB)) FLOAT(10); B contains the diagonal elements of A. -- glen
glen herrmannsfeldt wrote:
... > PL/I does consistently keep the lower bound to arrays, including > as subroutine arguments. PL/I does not have the I:J:K form, > so that problem doesn't come up. It does have *, for an > array cross section. An expression like SUM(A(I,*) * B(*,J)) > multiplies row I of A by column J of B and subs the result. > They must have the same lower and upper bound.
I'd forgot that PL/I had that. But you have failed to mention (except obliquely) another difference. You say that A and B must have the same lower and upper bound - but Fortran's equivalent requires only that they be conformable (the same rank and the same extent in each corresponding dimention). In Fortran, the *bounds* can be completely different. This rule about conformability means that the fact that expression results and array sections have a lower bound of one (regardless of the bounds of the operands) is less often significant - or even noticed. Without the rule of conformability, operating on sections would be nearly implossible. -- J. Giles "I conclude that there are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies and the other way is to make it so complicated that there are no obvious deficiencies." -- C. A. R. Hoare
James Giles wrote: > glen herrmannsfeldt wrote: >>PL/I does consistently keep the lower bound to arrays, including >>as subroutine arguments. PL/I does not have the I:J:K form, >>so that problem doesn't come up. It does have *, for an >>array cross section. An expression like SUM(A(I,*) * B(*,J)) >>multiplies row I of A by column J of B and subs the result. >>They must have the same lower and upper bound. > I'd forgot that PL/I had that. But you have failed to mention > (except obliquely) another difference. You say that A and > B must have the same lower and upper bound - but Fortran's > equivalent requires only that they be conformable (the same > rank and the same extent in each corresponding dimention). > In Fortran, the *bounds* can be completely different.
Previous posts mentioned how Fortran array sections work. I did say that it seemed more consistent. Yes, it doesn't do all the cases that Fortran can do. > This rule about conformability means that the fact that expression > results and array sections have a lower bound of one (regardless > of the bounds of the operands) is less often significant - or even > noticed. Without the rule of conformability, operating on > sections would be nearly implossible.
I would expect in the most common cases that it would work. In the general case, one can always use DO loops. As someone else pointed out, for more complex expressions DO loops are probably faster, anyway. PL/I is probably better at generating temporary arrays than Fortran. Another difference from Fortran is in mixed array/scalar expressions. A=A*A(10); The effects of a change to A(10) are applied to subsequent elements, where Fortran specifically says that the effects is as if the whole multiply is done before the assignment. Maybe in this case Fortran is more likely to generate a temporary array. -- glen
|
 |
 |
 |
 |
|