Ввод / вывод в чистых процедурах Фортрана - PullRequest
7 голосов
/ 07 января 2012

Я пытаюсь включить проверку ошибок в чистую процедуру, которую я пишу. Я хотел бы что-то вроде:

pure real function func1(output_unit,a)
    implicit none
    integer :: a, output_unit

    if (a < 0) then
        write(output_unit,*) 'Error in function func1: argument must be a nonnegative integer. It is ', a
    else
    func1 = a/3

    endif
    return
end function func1

Однако чистым функциям не разрешено иметь операторы ввода-вывода для внешних файлов, поэтому я попытался передать номер единицы в функцию, например, output_unit = 6, который является выходом по умолчанию. Gfortran по-прежнему считает это незаконным. Это можно обойти? Можно ли сделать функцию производным типом (вместо встроенного типа real здесь), который выводит строку при возникновении ошибки?

Ответы [ 2 ]

3 голосов
/ 22 июня 2016

Вы не первый, у кого возникла эта проблема, и я рад сообщить, что этот недостаток в стандарте будет исправлен в Fortran 2015. Как указано в в этом документе (стр. 6, заголовок«Одобренные изменения в стандарте»), «должно быть снято ограничение на появление оператора error stop в процедуре pure» .

Стандарт Fortran 2008 включалerror stop утверждение в контексте некоторых новых возможностей параллельных вычислений.Он сигнализирует об ошибке и останавливает все процессы как можно скорее.В настоящее время ни stop, ни error stop операторы не разрешены в pure процедурах, потому что они явно не поточнобезопасны.На практике это неоправданно ограничивает случаи, когда возникает внутренняя ошибка.

В зависимости от вашего компилятора, вам, возможно, придется терпеливо ждать реализации.Я знаю, что Intel реализовал в своем компиляторе ifort.( "F2015: отменить ограничение на STOP и ERROR STOP в процедурах PURE / ELEMENTAL" )

альтернатива

Для альтернативного подхода вы можете посмотреть на этот вопрос , хотя в вашем случае это, вероятно, немного сложнее, так как вам нужно изменить ключевое слово do concurrent, а не просто pure.

(конец правильного ответа)

если грязные руки - вариант ...

Тем временем вы могли бы сделать что-нибудь жестокое, как

pure subroutine internal_error(error_msg)
    ! Try hard to produce a runtime error, regardless of compiler flags.
    ! This is useful in pure subprograms where you want to produce an error, 
    ! preferably with a traceback.
    ! 
    ! Though far from pretty, this solution contains all the ugliness in this 
    ! single subprogram.
    ! 
    ! TODO: replace with ERROR STOP when supported by compiler
    implicit none

    character(*), intent(in) :: error_msg

    integer, dimension(:), allocatable :: molested

    allocate(molested(2))
    allocate(molested(2))
    molested(3) = molested(4)
    molested(1) = -10
    molested(2) = sqrt(real(molested(1)))
    deallocate(molested)
    deallocate(molested)
    molested(3) = molested(-10)
end subroutine internal_error

Если кто-то спросит, вы не получите это от меня.

0 голосов
/ 09 января 2012

Я сам нашел ответ, подробный здесь . Он использует то, что считается «устаревшим», но все же делает трюк; это называется альтернативным возвратом. Напишите процедуру как подпрограмму, так как она не работает с функциями.

pure real subroutine procA(arg1)
    implicit none
    integer :: arg1

    if (arg < 0) then
        return 1 ! exit the function and go to the first label supplied
                 ! when function was called. Also return 2, 3 etc.
    else
        procA = ... ! whatever it should do under normal circumstances
    endif
endsubroutine procA

.... 

! later on, procedure is called
num = procA(a, *220)

220 write(6,*) 'Error with func1: you've probably supplied a negative argument'

Что, вероятно, было бы лучше, это то, что предложил eriktous - получить процедуру для возврата статуса, возможно, в виде логического значения или целого числа, и заставить программу проверять это значение каждый раз после вызова процедуры. Если все хорошо, продолжай. В противном случае выведите соответствующее сообщение об ошибке.

Комментарии приветствуются.

...