Создавать объекты-обертки для де-свертывания ужасного кода на Фортране?

Я должен поработать над неким устаревшим Fortran, хотя я могу использовать самые последние компиляторы.

Код хранит огромное количество данных в одномерных массивах.

Например,

PROGRAM horrible_coding
IMPLICIT EVERYTHING ! Sarcasm

REAL, DIMENSION(1000) :: data
INTEGER, DIMENSION(50)   :: info_location

! Somewhere, info is read in and stored temporarily as info_1, info_2, etc.

data(1:3) = info_1
data(4:9) = info_2
...
data(134:192) = info_n

Связь между элементами в DATA массив идти с какими частями info хранится во втором массиве. Что-то вроде:

info_location(1) = 1
info_location(2) = 4
info_location(n) = 134

Вот так. Значение каждого элемента info_location Массив относится к первому элементу массива данных, где вы можете найти соответствующую информацию.

Так, например, если вы хотите получить данные для info_7, вам нужно сделать следующее:

size_of_info_7 = info_location(8) - info_location(7)
ALLOCATE(data_for_info_7(size_of_info_7))
data_for_info_7 = data(info_location(7) : info_location(7) + size_of_info_7 - 1)

К настоящему времени вид этого безумия, возможно, заставил кровь начать стрелять из твоих глаз, поэтому я прошу прощения.

Я хотел бы создать экземпляры объекта и сохранить все соответствующие данные для каждой части информации в качестве данных экземпляра. И пока я переношу вещи в 2003, я бы создал методы экземпляров для получения и установки данных экземпляров.

Я не хочу переписывать код, но хочу поставить эту модернизацию поверх того, что уже есть.

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

Это разумная вещь?

Могу ли я создать в Фортране объекты, данные экземпляров которых преимущественно являются указателями?

Я не решаюсь начать эту задачу, не разбрасывая идею стекпотока.

2 ответа

Решение

Могу ли я создать в Фортране объекты, данные экземпляров которых преимущественно являются указателями?

Я не уверен, что вы имеете в виду, но вы определенно можете сделать что-то вроде:

type data_ptr
  real,dimension(:),pointer :: data
end type

И вы также можете сделать массивы этих типов:

type(data_ptr),dimension(:),allocatable :: some_name

(может быть указательным или статическим, как вы хотите.)

Затем, если исходные данные TARGETатрибут, вы можете использовать:

some_name(i)%data => data(lower:upper)

Вы также можете переназначить указатель на разные нижние границы, процесс выше дает ему нижнюю границу 1.

Я нахожу код, который вы опубликовали, немного запутанным. Я ожидаю, что вы знаете, что линии

data(1:3) :: info_1
data(4:9) :: info_2
...
data(134:192) :: info_n

не являются синтаксически действительными Fortran (любого поколения). Я думаю, что я могу истолковать то, что вы пытаетесь сказать нам, но не хотел бы давать советы, основанные на (неправильной) интерпретации. Кроме того, вы бросаете объекты, такие как info_1, info_2 в смесь без уточнения их определения и декларации. Я не уверен, действительно ли info_1 это то же самое, что info_location(1),

Если я понимаю, что вы опубликовали, у вас есть довольно распространенная (в старом коде Фортрана) конструкция, в которой массив данных фиксированного размера (условно называемый data здесь), который используется для хранения коллекции предметов. Затем у вас есть индексный массив (называется info_location) который содержит индексы в данные в начале каждого элемента. Очень странно, что этот индексный массив имеет тип REAL, я ожидаю, что он будет INTEGER, чтобы вы могли писать такие выражения, как:

data(info(3):info(4)-1))

Это, конечно, не заставляет мои глазные яблоки кровоточить, возможно, я слишком долго программировал на Фортране, но это выглядит совершенно разумным для меня! Один вариант, который вы должны рассмотреть, это разыграть info_location интегрировать как-то и использовать это как индексный массив. Или, вы можете делать такие приведения, как и когда это необходимо, написав такие строки:

data(int(info(3)):int(info(4))-1))

Лично я бы сделал массив индексов INTEGER, REAL - неправильный тип для индексов массива.

Затем вы пишете

Так, например, если вы хотите получить данные для info_7, вам нужно сделать следующее:

size_of_info_7 = info_location(8) - info_location(7)
ALLOCATE(data_for_info_7(size_of_info_7))
data_for_info_7 = data(info_location(7) : info_location(7) + size_of_info_7 - 1)

Поскольку вы не уточнили, что именно info_7 или же data_for_info_7 Я немного смущен этим. Если вы используете неявную типизацию, то size_of_info_7 будет REAL, и ваш оператор ALLOCATE завершится неудачно, требуя INTEGER для размера выделенного объекта.

Я предполагаю, что data_for_info_7 это, вероятно, размещаемый массив REAL. Если info_location были типа INTEGER вы могли бы просто написать:

ALLOCATE(data_for_info_7, source = data(info_location(7) : info_location(8) - 1))

Владимир Ф уже дал совет по использованию указателей для очистки вашего кода. Другой подход заключается в использовании конструкции ASSOCIATE. Вы можете написать в соответствующих точках вашего кода что-то вроде:

ASSOCIATE(data_for_info_7 => data(info_location(7) : info_location(8) - 1))

сопоставляя это с END ASSOCIATE заявление в нужном месте. Это эффективно определяет псевдоним для секции массива в конструкции ASSOCIATE.

Итак, округлим:

  1. Тип info_location массив неверен.
  2. Оставляя это в стороне от оригинального проекта с массивом данных и другим массивом индексов, (безусловно, было) вполне разумно.
  3. У вас есть несколько вариантов обновления кода, включая указатели и ассоциации.
Другие вопросы по тегам