2016-12-10 3 views
2

Я изо всех сил пытался найти какую-либо конкретную информацию при проектировании производного типа. Я думаю, что лучший способ обсудить это - это несколько вариантов. Я составил несколько разделов кода с различными приложениями производного типа. Я бы предпочел использовать динамические массивы для nparts, index и refs. Я пропустил разделы кода, который фактически использует структуру (нет, потому что я ее создал), но примеры показаны, и в обычной программе я намерен использовать все значения в структуре хотя бы один раз.Проектирование производного типа с элементами массива

Вариант A: Использование статических массивов в производном типе. Недостатком является то, что мне придется угадать размер массива во время компиляции.

! Known before compile time. 
nboxes = 5000 
max_parts = 2000 
packs = 10 

Type Boxes 
    Sequence 
    Integer :: location, date 
    Integer, Dimension(0:packs) :: nparts 
    Integer, Dimension(max_parts,packs) :: index 
    Real(Kind=8), Dimension(packs,packs) :: refs 
End Type Boxes 

type(boxes), dimension(:), allocatable :: assembly 
allocate(assembly(nboxes)) 

! Perform some operations on assembly... 
do i = 1,nboxes 
    do j = 1,packs 
     do k = j,packs 
     example = assembly(i)%nparts(k) - assembly(i)%nparts(j) 
     . 
     . 
     do m = 1,max_parts 
      example = assembly(i)%index(m,j) + assembly(i)%refs(k,j) * assembly(i)%nparts(j) 
      . 
      . 
     end do 
     end do 
    end do 
end do 

Вариант B: Использовать динамические массивы в производном типе.

! Defined during execution. Much better. 
nboxes = 5000 
max_parts = 2000 
packs = 10 

Type Boxes 
    Sequence 
    Integer :: location, date 
    Integer, Dimension(:), Allocatable :: nparts 
    Integer, Dimension(:,:), Allocatable :: index 
    Real(Kind=8), Dimension(:,:), Allocatable :: refs 
End Type Boxes 

type(boxes), dimension(:), allocatable :: assembly 
allocate(assembly(nboxes)) 
do i = 1,nboxes 
    allocate(assembly(i)%nparts(0:packs)) 
    allocate(assembly(i)%index(max_parts,packs)) 
    allocate(assembly(i)%refs(packs,packs)) 
end do 

! Perform some operations on assembly... 
do i = 1,nboxes 
    do j = 1,packs 
     do k = j,packs 
     example = assembly(i)%nparts(k) - assembly(i)%nparts(j) 
     . 
     . 
     do m = 1,max_parts 
      example = assembly(i)%index(m,j) + assembly(i)%refs(k,j) * assembly(i)%nparts(j) 
      . 
      . 
     end do 
     end do 
    end do 
end do 

Вариант C: минимизировать количество динамических массивов, используемых в производном типе и силы, чтобы стать assembly массив. Обратите внимание, что в этой версии у нас есть куча неиспользуемой памяти. Например, nparts и index требуется память packs - с assembly(packs,packs,nboxes).

! Defined during execution. Much better. 
nboxes = 5000 
max_parts = 2000 
packs = 10 

Type Boxes 
    Sequence 
    Integer :: location, date, nparts, index 
    Real(Kind=8) :: refs 
    Integer, Dimension(:), Allocatable :: index 
End Type Boxes 

type(boxes), dimension(:,:,:), allocatable :: assembly 
allocate(assembly(packs,packs,nboxes)) 
do i = 1,nboxes 
    do j = 1,packs 
     do k = 1,packs 
     allocate(assembly(k,j,i)%index(max_parts)) 
     end do 
    end do 
end do 

! Perform some operations on assembly... 
do i = 1,nboxes 
    do j = 1,packs 
     do k = j,packs 
     example = assembly(k,j,i)%nparts - assembly(k,j,i)%nparts 
     . 
     do m = 1,max_parts 
      example = assembly(k,j,i)%index(m) + assembly(k,j,i)%refs * assembly(k,j,i)%nparts 
      . 
      . 
     end do 
     end do 
    end do 
