Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [General] оператор result 
V
    Опции темы
popovda
Дата 15.5.2007, 15:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 290
Регистрация: 9.6.2006
Где: Москва

Репутация: нет
Всего: 6



Интересует идеология работы Фортран-оператора result. Ведь подпрограмма (не ограничивая общности - функция) может возвращать массив двумя способами:
1. Через intent(out)
Код

integer function MyFunc1(b,res)
      real, dimension(:),intent(in) :: b;
      real, dimension(:),intent(out) :: res;
     .....................................
     res = AnyFunc_or_operation(b); ! Предопределенный массив
     .....................................
     MyFunc = 1;
end function MyFunc1;


2. С помощью оператора result
Код

function MyFunc2(b) result (res)
      real, dimension(:),intent(in) :: b;
      real, dimension(size(b)) :: res; ! Автоматический массив
     .....................................
     res = AnyFunc_or_operation(b);
     .....................................
end function MyFunc2;



Сдается мне, что второй способ предпочтительнее, т.к. идет из HPF и только он может 
использоваться в процедурах без побочного эффекта для возврата массива (pure procedures).
И ощущение такое, что в принципе они внутри устроены практически одинаково. То что во втором случае res - автоматический массив - несколько смущает, т.к. может возникнуть фрагментация памяти, хотя, с другой стороны, не будет же программист в одной и той же программе специально вызывать функцию с сильно различными размерами массива, а память для переменных функции выделяется, насколько я помню стандарт, при первом вызове и освобождается при завершении работы программы. И наверняка выделяется вполне приличными блоками.


--------------------
С уважением, Попов Д.А.
PM MAIL   Вверх
FatalError
Дата 15.5.2007, 21:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 92
Регистрация: 11.4.2006

Репутация: нет
Всего: 1



Я как-то не сталкивался с этим оператором на практике. Полез в хелп-файл для FTN-95, и обнаружил там совсем другое объяснение применения оператора RESULT:
Цитата

As an alternative to using the function name in assignment statements, a different name may be used if this name is added to the specification as illustrated here:

Код
REAL FUNCTION mod(x,y) RESULT(f)
REAL x,y
f=SQRT(x*x+y*y)
END FUNCTION mod


A function that either directly or indirectly calls itself must use RESULT and must be given the RECURSIVE attribute. For example:

Код
RECURSIVE INTEGER FUNCTION factorial(n) RESULT(f)
INTEGER n
IF(n==0)THEN
 f=1
ELSE
 f=factorial(n-1)
ENDIF
END FUNCTION factorial


В общем, с рекурсивными функциями все понятно. А в приводимом Вами примере мне вот совсем не ясно, как будет возвращаться массив. Автоматический массив создается при входе в функцию/процедуру и должен при выходе из нее разрушаться. Если только он не прописан с атрибутом SAVE. Без SAVE, мне кажется, данные просто потеряются. Да и то в них заглянуть можно будет только изнутри этой самой функции, если ее вызвать еще разок. Может, я не прав?
PM MAIL   Вверх
popovda
Дата 16.5.2007, 10:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 290
Регистрация: 9.6.2006
Где: Москва

Репутация: нет
Всего: 6



Автоматический массив разрушается при выполнении следующего за вызывающим функцию оператором. Посмотри этот код - значения из MyMatmul будут возвращены

Код

module MyMat
implicit none;
contains    
    function MyMatmul(A,B) result (C)
        real(8), dimension(:,:), intent(in) :: A,B;
        real(8), dimension(size(A,dim=1),size(B,dim=2)) :: C;
        
        C = matmul(A,B);
    end function MyMatmul;
end module MyMat;


program TestAutoArrays
use MyMat;
implicit none;

! Variables
real(8), dimension(1:5,1:4) :: A;
real(8), dimension(1:4,1:7) :: B;
real(8), dimension(1:5,1:7) :: C;

! Body of TestAutoArrays
A(:,1) = 1.0;
A(:,2) = 2.0;
A(:,3) = 3.0;
A(:,4) = 4.0;

B(1,:) = 10.0;
B(2,:) = 20.0;
B(3,:) = 30.0;
B(4,:) = 40.0;

C = matmul(A,B);

write(*,*) C;
C = 0.0;
write(*,*) "Use MyMatMul";
C = MyMatmul(A,B);
write(*,*) C;
read(*,*);
end program TestAutoArrays





