QBasic & Numerical Recipes

Computer Methods in Chemical Engineering


Calling Numerical Recipes routines can be tricky. We need to make sure that the parameters are passed correctly to the subroutines/functions. Numerical Recipes makes the matters worse because of the poor programming. For example, in the GAUSSJ routine, the parameter mp is not the leading dimension of B -- it is the second dimension of B -- and is not needed. Because Numerical Recipes uses real numbers as matrix/vector indices (which is a sloppy programming practice as index variables should be integers), be sure to declare dimensions with real numbers. Actually Numerical Recipes is not the only one to blame. Bill Gates and his QBasic does not make clear distinction of real numbers and integers, which comes back to haunt you poor students. Now is the payback time for being sloppy. Below we show some examples that work and some examples that are no good. To make matters even worse, the buggy program runs and yields results, but they are wrong and highly unpredictable. They happen without any warning -- no complaints of syntax errors from compilers or linkers nor any indication during run-time!!! And you may not be aware that the answers are wrong unless you test them thoroughly.

With "DECLARE SUB"

The following declares the subroutine. It always works because the declaration specifies that parameters are to be passed as real numbers irrespective of how they are defined originally -- Recommended, whether or not the subroutine codes appear in the same file or not.
      DECLARE SUB gaussj(a!(), n!, np!, b!(), m!, mp!)
      const n=3             ' n is treated as an integer
      dim A(n,n), b(n,1)
        :
      call GAUSSJ(A(), n, n, b(), 1, 1)
The rest of the codes for an example of A*x=b are in: The following has a one-dimensional array b(n) rather than a two-dimensional array b(n,1). It is o.k., because the leading dimension of b is passed correctly.
      DECLARE SUB gaussj(a!(), n!, np!, b!(), m!, mp!)
      const n=3!            ' n is treated as a real number
      dim A(n,n), b(n)
        :
      call GAUSSJ(A(), n, n, b(), 1, 1)
Likewise, the following is o.k., because the period "." forces n to be a real number
      DECLARE SUB gaussj(a!(), n!, np!, b!(), m!, mp!)
      const n=3.            ' n is treated as a real number
      dim A(n,n), b(n)
        :
      call GAUSSJ(A(), n, n, b(), 1, 1)
The following is no good, because the leading dimension of b (i.e., the constant "n") is messed up, in spite of the declaration of SUB and what type of arguments the subroutine should take. Moral: DECLARE alone cannot ensure that the variable types match, even though DECLARE was meant to catch type mismatch.
      DECLARE SUB gaussj(a!(), n!, np!, b!(), m!, mp!)
      const n=3             ' n is treated as an integer
      dim A(n,n), b(n)
        :
      call GAUSSJ(A(), n, n, b(), 1, 1)
Likewise, the following is no good, because it has the same problem with "n" as the last example, although the "1!" part has been fixed.
      DECLARE SUB gaussj(a!(), n!, np!, b!(), m!, mp!)
      const n=3             ' n is treated as an integer
      dim A(n,n), b(n)
        :
      call GAUSSJ(A(), n, n, b(), 1!, 1!)
The one below is o.k. because the problem with "n" is fixed.
      DECLARE SUB gaussj(a!(), n!, np!, b!(), m!, mp!)
      n=3                   ' n is treated as a real variable by default
      dim A(n,n), b(n)
        :
      call GAUSSJ(A(), n, n, b(), 1!, 1!)

Without "DECLARE SUB"

Without declaration of the subroutine, we need to make sure that real numbers are passed to the subroutine.

The following is o.k., because all the arguments are real

      const n=3!            ' n is treated as a real number
      dim A(n,n), b(n)
        :
      call GAUSSJ(A(), n, n, b(), 1!, 1!)
The following is also o.k.
      n=3                   ' n is treated as a real variable by default
      dim A(n,n), b(n)
        :
      call GAUSSJ(A(), n, n, b(), 1!, 1!)
The following is also o.k.
      n=3.                  ' n is treated as a real variable by default
      dim A(n,n), b(n)
        :
      call GAUSSJ(A(), n, n, b(), 1., 1.)
The following is no good because n is treated as an integer
      const n=3             ' n is treated as an integer
      dim A(n,n), b(n)
        :
      call GAUSSJ(A(), n, n, b(), 1!, 1!)
The following is no good because 1 is treated as an integer
      n=3                   ' n is treated as a real variable by default
      dim A(n,n), b(n)
        :
      call GAUSSJ(A(), n, n, b(), 1, 1)


There are more permutations that are not listed above, but I think we have had enough. It is easy to get confused after all these different permutations. The bottom line is that you want to distinguish clearly what is an integer and what is a real number.


Return to Prof. Nam Sun Wang's Home Page
Return to Computer Methods in Chemical Engineering (ENCH250)

Computer Methods in Chemical Engineering -- QBasic and Numerical Recipes
Forward comments to:
Nam Sun Wang
Department of Chemical & Biomolecular Engineering
University of Maryland
College Park, MD 20742-2111
301-405-1910 (voice)
301-314-9126 (FAX)
e-mail: nsw@umd.edu ©1996-2006 by Nam Sun Wang
UMCP logo