Бесконечный цикл Fortran при вызове функции

Почему я в бесконечном цикле?

PROGRAM tayls
  USE kertoma
  USE tforexp
  IMPLICIT NONE
  INTEGER :: n= 5
  INTEGER :: i
  REAL :: x
  WRITE(*,*) "f1(x)= (e**x-1)/x"
  DO i=1,10
    x= 0.01*i
    WRITE(*,*)x, (taylexp(x,n)-1)/x
  END DO
END PROGRAM tayls

с участием

MODULE tforexp
  USE kertoma
  IMPLICIT NONE
    CONTAINS
      FUNCTION taylexp(x,ord)
        REAL :: taylexp, x, sum
        INTEGER :: ord, i
        sum= 1.0
        DO i=1,ord
          sum= sum+ x**i/fact(i)
        END DO
        taylexp= sum
      END FUNCTION taylexp
END MODULE tforexp

а также

MODULE kertoma
  IMPLICIT NONE
CONTAINS
  FUNCTION fact(n)
    INTEGER :: fact,n,y=1
    DO WHILE (n>1)
      y= y*n
      n= n-1
    END DO
    fact = y
  END FUNCTION fact
END MODULE kertoma

Бесконечный цикл начинается сразу после первого вывода "f1(x)=...". Поэтому я думаю, что при первом вызове функции taylexp происходит бесконечный цикл, но я не понимаю, почему. Я думаю, что это как-то связано с фортраном, использующим общедоступные переменные, но я не знаю, как последовательно избегать этого. Сначала я попытался вызвать функцию без определения x, просто используя «0.01*i», и я подумал, что, возможно, проблема в том, что эта функция использует то же имя для фиктивного индекса, но это явно не решает проблему.


person swirld    schedule 20.01.2015    source источник
comment
Я понятия не имею, в этом ли проблема, но обратите внимание, что integer :: y=1 возможно не делает то, что вы думаете.   -  person francescalus    schedule 21.01.2015
comment
Где используется taylerr? Зачем тогда в посте?   -  person John Alexiou    schedule 25.01.2015


Ответы (2)


Проблема внутри, тогда функция fact(n):

n= n-1

изменяет аргумент и, следовательно, счетчик цикла i в taylexp. В вашем коде i никогда не превышает 2. Я удивлен, что компилятор не выдал предупреждения (мой тоже), потому что в этом случае могло случиться что угодно.

Лучше указать intent фиктивных аргументов, чтобы избежать подобных проблем в будущем:

  FUNCTION fact(n)
    integer,intent(in)  :: n
    INTEGER :: fact,nn,y

    y=1 ! Avoid the implicit save and assign variables separately
    nn=n
    DO WHILE (nn>1)
      y= y*nn
      nn= nn-1
    END DO
    fact = y
  END FUNCTION fact
person Alexander Vogt    schedule 20.01.2015
comment
Или, возможно, даже integer, intent(in), value :: n и избегать nn. - person francescalus; 21.01.2015
comment
@francescalus Да, но я стараюсь решать одну проблему за раз ;-) (помимо неявного сохранения, которое должно быть запрещено в Стандарте) - person Alexander Vogt; 21.01.2015

С помощью gfortran эту ошибку можно отловить с помощью параметра -fcheck=all:

$ gfortran -fcheck=all 1.f90 
$ ./a.out
 f1(x)= (e**x-1)/x
At line 22 of file 1.f90
Fortran runtime error: Loop variable has been modified
person Community    schedule 24.01.2015