2

Suppose I have the following piece of code in my Fortran program:

recursive function T_GreCoDi( n, m ) result (GCD)
  implicit none
  integer, intent(in) :: n, m
  integer :: GCD

  select case(n)
    case(0)
      select case(m)
        case(0)
          print *, 'both of your numbers are zeros. GCD = -1'
          GCD = -1
        case default
          GCD = m
      end select
    case(1)
      GCD = 1
    case default
      select case(m)
        case(0)
          GCD = n
        case(:n)!<--THIS IS PROBLEM
          GCD = T_GreCoDi(n-m, m)
        case default
          GCD = T_GreCoDi(m-n, n)
      end select
    end select
  end function T_GreCoDi

When compiled it causes the error:

Error: Parameter 'n' at (1) has not been declared or is a variable, which does not reduce to a constant expression

So my question: Is there a way to solve this ( I still want to use case-statement)?

It is easy to avoid this error just by using if-statement instead case-statement but I want to use case- for integrity of my code.

1
  • I have edited my question.
    – LRDPRDX
    Commented Jan 4, 2017 at 17:29

1 Answer 1

2

If I were writing this, I really wouldn't use a select case construct. I'll answer under the assumption that such is necessary as far as it goes, though.

The general answer is that with a case selector, whichever of the forms

  • (n)
  • (l:)
  • (l:u)
  • (:u)

it takes, each thing there (n, l or u) must be a scalar constant expression. That's just how Fortran says. This is why your compiler is complaining.

To retain the select case construct something will have to be rewritten. But what?

Let's look at the specific case here, and at the part

select case(n)
  case(0) ...
  case(1) ...
  case default     ! n is an integer not 0 or 1
    select case(m)
      case(0) ...
      case(****)   ! Something here for m<n and m.ne.0
        GCD = T_GreCoDi(n-m, m)
      case default
        GCD = T_GreCoDi(m-n, n)
    end select
  end select

There are two options here for m not 0. (:n) is selected if (non-zero) m is less than or equal to n. The (default) is selected if (non-zero) m is greater than n. But, the only difference between what is executed is in the function arguments. This leads to the natural if construct

      if (m<=n) then
        GCD = T_GreCoDi(n-m, m)
      else
        GCD = T_GreCoDi(m-n, n)
      end if

You don't want to do that. Is

      GCD = T_GreCoDi(ABS(n-m), MIN(m,n))

better?

select case(n)
  case(0)
    select case(m)
      case(0)
        print *, 'both of your numbers are zeros. GCD = -1'
        GCD = -1
      case default
        GCD = m
    end select
  case(1)
    GCD = 1
  case default
    select case(m)
      case(0)
        GCD = n
      case default
        GCD = T_GreCoDi(ABS(n-m), MIN(m,n))
    end select
  end select

Honestly, I think this confirms my suspicion that the case construct is not the way to go here.

1
  • What a shame. I did not think about ABS function. Thank you for the idea.
    – LRDPRDX
    Commented Jan 4, 2017 at 20:41

Not the answer you're looking for? Browse other questions tagged or ask your own question.