PROCEDURE hqr(VAR a: glnpnp; n: integer; VAR wr,wi: glnp);
(* Programs using routine HQR must define the type
TYPE
   glnpnp = ARRAY [1..np,1..np] OF real;
   glnp = ARRAY [1..np] OF real;
where 'np by np' is the physical dimension of the matrix whose
eigenvalues are to be found. *)
LABEL 2,3,4;
VAR
   nn,m,l,k,j,its,i,mmin: integer;
   z,y,x,w,v,u,t,s,r,q,p,anorm: real;
FUNCTION sign(a,b: real): real;
   BEGIN
      IF (b < 0.0) THEN sign := -abs(a) ELSE sign := abs(a)
   END;
FUNCTION min(a,b: integer): integer;
   BEGIN
      IF (a < b) THEN min := a ELSE min := b
   END;
BEGIN
   anorm := abs(a[1,1]);
   FOR i := 2 to n DO BEGIN
      FOR j := i-1 to n DO BEGIN
         anorm := anorm+abs(a[i,j])
      END
   END;
   nn := n;
   t := 0.0;
   WHILE (nn >= 1) DO BEGIN
      its := 0;
2:      FOR l := nn DOWNTO 2 DO BEGIN
         s := abs(a[l-1,l-1])+abs(a[l,l]);
         IF (s = 0.0) THEN s := anorm;
         IF ((abs(a[l,l-1])+s) = s) THEN GOTO 3
      END;
      l := 1;
3:      x := a[nn,nn];
      IF (l = nn) THEN BEGIN
         wr[nn] := x+t;
         wi[nn] := 0.0;
         nn := nn-1
      END ELSE BEGIN
         y := a[nn-1,nn-1];
         w := a[nn,nn-1]*a[nn-1,nn];
         IF (l = nn-1) THEN BEGIN
            p := 0.5*(y-x);
            q := sqr(p)+w;
            z := sqrt(abs(q));
            x := x+t;
            IF (q >= 0.0) THEN BEGIN
               z := p+sign(z,p);
               wr[nn] := x+z;
               wr[nn-1] := wr[nn];
               IF (z <> 0.0) THEN wr[nn] := x-w/z;
               wi[nn] := 0.0;
               wi[nn-1] := 0.0
            END ELSE BEGIN
               wr[nn] := x+p;
               wr[nn-1] := wr[nn];
               wi[nn] := z;
               wi[nn-1] := -z
            END;
            nn := nn-2
         END ELSE BEGIN
            IF (its = 30) THEN BEGIN
               writeln('pause in routine HQR');
               writeln('too many iterations'); readln
            END;
            IF ((its = 10) OR (its = 20)) THEN BEGIN
               t := t+x;
               FOR i := 1 to nn DO BEGIN
                  a[i,i] := a[i,i]-x
               END;
               s := abs(a[nn,nn-1])+abs(a[nn-1,nn-2]);
               x := 0.75*s;
               y := x;
               w := -0.4375*sqr(s)
            END;
            its := its+1;
            FOR m := nn-2 DOWNTO l DO BEGIN
               z := a[m,m];
               r := x-z;
               s := y-z;
               p := (r*s-w)/a[m+1,m]+a[m,m+1];
               q := a[m+1,m+1]-z-r-s;
               r := a[m+2,m+1];
               s := abs(p)+abs(q)+abs(r);
               p := p/s;
               q := q/s;
               r := r/s;
               IF (m = l) THEN GOTO 4;
               u := abs(a[m,m-1])*(abs(q)+abs(r));
               v := abs(p)*(abs(a[m-1,m-1])+abs(z)
                     +abs(a[m+1,m+1]));
               IF ((u+v) = v) THEN GOTO 4
            END;
4:            FOR i := m+2 to nn DO BEGIN
               a[i,i-2] := 0.0;
               IF  (i <> (m+2)) THEN a[i,i-3] := 0.0
            END;
            FOR k := m to nn-1 DO BEGIN
               IF (k <> m) THEN BEGIN
                  p := a[k,k-1];
                  q := a[k+1,k-1];
                  r := 0.0;
                  IF (k <> (nn-1)) THEN
                     r := a[k+2,k-1];
                  x := abs(p)+abs(q)+abs(r);
                  IF (x <> 0.0) THEN BEGIN
                     p := p/x;
                     q := q/x;
                     r := r/x
                  END
               END;
               s := sign(sqrt(sqr(p)+sqr(q)+sqr(r)),p);
               IF (s <> 0.0) THEN BEGIN
                  IF (k = m) THEN BEGIN
                     IF (l <> m) THEN
                       a[k,k-1] := -a[k,k-1];
                  END ELSE BEGIN
                     a[k,k-1] := -s*x
                  END;
                  p := p+s;
                  x := p/s;
                  y := q/s;
                  z := r/s;
                  q := q/p;
                  r := r/p;
                  FOR j := k to nn DO BEGIN
                     p := a[k,j]+q*a[k+1,j];
                     IF (k <> (nn-1)) THEN BEGIN
                        p := p+r*a[k+2,j];
                        a[k+2,j] := a[k+2,j]-p*z
                     END;
                     a[k+1,j] := a[k+1,j]-p*y;
                     a[k,j] := a[k,j]-p*x
                  END;
                  mmin := min(nn,k+3);
                  FOR i := l to mmin DO BEGIN
                     p := x*a[i,k]+y*a[i,k+1];
                     IF (k <> (nn-1)) THEN BEGIN
                        p := p+z*a[i,k+2];
                        a[i,k+2] := a[i,k+2]-p*r
                     END;
                     a[i,k+1] := a[i,k+1]-p*q;
                     a[i,k] := a[i,k]-p
                  END
               END
            END;
            GOTO 2
         END
      END
   END
END;
PROCEDURE hunt(xx: glnarray; n: integer;
      x: real; VAR jlo: integer);
(* Programs using routine HUNT must define the type
TYPE
   glnarray = ARRAY [1..n] OF real;
in the main routine. *)
LABEL 1,2,3,4;
VAR
   jm,jhi,inc: integer;
   ascnd: boolean;
BEGIN
   ascnd := xx[n] > xx[1];
   IF ((jlo <= 0) OR (jlo > n)) THEN BEGIN
      jlo := 0;
      jhi := n+1;
      GOTO 3
   END;
   inc := 1;
   IF ((x >= xx[jlo]) = ascnd ) THEN BEGIN
1:      jhi := jlo+inc;
      IF (jhi > n) THEN BEGIN
         jhi := n+1
      END ELSE IF ((x >= xx[jhi]) = ascnd ) THEN BEGIN
         jlo := jhi;
         inc := inc+inc;
         GOTO 1
      END
   END ELSE BEGIN
      jhi := jlo;
2:      jlo := jhi-inc;
      IF (jlo < 1) THEN BEGIN
         jlo := 0
      END ELSE IF ((x < xx[jlo]) = ascnd ) THEN BEGIN
         jhi := jlo;
         inc := inc+inc;
         GOTO 2
      END
   END;
3:   IF ((jhi-jlo) = 1) THEN GOTO 4;
   jm := (jhi+jlo) DIV 2;
   IF ((x > xx[jm]) = ascnd ) THEN BEGIN
      jlo := jm
   END ELSE BEGIN
      jhi := jm
   END;
   GOTO 3;
4:
END;
