SORTC Subroutine

public subroutine SORTC(X, Y, N, Xs, Yc)

NAME

sortc(3f) - [M_datapac:SORT] sort a vector of sample
observations and "carry" a second vector

SYNOPSIS

 Subroutine sortc(X,Y,N,Xs,Yc)

   Real(kind=wp), Intent (In)    :: X
   Real(kind=wp), Intent (In)    :: Y
   Integer, Intent (In) :: N
   Real(kind=wp), Intent (Out)   :: Xs
   Real(kind=wp), Intent (Out)   :: Yc

DESCRIPTION

SORTC(3f) sorts (in ascending order) the N elements of the vector X,
puts the resulting N sorted values into the vector XS,
rearranges the elements of the vector Y (according to the sort on X),
and puts the rearranged Y values into the vector YC.
This subroutine gives the data analyst the ability to sort one data
vector while 'carrying along' the elements of a second data vector.

The smallest element of the vector X will be placed in the first
position of the vector XS, the second smallest element in the vector
X will be placed in the second position of the vector XS, etc.

The element in the vector Y corresponding to the smallest element in
X will be placed in the first position of the vector YC, the element
in the vector Y corresponding to the second smallest element in X
will be placed in the second position of the vector YC, etc.

The input vector X remains unaltered.

If the analyst desires a sort 'in place', this is done by having the
same output vector as input vector in the calling sequence. Thus,
for example, the calling sequence CALL SORTC(X,Y,N,X,YC) is allowable
and will result in the desired 'in-place' sort.

The sorting algorithm used herein is the binary sort. This algorithm
is extremely fast as the following time trials indicate. These time
trials were carried out on the UNIVAC 1108 EXEC 8 system at NBS in
August of 1974. By way of comparison, the time trial values for the
easy-to-program but extremely inefficient bubble sort algorithm have
also been included--

  Number of Random        Binary Sort       Bubble Sort
  Numbers Sorted
    N = 10                 .002 sec          .002 sec
    N = 100                .011 sec          .045 sec
    N = 1000               .141 sec         4.332 sec
    N = 3000               .476 sec        37.683 sec
    N = 10000             1.887 sec      NOT COMPUTED

INPUT ARGUMENTS

  X   The vector of observations to be sorted.

  Y   The vector of
      observations to be 'carried along', that is, to be rearranged
      according to the sort on X.

  N   The integer number of observations in the vector X.

OUTPUT ARGUMENTS

  XS  The vector into which the sorted data values from X will be
      placed in ascending order.

  YC  The vector into which the rearranged (according to the sort of
      the vector X) values of the vector Y will be placed.

EXAMPLES

Sample program:

program demo_sortc
use M_datapac, only : sortc, label
implicit none
integer,parameter            :: isz=20
real                         :: aa(isz)
real                         :: bb(isz)
real                         :: cc(isz)
real                         :: dd(isz)
integer                      :: i
  call label('sortc')
  write(*,*)'initializing array with ',isz,' random numbers'
  call random_seed()
  CALL RANDOM_NUMBER(aa)
  aa=aa*450000.0
  bb=real([(i,i=1,isz)])
  call sortc(aa,bb,size(aa),cc,dd)

  write(*,*)'checking if real values are sorted(3f)'
  do i=1,isz-1
     if(cc(i).gt.cc(i+1))then
        write(*,*)'Error in sorting reals small to large ',i,cc(i),cc(i+1)
     endif
  enddo
  write(*,*)'test of sortc(3f) complete'
  write(*,'(4(g0,1x))')(aa(i),bb(i),cc(i),dd(i),i=1,isz)
  write(*,'(*(g0,1x))')sum(aa),sum(cc) ! should be the same if no truncation
  write(*,'(*(g0,1x))')sum(bb),sum(dd)

end program demo_sortc

Results:

AUTHOR

The original DATAPAC library was written by James Filliben of the Statistical
Engineering Division, National Institute of Standards and Technology.

MAINTAINER

John Urban, 2022.05.31

REFERENCES

  1. CACM MARCH 1969, page 186 (BINARY SORT ALGORITHM BY RICHARD C. SINGLETON).
  2. CACM JANUARY 1970, page 54.
  3. CACM OCTOBER 1970, page 624.
  4. JACM JANUARY 1961, page 41.

LICENSE

CC0-1.0

Arguments

Type IntentOptional Attributes Name
real(kind=wp) :: X(:)
real(kind=wp) :: Y(:)
integer :: N
real(kind=wp) :: Xs(:)
real(kind=wp) :: Yc(:)

Source Code

SUBROUTINE SORTC(X,Y,N,Xs,Yc)

