Computing the cross product of two vectors in Fortran 90

This is kind of a late answer, but since I stumbled upon this and there is no real explanation yet for why your error occurred, I figured I'd add an explanation for everybody else who stumbles upon this question:

In your program, you define an array called cross, which is of rank 1. Then you call the cross function you define further down. Since the cross function does not have an explicit interface (see M.S.B.'s answer), the compiler does not know about it at this point. What it does know about is the array you declared. If you write r = cross(m, n), the compiler thinks you want to access the element at position (m, n) of the array cross. Since this array is of rank 1, but you supplied two arguments, you get the error

rank mismatch in array reference at (1) (2/1)

which means that you supplied two coordinates when the compiler was expecting one.


You can place the subroutines used in a program after a contains keyword within the program. This eliminates the need for creating a module or adding the interface definition.

PROGRAM crosstest
  IMPLICIT NONE

  INTEGER, DIMENSION(3) :: m, n
  INTEGER, DIMENSION(3) :: cross
  INTEGER, DIMENSION(3) :: r

  m=(/1, 2, 3/)
  n=(/4, 5, 6/)
  r=cross(m,n)

  print *, r

CONTAINS

PURE FUNCTION cross(a, b)
  INTEGER, DIMENSION(3) :: cross
  INTEGER, DIMENSION(3), INTENT(IN) :: a, b

  cross(1) = a(2) * b(3) - a(3) * b(2)
  cross(2) = a(3) * b(1) - a(1) * b(3)
  cross(3) = a(1) * b(2) - a(2) * b(1)
END FUNCTION cross

END PROGRAM crosstest

The best practice is to place your procedures (subroutines and functions) in a module and then "use" that module from your main program or other procedures. You don't need to "use" the module from other procedures of the same module. This will make the interface of the procedure explicit so that the calling program or procedure "knows" the characteristics of the arguments ... it allows the compiler to check for consistency between the arguments on both sides ... caller and callee .. this eliminates a lot of bugs.

Outside of the language standard, but in practice necessary: if you use one file, place the module before the main program that uses it. Otherwise the compiler will be unaware of it. so:

module my_subs

implicit none

contains

FUNCTION cross(a, b)
  INTEGER, DIMENSION(3) :: cross
  INTEGER, DIMENSION(3), INTENT(IN) :: a, b

  cross(1) = a(2) * b(3) - a(3) * b(2)
  cross(2) = a(3) * b(1) - a(1) * b(3)
  cross(3) = a(1) * b(2) - a(2) * b(1)
END FUNCTION cross

end module my_subs


PROGRAM crosstest
  use my_subs
  IMPLICIT NONE

  INTEGER, DIMENSION(3) :: m, n
  INTEGER, DIMENSION(3) :: r

  m= [ 1, 2, 3 ]
  n= [ 4, 5, 6 ]
  r=cross(m,n)
  write (*, *) r

END PROGRAM crosstest