How to stop a subroutine and raise a flag?
Asked Answered
S

2

4

I am writing a program in Fortran 95 (to be compiled with with gfortran) containing a subroutine that performs a certain computation. As suggested in "Fortran 95/2003 for Scientists & Engineers" by S. J. Chapman, I am trying to stop the subroutine when an error is encountered and "throw"[1] an error flag that is "catch"ed[1] by the calling program, that will take all the necessary actions. Ideally, I am going for something like:

! Pseudo-code
PROGRAM my_prog
    integer :: error_flag
    CALL my_subr (<input_args>, <output_args>, error_flag)
    ! Also error_flag is an output: 0 -> everything OK, 1 -> error
    IF (error_flag /= 0) THEN
        WRITE (*,*) 'Error during execution of "my_subr"'
    ELSE
        ... do something ...
    END IF
END PROGRAM my_prog

How can I stop the subroutine and gracefully handle the errors?

Here is an example: the subroutine "division" takes an integer input value and iteratively divides it by a value that is the input value decremented by the number of steps-1. When such value reaches zero, a flag should be raised and the subroutine should be exited without performing the division by zero.

SUBROUTINE division (inval, outval, error_flag)
  IMPLICIT NONE

  INTEGER, INTENT(IN) :: inval
  REAL, INTENT(OUT) :: outval
  INTEGER, INTENT(OUT) :: error_flag ! 0 -> OK, 1 -> error

  INTEGER :: i
  REAL :: x

  error_flag = 0
  x = REAL(inval)
  DO i = 0, 10
     IF (inval-i == 0) error_flag = 1
     ! How can I gracefully exit now?
     x = x / REAL(inval-i)
  END DO

END SUBROUTINE division

PROGRAM my_prog
  IMPLICIT NONE
  REAL :: outval
  INTEGER :: error_flag
  CALL division (8, outval, error_flag)
  IF (error_flag == 1) THEN
     WRITE (*,*) 'Division by zero'
  ELSE
     WRITE (*,*) 'Output value:', outval
  END IF
END PROGRAM my_prog

Notes:

[1] I am borrowing (in a probably inappropriate way) C++'s jargon.

Stivers answered 7/8, 2015 at 9:15 Comment(6)
You use an error flag in your example. What more do you won't? Did you have a problem with that? Fortran is closer to C in this regard (C uses return values in a very similar way).Himmler
Inside the subroutine you would use the same logic as your calling program -- wrap the potentially troublesome code inside some logic to jump to the end of the routine without further ado when an error occurs.Virtuosic
@VladimirF: The problem is not in the above pseudo-code, but in the subroutine: let's say I have a loop and I encounter a division by zero. I would like to raise a flag before the division is performed, not to perform the division and immediately "exit" the subroutine. How can I do that?Stivers
You must check the value of the divisor in an if condition, set the return value and return. Where do you see a problem? Show an example of the actual code you have.Himmler
@VladimirF: I added an example. Please have a look.Stivers
@HighPerformanceMark: The problem is basically that I don't know how to stop a subroutine (how to return, if you want).Stivers
E
2

Seeing your example it seems that you are just missing the return statement:

  error_flag = 0
  x = REAL(inval)
  DO i = 0, 10
     IF (inval-i == 0) then
                         error_flag = 1
                         return
     END IF

     x = x / REAL(inval-i)
  END DO
Eades answered 7/8, 2015 at 9:58 Comment(1)
No, it is OK. Why? You can also have more exit statements, that advise is nonsense. At least if applied blindly.Himmler
V
2

One possibility would be to change

  DO i = 0, 10
     IF (inval-i == 0) error_flag = 1
     ! How can I gracefully exit now?
     x = x / REAL(inval-i)
  END DO

to

  DO i = 0, 10
     IF (inval-i == 0) THEN 
        error_flag = 1
        EXIT
     END IF
     ! Now you have gracefully exited
     x = x / REAL(inval-i)
  END DO
  ! Code to tidy up if the error flag was set

Here the EXIT statement exits the loop -- Vladimir's answer shows you how to use RETURN to exit the subroutine more immediately. Whichever approach you choose don't forget to assign to outval before leaving the subroutine.

Virtuosic answered 7/8, 2015 at 10:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.