Функция с массивом

Я новичок в области программирования на Фортране, и после тестирования нескольких программ я уже понял, как писать программы. Сейчас я пробовал себя в более сложной программе и столкнулся с проблемой, которую не смог решить самостоятельно. Я уже гуглил об этой проблеме, но не смог найти адекватного ответа... Поэтому я подумал, может быть, есть один или два программиста на Фортране, которые могут помочь мне в решении этой проблемы.

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

program matrixMul
implicit none
integer, parameter :: ikind=selected_int_kind(18)
integer(kind=ikind), allocatable, dimension(:,:) :: m1, m2, result, mulMatrix
integer :: rows, cols, i, j

print *, 'Please enter the number of rows the matrix should have: '
read *, rows

print *, 'Please enter the number of columns the matrix should have: '
read *, cols

!allocate sufficient memory
allocate(m1(rows, cols), m2(cols, rows))

!fill matrixes with numbers entered by the user
call fillMatrix(m1, rows, cols)
call fillMatrix(m2, cols, rows)

result = mulMatrix(m1, m2, rows, cols)

!prints the result matrix to the screen
call printMatrix(result, rows, cols)

!deallocate memory
deallocate(m1, m2, mulMatrix, result)
end program matrixMul

Где функция, которая выполняет фактическое умножение, выглядит так:

function mulMatrix(m1, m2, r, c) result(mulMat)
implicit none
integer, parameter :: ikind=selected_int_kind(18)
integer(kind=ikind), dimension(r, c) :: m1
integer(kind=ikind), dimension(c, r) :: m2
integer(kind=ikind), allocatable, dimension(:,:) :: mulMat
integer r, c, i, j, k

allocate(mulMat(r,r))

!code which performs calculation is omitted

end function mulMatrix

Мой компилятор сообщает о следующей ошибке:

Ошибка: индекс массива в (1) является массивом ранга 2

Мне кажется, что компилятор будет рассматривать переменную mulMatrix как обычный массив и поэтому жалуется на нее, потому что я использую ее, поскольку она будет иметь четыре измерения, что не так. Но как заставить компилятор думать об этой переменной как о вызове функции с четырьмя параметрами, а не как о доступе к массиву? Любая помощь будет оценена.


person tzwickl    schedule 20.03.2014    source источник
comment
Удаление объявления массива mulMatrix из основной программы и определение функции внутри модуля решит вашу проблему. Размещение любых внешних процедур (функций и подпрограмм) в модулях и доступ к ним через use somemodule обеспечивает явный интерфейс и позволяет компиляторам проверять несоответствие типов аргументов, конфликты имен и т. д.   -  person milancurcic    schedule 20.03.2014
comment
Аналогично предыдущему комментарию. Пример: stackoverflow.com/questions/6511711/. Кроме того, при желании вы можете опустить аргументы r и c, объявить m1 и m2 с помощью dimension(:,:), определяющих размерности в функции с помощью встроенного size.   -  person M. S. B.    schedule 20.03.2014
comment
Я упомяну встроенный matmul на тот случай, если вы еще с ним не сталкивались.   -  person High Performance Mark    schedule 20.03.2014


Ответы (1)


Как уже упоминалось IRO-bot, используйте module. Это будет очень хорошей практикой, так как вы изучаете новый язык. С модулем вам просто нужно будет использовать модуль вместо того, чтобы объявлять функции по отдельности. Также рекомендуется не использовать ключевые слова в качестве имен переменных (пример: результат), использовать что-то другое. Я полагал, что вы хорошо понимаете трюк с возвратом выделяемых массивов в качестве возвращаемого значения функции, введенный в fortran 2003.

Ваша программа может выглядеть так, (функции содержатся в файле программы, а не в отдельном модуле, результат тот же)

program matrixMul
implicit none
integer, parameter :: ikind=selected_int_kind(18)
integer(kind=ikind), allocatable, dimension(:,:) :: m1, m2, m3
integer :: rows, cols, i, j

    print *, 'Please enter the number of rows the matrix should have: '
    read *, rows

    print *, 'Please enter the number of columns the matrix should have: '
    read *, cols

    !allocate sufficient memory
    allocate(m1(rows, cols), m2(cols, rows))

    !fill matrixes with numbers entered by the user
    call fillMatrix(m1, rows, cols)
    call fillMatrix(m2, cols, rows)
    m1 = 1
    m2 = 1

    m3 = mulMatrix(m1, m2, rows, cols)

    !prints the result matrix to the screen
    call printMatrix(m3, rows, cols)

    !deallocate memory
    deallocate(m1, m2, m3)

contains
    function mulMatrix(m1, m2, r, c) result(mulMat)
    implicit none
            integer, parameter :: ikind=selected_int_kind(18)
            integer(kind=ikind), dimension(r, c) :: m1
            integer(kind=ikind), dimension(c, r) :: m2
            integer(kind=ikind), allocatable, dimension(:,:) :: mulMat
            integer r, c, i, j, k

            allocate(mulMat(r,r))

            !code which performs calculation is omitted

    end function mulMatrix
end program matrixMul

Другое мнение: если вы выполняете умножение матриц, как определено в линейной алгебре, результирующая матрица будет строками x строками, см. вызов для печати результата. Икра будет заключаться в том, чтобы не добавлять размер матриц в качестве параметров (см. комментарий M.S.B.) и использовать встроенные функции LBOUND и UBOUND или SIZE, чтобы получить их в функции.

person innoSPG    schedule 20.03.2014