--------------------
С уважением, Попов Д.А.
PM MAIL   Вверх
popovda
Дата 16.5.2007, 16:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 290
Регистрация: 9.6.2006
Где: Москва

Репутация: нет
Всего: 6



Пообщался на эту тему с Аллой Моисеевной Горелик. Выяснилось, что result - это не оператор, а суффикс при объявлении функции. Кроме того, будет фрагментация памяти или нет - зависит от реализации компилятора. Уже что-то.


--------------------
С уважением, Попов Д.А.
PM MAIL   Вверх
Cr@$h
Дата 17.1.2009, 16:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Исследователь
***


Профиль
Группа: Участник Клуба
Сообщений: 1693
Регистрация: 3.4.2005
Где: Санкт-Петербург, Россия

Репутация: 1
Всего: 41



Цитата(popovda @  15.5.2007,  16:08 Найти цитируемый пост)
Сдается мне, что второй способ предпочтительнее, т.к. идет из HPF и только он может 
использоваться в процедурах без побочного эффекта для возврата массива

Ну, процедуры-не-функции тоже могут быть чистыми, даже если будут меня больше одного параметра ;-)
Код

pure subroutine MySubRout1(b, res)
      real, dimension(:),intent(in) :: b;
      real, dimension(:),intent(out) :: res;
     .....................................
     res = AnyFunc_or_operation(b); ! Предопределенный массив
     .....................................
end subroutine MySubRout1;

Цитата(popovda @  15.5.2007,  16:08 Найти цитируемый пост)
память для переменных функции выделяется, насколько я помню стандарт, при первом вызове и освобождается при завершении работы программы

Хм.. Возможно. Но одно дело память для ссылки, а другое дело память для массива у этой ссылки. Т.е. если возвращается массив неизвестной длины, то возвращается ссылка (да как и всегда), а выделение памяти будет каждый раз своё.
Цитата(FatalError @  15.5.2007,  22:27 Найти цитируемый пост)
Автоматический массив создается при входе в функцию/процедуру и должен при выходе из нее разрушаться. 

Это не совсем автоматический массив функции, это же сама функция. Проверь, например, когда используешь MatMul, памяти ведь нужно в два раза больше. Так и тут: массив функции живёт, пока результат функции не присвоится куда-нибудь или не перестанет использоваться.
Цитата(popovda @  16.5.2007,  17:35 Найти цитируемый пост)
Кроме того, будет фрагментация памяти или нет - зависит от реализации компилятора. 

При использовании многих функций, получается, что фрагментация памяти как бы будет. Да что там говорить, "вместо" процедур почти все встроенные подпрограммы являются функциями! И это то в божном Fotran! Казалось бы, зачем, почему.. Да потому что по-другому быть не может.
Казалось бы, здесь не будет выделений памяти вообще:
Код

call MatMul(MatrixA, MatrixB, ResultMatrix)

а тут -- может и быть:
Код

ResultMatrix = MatMul(MatrixA, MatrixB)

Но.. первый вариант не подходит для:
Код

call MatMul(MatrixA, MatrixB, MatrixA)

Цитата(FatalError @  15.5.2007,  22:27 Найти цитируемый пост)
Автоматический массив создается при входе в функцию/процедуру и должен при выходе из нее разрушаться. Если только он не прописан с атрибутом SAVE. Без SAVE, мне кажется, данные просто потеряются.

Но к массиву функции это не относится.

Интересно, что для рекурсии result обязателен. Это как бы переменная каждого экземпляра функции.

Добавлено через 10 минут и 57 секунд
А вообще, мораль такова. Если функция в конечном итоге присваивается к одному из своих аргументов, то выделения памяти не избежать.
Код

A = Func(A, B) ! Массивы

Но до чего обидно, если функция эта имеет такую природу:

Код

A = SumOfElements(A, B) ! = MaxAbsElements(A, B)

и т.п. Ведь компилятору будет очень сложно распознать. Ничего страшного, в том числе и для этого придумали элементные функции. И если тут выделение памяти будет:
Код

A = MatMul(A, B)

то тут -- не факт:
Код

A = Sin(A)

Думаю, разница улавливается прозрачно.

Нелишнее выделение памяти -- элемент искусства разработчиков компилятора.
Код

A = MatMul(A, B) + MatMul(B, C)

PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Fortran | Следующая тема »


 




[ Время генерации скрипта: 0.0442 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.