next up previous contents
Next: Linear Equation Solvers Up: Complete Example Programs Previous: Complete Example Programs

Rational Arithmetic

! File typical.1.f90

! The suffix .f90 permits the use of the new free source form available in 
! Fortran 90.

! A module is a new feature in Fortran 90.  Modules are primarily used to 
! declare data, subroutines, and functions that are accessible in more than
! one program unit.  Modules are a safe alternative to common in Fortran 77,
! and provide much more functionality by including more than just data.
! The data, subroutine, and function names in a module are made available 
! by using the module in the program unit using the USE statement together 
! with the module name.

! Case is not significant in Fortran 90. 

module TypicalModule
   integer, parameter :: N = 4     ! Declare an integer constant, N.
   integer, parameter :: M = 50    ! Declare an integer constant, M.

   private M   ! Make the integer constant visible only within this module.

   ! Define a derived type called rational that contains two integer 
   ! components, n and d.  Derived types are similar to records in Pascal
   ! or structures in C.  Individual components are accessed via the ``%''
   ! operator (see the rationalAdd function below).

   type rational
      integer n, d
   end type rational


   ! Every subroutine or function has an interface which indicates the name,
   ! the arguments, their types, attributes, and the type and attributes of
   ! the function (for a function).

   ! There are two types of interfaces in Fortran 90, implicit interfaces
   ! and explicit interfaces.  Implicit interfaces are used in Fortran 77
   ! external procedures and assume that a procedure call is correct in the 
   ! type and number of arguments passed.  Explicit interfaces, however, have
   ! the advantage that type-checking of actual and dummy arguments can be 
   ! performed for procedure calls.  Incorrect calls or invocations are
   ! detected by the compiler.

   ! Interfaces of subroutines and functions within a module are always
   ! explicit.  However, an interface block is needed to define a generic
   ! procedure name or operator and the set of procedures to which the name 
   ! applies.  The following interface block extends the binary ``+'' 
   ! operator.  Now, the function rationalAdd can be invoked using the
   ! binary operator ``+'' on two objects of type( rational ).

   interface operator (+)
      module procedure rationalAdd
   end interface 

   private gcd   ! Use the gcd function internal to this module only.


   ! The contains statement indicates the presence of one or more internal
   ! subprograms that are included in the module and is necessary to 
   ! separate the specification statements of the module from the
   ! subprogram definitions.

   contains 

   function rationalAdd( left, right )

      ! To declare a variable to be of some derived type, use the type 
      ! statement with the derived type's name in parenthesis.

      type( rational ) rationalAdd

      ! As in Fortran 77, parameter passing is by reference.  
      ! It may be necessary for the compiler to generate temporaries in
      ! some cases.  However, changes to these temporaries affect the actual
      ! argument.  Fortran 90 provides the intent attribute to further 
      ! specify and document a variable's use in the program.  Possible 
      ! intent specifications are in, out, and inout.  Variables violating
      ! their intent are caught by the compiler.

      type( rational ), intent(in) :: left, right

      integer k, m1, m2
      type( rational ) sum

      k = gcd( left%d, right%d )
      m1 = left%d / k
      m2 = right%d / k

      ! To assign a value to a variable of a derived type such as sum, use 
      ! a structure constructor as indicated below.  A structure constructor
      ! consists of the derived type name together with the value to be 
      ! assigned to each component of the derived type, in the order 
      ! declared in the specification of the derived type.  (A derived type 
      ! may also be assigned by assigning values to its individual 
      ! components.)

      sum = rational( left%n * m2 + right%n * m1, left%d * m2 )

      k = gcd( sum%n, sum%d )
      rationalAdd = rational( sum%n / k, sum%d / k )  ! Reduce the rational.
   end function rationalAdd


   ! Recursion is now permissible in Fortran 90.  The function gcd is 
   ! declared recursively below.

   ! If a function calls itself, either directly or indirectly, the
   ! keyword recursive must appear in the function statement.  Recursive
   ! functions must also declare a result clause to be used rather than the
   ! function name.  This requirement is to avoid ambiguity with
   ! array-valued functions that are directly recursive.  The result
   ! variable is used to hold the function result for each function 
   ! invocation; the function name is used to invoke the function itself.

   recursive function gcd( a, b ) result( divisor )

      ! Note that the function itself is not declared when the result
      ! variable is present.  The type of the function is the type of 
      ! the result variable.  Thus, only the result variable may be 
      ! declared. 

      integer divisor
      integer, intent(in) :: a, b

      integer m, n

      ! Multiple statements may be written on a single source line
      ! provided they are delimited with semicolons.

      m = abs(a); n = abs(b)
      if ( m > n ) call swap( m, n )  ! Insure that m <= n.

      ! When the function invokes itself recursively, the result variable
      ! should be used to store the result of the function.  The function
      ! name is used to invoke the function.  Thus, the function name should
      ! not appear on the left-hand side of an assignment statement.

      if ( m == 0 ) then 
         divisor = n
      else
         divisor = gcd( mod( n, m ), m )
      end if

      ! Unlike internal subprograms, module procedures, such as gcd, may 
      ! have internal subprograms defined within them (to one level only). 
      ! As with module procedures, internal subprograms also have an
      ! explicit interface.  Thus, the swap subroutine is not declared in 
      ! the gcd function above---its interface is explicit.


      contains

      ! The swap subroutine is internal to gcd and is not visible
      ! elsewhere, not even in this module.

      subroutine swap( x, y )
         integer, intent(inout) :: x, y

         integer tmp

         tmp = x; x = y; y = tmp 
      end subroutine swap

   end function gcd

end module TypicalModule





! The above module can be in a different source file than the program and 
! be compiled separately.  The explicit interfaces of the module procedures
! guarantee that the compiler will check the actual and dummy arguments, in
! both type and number, for each module procedure called in the program.

program Typical

   ! A module is accessed via the use statement.  With the use statement 
   ! below, all public names (names not declared private in the module) are
   ! available for use in the program.  Use statements must immediately 
   ! follow the program statement.  A program may use an unlimited 
   ! number of modules.

   use TypicalModule

   ! Note that a variable may be initialized at the time of declaration.

   type( rational ) :: a = rational( 1, 2 ), b = rational( 3, 4 ), c


   ! The derived type rational and its associated function, ``+'', may 
   ! now be used between a and b.

   c = a + b   ! This statement is equivalent to c = rationalAdd( a, b ).


   ! Input two rational numbers and output their sum.

   print *, 'Enter two rational numbers.'
   print *

   ! Nonadvancing output is possible using the advance specifier in the
   ! write statement.  This permits multiple write statements to output
   ! a continuing line of output.

   write( *, fmt = "(a)", advance = "no" ) 'Numerator of a   :  '
   read  *, a%n

   write( *, fmt = "(a)", advance = "no" ) 'Denominator of a :  '
   read  *, a%d

   write( *, fmt = "(a)", advance = "no" ) 'Numerator of b   :  '
   read  *, b%n

   write( *, fmt = "(a)", advance = "no" ) 'Denominator of b :  '
   read  *, b%d

   c = a + b

   print *
   print *, a%n, '/', a%d, '+', b%n, '/', b%d, '=', c%n, '/', c%d

end program Typical



next up previous contents
Next: Linear Equation Solvers Up: Complete Example Programs Previous: Complete Example Programs