end do 

Вариант D: Еще одна перестановка Вариант C.

Вопросы:

  1. Какой вариант правильный/ожидается, метод проектирования производного типа, например, do петли показали? Какая версия наиболее оптимизирована, учитывая, что мне нужны возможности динамического массива?
  2. Возможно, связано с выше. Как выделена и доступна память? Возможно ли использование SEQUENCE? Я думаю, что выделенные массивы не появятся в последовательности в любом случае. Разве этот пункт не был бы лучшим вариантом, поскольку каждый раздел из assembly меньше?
  3. Должен ли я разделить этот производный тип на несколько производных типов или вообще избавиться от него и просто придерживаться переменных? Я буду использовать этот производный тип в нескольких процедурах и поместил бы его в модуль.
+0

Поддерживает ли ваш компилятор параметризованные производные типы? – francescalus

+0

Это правда, хотя я не знаком с концепцией и приложением. Так что мой разум еще не поддерживает его. :) – Higgy

+1

'kind = 8' действительно уродливый, избегайте волшебных констант! Это не означает 8 байтов! По крайней мере, не во всех компиляторах. –

ответ

2
  1. Вы хотите быстро изменяя индекс, чтобы быть вашим внутренний цикл. Самый быстрый переменный индекс является первым в многомерном массиве. Таким образом, вариант B близок к этой цели. Хотя вы можете изменить порядок размеров в ссылках.

  2. Схема памяти для двумерного массива формы (M, N), доступ к которой осуществляется с помощью индексов (I, J) определяется по следующей упорядоченности: k = i+m*(j-1), где k обозначает одномерную индекс в памяти. Выведенный тип данных будет содержать ссылку на выделенную память, и фактическая память содержащихся в ней allocatables может быть разбросана по всей памяти, но каждый распределяемый массив сам по себе является смежным. Таким образом, в вашем варианте B assembly будет непрерывным массивом, содержащим ссылки на выделяемые массивы.Каждый из nparts, index и refs был бы смежными массивами сам по себе, но они могут быть расположены в произвольных местах без какого-либо конкретного отношения внутри одного элемента сборки или через разные элементы сборки. Использование SEQUENCE здесь не имеет никакого смысла, оно вынуждает компилятор помещать элементы производного типа данных в память в порядке, в котором вы указываете, и запретит ему переустанавливать компоненты типа данных, поскольку он считает нужным , что может ограничить производительность. Я сомневаюсь, что это принесло бы большие эффекты в вашем примере, но когда это не нужно, вы должны оставить его.

  3. Нет, вариант B выглядит вполне разумным, на мой взгляд (за исключением sequence).

+0

1. Ой, недосмотр с моей стороны. Я редактировал код в вопросе, чтобы это было правильно. 2. Помогает ли «ПОСЛЕДОВАТЕЛЬНОСТЬ» в варианте «А» с точки зрения оптимизации? У меня создалось впечатление, что наличие этой информации, расположенной рядом с памятью, улучшит скорость вычислений внутри петель. Было бы еще лучше использовать производный тип, где память смежна для каждого цикла и выделяется? Например, вариант Option C, где 'index' больше не является массивом в производном типе. – Higgy

+1

@Higgy, какую информацию вы имеете в виду в отношении 'SEQUENCE'? С точки зрения производительности в основном это плохая идея поместить ее в производные типы данных. Как я уже сказал, это заставляет компилятор использовать заказ, который вы налагаете. Таким образом, у него меньше вариантов оптимизации. Вы хотите иметь массивы, вот где Fortran светит, и я считаю, что вариант B дает вам лучший вариант. Вероятно, вариант с улучшенной производительностью A будет еще лучше, но вы сказали, что хотите использовать динамическое распределение памяти. Вариации C хуже, чем A и B, на мой взгляд. – haraldkl

+0

Очень хорошо. Это очищает меня. Есть ли причина, по которой «SEQUENCE» будет полезной? – Higgy

Смежные вопросы