Функция Fortran, возвращающая выделяемый массив с нетривиальными границами

Что касается объекта, я изо всех сил пытаюсь понять логику функций, возвращающих выделяемые массивы. Мне нравится эта конструкция из-за ее ясности по сравнению с подпрограммами, а также из-за того, что чистые функции на фортране — отличный способ написать чистый, функциональный программный код.

Предположим, мне нужно написать простую функцию, возвращающую массив индексов с произвольными границами, как в этой программе:

program test_allocatable_functionReturn
      implicit none

      integer, allocatable :: fun(:),sub(:),noa(:)
      integer, parameter :: low = -4
      integer, parameter :: hi  = 3

      call testsub(sub,low,hi)
      fun = testfun(low,hi)
      noa = testfun_noalloc(low,hi)

      print '(4(a,i3),a)', 'testsub:  lbound=',lbound(sub),'(expected = ',low,'), ubound=',ubound(sub),'(expected = ',hi,')'
      print '(4(a,i3),a)', 'testfun:  lbound=',lbound(fun),'(expected = ',low,'), ubound=',ubound(fun),'(expected = ',hi,')'
      print '(4(a,i3),a)', 'no alloc: lbound=',lbound(noa),'(expected = ',low,'), ubound=',ubound(noa),'(expected = ',hi,')'


      contains
             pure function testfun_noalloc(low,hi) result(array)
                integer, intent(in) :: low,hi
                integer :: array(low:hi)
                integer :: i
                 forall(i=low:hi) array(i) = i
             end function testfun_noalloc


             pure function testfun(low,hi) result(array)
                integer, allocatable :: array(:)
                integer, intent(in) :: low,hi
                integer :: i
                 allocate(array(low:hi))
                 forall(i=low:hi) array(i) = i
             end function testfun


             pure subroutine testsub(array,low,hi)
                integer, intent(out), allocatable :: array(:)
                integer, intent(in) :: low,hi
                integer :: i
                 allocate(array(low:hi))
                 forall(i=low:hi) array(i) = i
             end subroutine testsub

end program

Я реализовал это тремя способами:

  • функция, возвращающая размещаемый массив (testfun)
  • подпрограмма (testsub)
  • функция, возвращающая статический массив (testfun_noalloc)

Подпрограмма работает с возвращаемым массивом и правильно распределяет его. В примере должен быть возвращен массив размером (-4:3). Функция в любой реализации возвращает массив размером (1:hi-low+1):

testsub:  lbound= -4(expected =  -4), ubound=  3(expected =   3)
testfun:  lbound=  1(expected =  -4), ubound=  8(expected =   3)
no alloc: lbound=  1(expected =  -4), ubound=  8(expected =   3)

Почему это происходит? Я понимаю, что fortran может перераспределить массив при присвоении возвращаемого значения функции моему массиву LHS, но даже в этом случае, почему он не выделяется с правильными границами? Я понимаю, что такое может произойти при передаче статического массива в выделяемый массив с перераспределением левой части в стиле f2003, но при использовании в качестве входного размещаемого массива я ожидал, что информация о границах будет сохранена. Я что-то упустил здесь? Кстати, этот пример был скомпилирован с помощью gfortran 9.2.0.

Спасибо, Федерико.


person Federico Perini    schedule 06.07.2020    source источник
comment
Как отмечено в ответах на связанные вопросы, нижняя граница выражения массива, а не целого массива, всегда равна 1, независимо от границ массива, используемого в этом выражении.   -  person francescalus    schedule 06.07.2020
comment
Получил спасибо - понимаю причины. Но, ИМХО, это делает работу с массивами размером со значение гораздо менее привлекательной....   -  person Federico Perini    schedule 07.07.2020