REAL(kind=wp) :: amed, bmed, hold, tx, ty, X(:), Xs(:), Y(:), Yc(:)
INTEGER i, il(36), ip1, iu(36), j, jmi, jmk, k, l, lmi, m, mid, N, nm1
!
!     RESTRICTIONS--THE DIMENSIONS OF THE VECTORS IL AND IU
!                   (DEFINED AND USED INTERNALLY WITHIN
!                   THIS SUBROUTINE) DICTATE THE MAXIMUM
!                   ALLOWABLE VALUE OF N FOR THIS SUBROUTINE.
!                   IF IL AND IU EACH HAVE DIMENSION K,
!                   THEN N MAY NOT EXCEED 2**(K+1) - 1.
!                   FOR THIS SUBROUTINE AS WRITTEN, THE DIMENSIONS
!                   OF IL AND IU HAVE BEEN SET TO 36,
!                   THUS THE MAXIMUM ALLOWABLE VALUE OF N IS
!                   APPROXIMATELY 137 BILLION.
!                   SINCE THIS EXCEEDS THE MAXIMUM ALLOWABLE
!                   VALUE FOR AN INTEGER VARIABLE IN MANY COMPUTERS,
!                   AND SINCE A SORT OF 137 BILLION ELEMENTS
!                   IS PRESENTLY IMPRACTICAL AND UNLIKELY,
!                   THEN THERE IS NO PRACTICAL RESTRICTION
!                   ON THE MAXIMUM VALUE OF N FOR THIS SUBROUTINE.
!                   (IN LIGHT OF THE ABOVE, NO CHECK OF THE
!                   UPPER LIMIT OF N HAS BEEN INCORPORATED
!                   INTO THIS SUBROUTINE.)
!---------------------------------------------------------------------
!     CHECK THE INPUT ARGUMENTS FOR ERRORS
!
   IF ( N<1 ) THEN
      WRITE (G_IO,99001)
      99001 FORMAT (' ','***** FATAL ERROR--The second input argument to SORTC(3f)  is non-positive *****')
      WRITE (G_IO,99002) N
      99002 FORMAT (' ','***** The value of the argument is ',I0,' *****')
      RETURN
   ELSE
      IF ( N==1 ) THEN
         WRITE (G_IO,99003)
         99003 FORMAT (' ','***** NON-FATAL DIAGNOSTIC--The second input argument to SORTC(3f) has the value 1 *****')
         Xs(1) = X(1)
         Yc(1) = Y(1)
         RETURN
      ELSE
         hold = X(1)
         DO i = 2 , N
            IF ( X(i)/=hold ) GOTO 50
         ENDDO
         WRITE (G_IO,99004) hold
          99004       FORMAT (' ',                                                &
          & '***** NON-FATAL DIAGNOSTIC--The first input argument (a vector) to SORTC(3f) has all elements =', &
          & E15.8, &
          & ' *****')
         DO i = 1 , N
            Xs(i) = X(i)
            Yc(i) = Y(i)
         ENDDO
         RETURN
      ENDIF
!
!-----START POINT-----------------------------------------------------
!
!  COPY THE VECTOR X INTO THE VECTOR XS
 50      continue
         DO i = 1 , N
            Xs(i) = X(i)
         ENDDO
!
!     COPY THE VECTOR Y INTO THE VECTOR YS
!
         DO i = 1 , N
            Yc(i) = Y(i)
         ENDDO
!
!     CHECK TO SEE IF THE INPUT VECTOR IS ALREADY SORTED
!
         nm1 = N - 1
         DO i = 1 , nm1
            ip1 = i + 1
            IF ( Xs(i)>Xs(ip1) ) GOTO 100
         ENDDO
         RETURN
      ENDIF
 100  continue
      m = 1
      i = 1
      j = N
 200  continue
      IF ( i>=j ) GOTO 400
 300  continue
      k = i
      mid = (i+j)/2
      amed = Xs(mid)
      bmed = Yc(mid)
      IF ( Xs(i)>amed ) THEN
         Xs(mid) = Xs(i)
         Yc(mid) = Yc(i)
         Xs(i) = amed
         Yc(i) = bmed
         amed = Xs(mid)
         bmed = Yc(mid)
      ENDIF
      l = j
      IF ( Xs(j)<amed ) THEN
         Xs(mid) = Xs(j)
         Yc(mid) = Yc(j)
         Xs(j) = amed
         Yc(j) = bmed
         amed = Xs(mid)
         bmed = Yc(mid)
         IF ( Xs(i)>amed ) THEN
            Xs(mid) = Xs(i)
            Yc(mid) = Yc(i)
            Xs(i) = amed
            Yc(i) = bmed
            amed = Xs(mid)
            bmed = Yc(mid)
         ENDIF
      ENDIF
      DO
         l = l - 1
         IF ( Xs(l)<=amed ) THEN
            tx = Xs(l)
            ty = Yc(l)
            DO
               k = k + 1
               IF ( Xs(k)>=amed ) THEN
                  IF ( k<=l ) THEN
                     Xs(l) = Xs(k)
                     Yc(l) = Yc(k)
                     Xs(k) = tx
                     Yc(k) = ty
                     EXIT
                  ELSE
                     lmi = l - i
                     jmk = j - k
                     IF ( lmi<=jmk ) THEN
                        il(m) = k
                        iu(m) = j
                        j = l
                        m = m + 1
                     ELSE
                        il(m) = i
                        iu(m) = l
                        i = k
                        m = m + 1
                     ENDIF
                     GOTO 500
                  ENDIF
               ENDIF
            ENDDO
         ENDIF
      ENDDO
 400  continue
      m = m - 1
      IF ( m==0 ) RETURN
      i = il(m)
      j = iu(m)
 500  continue
      jmi = j - i
      IF ( jmi>=11 ) GOTO 300
      IF ( i==1 ) GOTO 200
      i = i - 1
      DO
         i = i + 1
         IF ( i==j ) GOTO 400
         amed = Xs(i+1)
         bmed = Yc(i+1)
         IF ( Xs(i)>amed ) THEN
            k = i
            DO
               Xs(k+1) = Xs(k)
               Yc(k+1) = Yc(k)
               k = k - 1
               IF ( amed>=Xs(k) ) THEN
                  Xs(k+1) = amed
                  Yc(k+1) = bmed
                  EXIT
               ENDIF
            ENDDO
         ENDIF
      ENDDO
END SUBROUTINE SORTC