Правильное объявление массива Struc - PullRequest
0 голосов
/ 21 января 2019

Я пытаюсь перевести октавный код matlab / gnu в код языка gfortran.

Я сделал объявление о Struc для формирования массива, как написано в Matlab. Однако компилятор не будет обрабатывать команду SIZE из-за той проблемы с массивом, которую я не понимаю. Ниже код октавы, который я пытаюсь перевести

function test1
clc;
close all;
start= 5;
function out = function1(start)
myarray = struct(...
    'list1', {'A', 'Cc', 'B', 'E', 'F', 'G', 'H', 'I'}, ...
    'list2', {1, 2,  3,  4, 5, 6, 7, 8},...
    'list3', {3, 3, 3, 3, 3, 2, 2, 2});
function list1 = function2(list2)
    done = false;
    myarray    
    numel(myarray)
    ra = randi([1 numel(myarray)], 1, 1)
    myarray(ra).list2;

    list1 = myarray(ra);
    if list1.list1 == 'E'
        list1.list1 = round(randn(1,1) * 5);
    end
   end
  x = {}; 
  y = [];
  list2 = 0;    
    list1 = function2(list2);
    list2 = list2 + list1.list3;
  out = struct('x', {x}, 'y', {y});
 end
function1(5)
end

Вывод октавного кода,

test1

myarray =

1x8 struct array containing the fields:

list1
list2
list3

ans =  8
ra =  1
ans =

scalar structure containing the fields:

x = {}(0x0)
y = [](0x0) 

Мой код gfortran,

function function1(start) result(out1)

 type myarray
 character, dimension(8)::list1=(/'A','C','B','E','F','G','H','I'/); 
 integer, dimension(8)::list2 =(/1,2,3,4,5,6,7,8/); 
 integer, dimension(8)::list3 =(/3,3,3,3,3,2,2/);
  end type 

  integer :: start;
  integer :: out1;
  integer :: sd;

 contains

  function function2(list2) result(list1)

   integer, intent(in) :: list2; ! input
   integer :: list1;             ! output  
   logical :: done;  
   integer, dimension(1,1) :: ra;
   real    :: rnd1;

    done = .FALSE.


    call random_number(rnd1);
    ra = nint(rnd1*5);
    sd= size(myarray);
   ! ra = nint(rnd1*size(myarray));
       print*, "random number is ", ra;
     myarray(ra)

 end function function2

 end function function1

program test1
use iso_fortran_env
implicit none

integer                 :: start, xout;
real                    :: ra;
integer                 :: function1;

start =5;
xout=function1(5);
end program test1

Сообщение об ошибке, полученное командой build:

gfortran  -Ofast -Wall -o "test1" "test1.f90"  
test1.f90:32:16:
      myarray(ra).list2;
            1
Error: Derived type ‘myarray’ cannot be used as a variable at (1)
test1.f90:29:17:
     sd= size(myarray);
             1
Error: ‘array’ argument of ‘size’ intrinsic at (1) must be an array
Compilation failed.

Я считаю, что проблема заключается в моем объявлении структуры массива. Я что-то там упускаю. Какие-либо предложения? Обратите внимание, что в коде gfortran в значениях list1 мне пришлось изменить символ 'Cc' на 'C', чтобы он работал.

1 Ответ

0 голосов
/ 21 января 2019

В отличие от случая с Matlab, где struct создает объект с заданными значениями, оператор type в Fortran этого не делает.

Вместо этого type myarray определяет, как будет выглядеть объект,Ни один объект не создан, и нам нужно сделать что-то вроде

type myarray
   ...   ! The definition of components
end type myarray
type(myarray) obj ! Declare an object of the defined type.

. После этого obj будет вашим интересным объектом.

Однако есть еще кое-что, на что следует обратить внимание.С

type myarray
  character, dimension(8)::list1=(/'A','C','B','E','F','G','H','I'/); 
  integer, dimension(8)::list2 =(/1,2,3,4,5,6,7,8/); 
  integer, dimension(8)::list3 =(/3,3,3,3,3,2,2/);
end type 

вы (опять же) не создаете объект.Когда вы делаете создаете объект (используя type(myarray) obj, этот объект, вероятно, начинается с указанных значений. Однако это не совсем то, что вы можете ожидать от оператора Matlab struct.подробности об этом можно прочитать о инициализации по умолчанию * конструкторах и .

При достижении size(myarray) объект, объявленный исключительно как type(myarray) obj, является скаляром объект. Это разница между «массивами структур» и «структурами массивов». «Структура» myarray содержит три массива каждый длиной 8. Вместо этого имеется массив структур:

type myarray
  character list1
  integer list2, list3
end type myarray
type(myarray), dimension(8) :: array

Однако вам придется создать массив. Возможно,

array = [myarray('A',1,3), myarray('C',2,3), ...]

У других вопросов есть ответы, которые касаются деталей построения таких массивов структур.

...