[comp.sys.handhelds] Root-finder for HP48

mblakele@jarthur.claremont.edu (Tad Blakeley) (02/22/91)

	Here's a beta version of PROOT, a root-finder for real-coefficient
polynomials.  Inputs are N, the degree of the polynomial, and A, its
coefficient matrix.  Example:  to find the roots of x^3+2x^2+3x+4,
enter [1 2 3 4] 'A' STO 3 'N' STO PROOT
	The routines were ported from a Fortran program, so I'm still
optimizing.  Eventually, if I can get the speed up to speed, I'll build
a root-locus plotter around PROOT.
	If you find this program useful, please try to optimize it.  The
number above the returned roots is a time for the PROOT call; it takes
about 16 seconds on my HP for a cubic polynomial.  If you can improve the
speed, accuracy, or size of PROOT, please let me know.  I'll post
improved versions as I get them written.
					-- tad
------------------------clip 'n' save-------------------------------------
%%HP: T(1)A(D)F(.);
DIR
  A
[ 1 2 3 4 ]
  N 3
  PROOT
    + TIME INIT
PART3 PART4
    ;
  TRIM
    + TIME - U V
(0,1) * + OBJ
 DROP
DROP KILL
    ;
  U
[ -.174685404255 -.174685404255 -1.65062919149 0 ]
  V
[ -1.54686888726 1.54686888726 0 0 ]
  INIT
    + N 1 + 1 
LIST
0 CON DUP 'V' STO
'U' STO N 1 + 'NC'
STO NC 1 + 1 
LIST
0 CON DUP 'C' STO
'B' STO -1 'IRREV'
STO A 'H' STO 0 0 0
'P' STO 'Q' STO 'R'
STO
    ;
  PP .174685404255
  QP 2.42331834482
  F -2.39280335436
  NL 3
  M 2
  NP 3
  E .0000000001
  PART70
    + 'NC' 2 STO-
      IF IRREV 0 <
      THEN Q INV
'QP' STO P Q 2 * /
'PP' STO
      ELSE Q 'QP'
STO P 2 / 'PP' STO
      END PP SQ QP
- 'F' STO
      IF F 0 <
      THEN U NC 1 +
PP NEG PUT NC PP
NEG PUT 'U' STO V
NC 1 + F NEG  PUT
DUP NC 1 + GET NEG
NC SWAP PUT 'V' STO
      ELSE U NC 1 +
PP PP ABS / PP ABS
F  + * NEG PUT DUP
NC 1 + GET QP SWAP
/ NC SWAP PUT 'U'
STO V NC 1 + 0 PUT
NC 0 PUT 'V' STO
      END 1 NC
      FOR I H I B I
2 + GET PUT 'H' STO
      NEXT PART4
    ;
  PART50
    + 'NC' 1 STO- V
NC 0 PUT 'V' STO
      IF IRREV 0 <
      THEN U NC R
INV PUT 'U' STO
      ELSE U NC R
PUT 'U' STO
      END 1 NC
      FOR I H I B I
1 + GET PUT 'H' STO
      NEXT PART4
    ;
  PART20
    + 1 1000
      FOR J NC 1 -
NC NP -
        FOR I B I H
I GET R B I 1 + GET
* + PUT 'B' STO C I
B I GET R C I 1 +
GET * + PUT 'C' STO
-1
        STEP
        IF B 1 GET
H 1 GET / ABS E 	
        THEN PART50
        END
        IF C 2 GET
0 ==
        THEN R 1 +
'R' STO
        ELSE R B 1
GET C 2 GET / - 'R'
STO
        END NC 1 -
NC NP -
        FOR I B I H
I GET P B I 1 + GET
* - Q B I 2 + GET *
- PUT 'B' STO C I B
I GET P C I 1 + GET
* - Q C I 2 + GET *
- PUT 'C' STO -1
        STEP 1 'T'
STO
        IF H 2 GET
0 
        THEN 1 'T'
STO+
        END
        IF B 2 GET
H T GET / ABS E 	 B
1 GET H 1 GET / ABS
E 	 AND
        THEN PART70
        END C 2 GET
B 2 GET - 'CBAR'
STO C 3 GET SQ CBAR
C 4 GET * - 'D' STO
        IF D 0 ==
        THEN P 2 -
'P' STO Q Q 1 + *
'Q' STO
        ELSE P B 2
GET C 3 GET * B 1
GET C 4 GET * - D /
+ 'P' STO
        END
      NEXT Q B 2
GET CBAR * B 1 GET
C 3 GET * - D / -
'Q' STO E 10 * 'E'
STO PART20
    ;
  PART19
    + .0000000001
'E' STO B NC H NC
GET PUT 'B' STO C
NC H NC GET PUT 'C'
STO B NC 1 + 0 PUT
'B' STO C NC 1 + 0
PUT 'C' STO NC 1 -
'NP' STO PART20
    ;
  PART4
    +
      IF NC 1 - 0
==
      THEN TRIM
      END
      IF NC 2 - 0
==
      THEN H 1 GET
H 2 GET / NEG 'R'
STO PART50
      END
      IF NC 3 - 0
==
      THEN H 2 GET
H 3 GET / 'P' STO H
1 GET H 3 GET / 'Q'
STO PART70
      END
      IF H NC 1 -
GET H NC GET / ABS
H 2 GET H 1 GET /
ABS - 0 

      THEN PART19
      END IRREV NEG
'IRREV' STO NC 2 /
'M' STO 1 M
      FOR I NC 1 +
I - 'NL' STO H NL
GET 'F' STO H NL H
I GET PUT 'H' STO H
I F PUT 'H' STO
      NEXT
      IF Q 0 
      THEN P Q /
'P' STO Q INV 'Q'
STO
      ELSE 0 'P'
STO
      END
      IF R 0 
      THEN R INV
'R' STO
      END PART19
    ;
  PART3
    + H 1 GET
      IF 0 ==
      THEN 'NC' 1
STO- V NC 0 PUT 'V'
STO U NC 0 PUT 'U'
STO 1 NC
        FOR I H I H
I 1 + GET PUT 'H'
STO
        NEXT PART3
      END
    ;
  R -1.65062919149
  Q 2.42331834482
  P .34937080851
  H
[ .34937080851 .34937080851 1 1 ]
  IRREV 1
  B
[ -.00000000023 2.42331834482 .34937080851 1 0 ]
  C
[ -7.54537830759 4.57121341744 -1.30125838298 1 0 ]
  NC 1
  D 3.43041707098
  CBAR
-.17701875726
  T 2
  I 1
END

wscott@en.ecn.purdue.edu (Wayne H Scott) (02/22/91)

I havn't posted this in a while, and some people seem to have 
missed it so...

Article 1164 of comp.sys.handhelds:
Newsgroups: comp.sys.handhelds
Path: en.ecn.purdue.edu!wscott
From: wscott@ecn.purdue.edu (Wayne H Scott)
Subject: polynomial routines ver 3.1
Message-ID: <1990Sep3.153439.4558@ecn.purdue.edu>
Organization: Purdue University Engineering Computer Network
Date: Mon, 3 Sep 90 15:34:39 GMT

Here it is, my polynomial routines version 3.2

Changes from version 3.1:
	- Faster PMUL
	- RT now works with complex cooeffients
	- various bug fixes

These routines are in the public domain, but I ask that if you use any of 
them in one of your programs you give me credit.  I am also
not responsible for any damage caused by these programs.

This package include the following programs.

TRIM	Strip leading zeros from polynomial object.
IRT	Invert root program.  Given n roots it return a nth degree polynomial.
PDER	Derivative of a polynomial.
RDER	Derivative of a rational function.
PF	Partial Fractions.  (Handles multiple roots!)
FCTP	Factor polynomial
RT	Find roots of any polynomial
L2A	Convert a list to an array and back.
PADD	Add two polynomials
PMUL	Multiply two polynomials.
PDIV	Divide two polynomials.
EVPLY	Evalulate a polynomial at a point.
COEF	Given an equation return a polynomial list.

These programs are for the HP-48sx.  I have a version of them that works
correctly on the HP-28.  Send me mail if you want it.

I think people will find these very useful and work as I say, but if you
find any bugs please send me E-Mail.  Comments are also welcome.

Some of these routines could be faster (PF, PMUL, ...) tell me if you know
how to speed them up.

_______________________________________________________________________________
Wayne Scott             |  INTERNET:   wscott@en.ecn.purdue.edu
Electrical Engineering  |  BITNET:     wscott%ea.ecn.purdue.edu@purccvm
Purdue University       |  UUCP:      {purdue, pur-ee}!en.ecn.purdue.edu!wscott
_______________________________________________________________________________


These programs all work on polynomials in the follows form:

3*X^3-7*X^2+5 is entered as  { 3 -7 0 5 }


Reasons why I use lists instead of arrays include:

        * lists look better on the stack.  (multi-line)
        * The interactive stack can quickly put serveral items in a
          list.
        * Hitting EVAL will quickly return the elements on a list.
        * the '+' key will add a element to the end or beginning of a list
          or concat two lists
        * Internally the main program that needs to be fast (BAIRS)
          does 100% stack maniplations so speed of arrays vs. lists was
          not a major issue.
        * It would be easier for later releases to include symbolic
          polynomials.

so going down the list...

The first program is FCTP. (factor polynomial)
When it is passed the cooeficients of a polynomial in a list it returns the
factor of that polynomal.  ex:
 
1: { 1 -17.8 99.41 -261.218 352.611 -134.106 }
FCTP
3: { 1 -4.2 2.1 }
2: { 1 -3.3 6.2 }
1: { 1 -10.3 }

This tells us that X^5-17.8*X^4+99.41*X^3-261.218*X^2+352.611*X-134.106
factors to (X^2-4.2*X+2.1)*(X^2-3.3*X+6.2)*(X-10.3)
 
Neat!

The next program is RT. (Roots)
If given a polynmoial it return its roots.  ex:

1: { 1 -17.8 99.41 -261.218 352.611 -134.106 }
RT
5: 3.61986841536
4: .58013158464
3: (1.65, 1.8648056199)
2: (1.65, -1.8648056199)
1: 10.3

Very Useful!
RT with work with complex cooeffients in the polynomial.

These programs use the BAIRS program which performs Bairstow's method of
quadratic factors and QUD with does the quadratic equation.

TRIM  is used to strip the leading zeros from a polynomial list.

{0 0 3 0 7 } TRIM => { 3 0 7 }

RDER  will give the derivative of a rational function.

ie. d        x + 4                   -X^2 - 8*x + 31
    --   -------------  =   --------------------------------
    dx   x^2 - 7*x + 3      x^4 - 14*x^3 + 55*x^2 - 42*x + 9

2: { 1 4 }
1: { 1 -7 3 }
RDER
2: { -1 -8 31 }
1: { 1 -14 55 -42 9 }

I don't know about you but I think it's useful.

IRT will return a polynomial whose roots you specify.

ie.  If a transfer function has zeros at -1, 1 and 5 the function
     is x^3 - 5*x^2 - x + 5

1: { -1 1 5 }
IRT
1: { 1 -5 -1 5 }

PDER will return the derivtive of a polynomial.

.ie   The  d/dx (x^3 - 5*x^2 - x + 5) = 3*x^2 - 10*x - 1

1: { 1 -5 -1 5 }
PDER
1: { 3 -10 -1 }

PF will do a partial fraction expansion on a transfer function.

.ie       s + 5	         1/18    5/270    2/3      1/9       2/27
     ----------------- = ----- + ----- - ------- - ------- - -----
     (s-4)(s+2)(s-1)^3   (s-4)   (s+2)   (s-1)^3   (s-1)^2   (s-1) 

2: { 1 5 }
1: { 4 -2 1 1 1 }
PF
1: { 5.5555e-2 1.85185e-2 -.6666 -.11111 -.074074 }

This program expects the polynomial of the numerator to be on level 2 and
a list with the poles to be on level 1.  Repeated poles are suported but
they must be listed in order.  The output is a list of the values of the 
fraction in the same order as the poles were entered.

PADD, PMUL, and PDIV are all obvious, they take two polynomial lists off
the stack and perform the operation on them.

PDIV returns the polynomial and the remainder polynomial.

L2A converts a list to and array. (and back)

1: { 1 2 3 }
L2A
1: [ 1 2 3 ]
L2A
1: { 1 2 3 }

EVPLY evalutates and polynomial at a point.

x^3 - 3*x^2 +10*x - 5 | x=2.5   = 16.875

2: { 1 -3 10 -5 }
1: 2.5
EVPLY
1: 16.875

P.S. Many thanks to Mattias Dahl & Henrik Johansson for fixs they have
     made.

%%HP: T(3)A(R)F(.);
DIR
  PDIV
  \<< DUP SIZE 3 ROLLD OBJ\-> \->ARRY SWAP OBJ\-> \->ARRY \-> c b a
     \<< a b 
         IF c 1 SAME THEN
           OBJ\-> DROP / OBJ\-> 1 GET \->LIST { 0 }
         ELSE           
           WHILE
             OVER SIZE 1 GET c \>=
           REPEAT DIVV
           END
           DROP \-> d
           \<< a SIZE 1 GET c 1 - - IF DUP NOT THEN
	       1 END \->LIST d OBJ\-> OBJ\-> DROP \->LIST
           \>>
        END
     \>>
  \>>
  TRIM
  \<< OBJ\-> \-> n
     \<< n
         WHILE ROLL DUP ABS NOT n 1 - AND
         REPEAT DROP 'n' DECR
         END n ROLLD
         n \->LIST
     \>>
  \>>
      RDER
        \<< \-> F G
          \<< G F
PDER PMUL G PDER {
-1 } PMUL F PMUL
PADD G G PMUL
          \>>
        \>>
      IRT
        \<< OBJ\-> \-> n
          \<<
            IF n 0
>
            THEN 1
n
              START
n ROLL { 1 } SWAP
NEG +
              NEXT
            ELSE {
1 }
            END
            IF n 1
>
            THEN 2
n
              START
PMUL
              NEXT
            END
          \>>
        \>>
      PDER
        \<< OBJ\-> \-> n
          \<< 1 n
            FOR i n
ROLL n i - *
            NEXT
DROP
            IF n 1
==
            THEN {
0 }
            ELSE n
1 - \->LIST
            END
          \>>
        \>>
      PF
        \<< MAXR { }
\-> Z P OLD LAST
          \<< 1 P
SIZE
            FOR I P
I GET \-> p1
              \<<
IF p1 OLD \=/
THEN Z p1 EVPLY 1 P
SIZE
  FOR J
    IF P J GET P I
GET \=/
    THEN p1 P J GET
- /
    END
  NEXT p1 'OLD' STO
{ } 'LAST' STO
ELSE
  IF { } LAST SAME
  THEN 1 { } 1 P
SIZE
    FOR K P K GET
      IF DUP p1 ==
      THEN DROP
      ELSE +
      END
    NEXT IRT Z SWAP
  ELSE LAST OBJ\->
DROP
  END RDER DUP2 5
PICK 1 + 3 ROLLD 3
\->LIST 'LAST' STO p1
EVPLY SWAP p1 EVPLY
SWAP / SWAP ! /
END
              \>>
            NEXT P
SIZE \->LIST
          \>>
        \>>
      FCTP
        \<<
          IF DUP
SIZE 3 >
          THEN DUP
BAIRS SWAP OVER
PDIV DROP FCTP
          END
        \>>
      RT
        \<< TRIM DUP
SIZE \-> n
          \<<
            IF n 3
>
            THEN
DUP BAIRS SWAP OVER
PDIV DROP \-> A B
              \<< A
RT B RT 
              \>>
            ELSE
              IF n
2 >
              THEN
QUD 
              ELSE
LIST\-> DROP NEG SWAP
/
              END
            END 
          \>>
        \>>
      L\178A
        \<<
          IF DUP
TYPE 5 ==
          THEN OBJ\->
\->ARRY
          ELSE OBJ\->
1 GET \->LIST
          END
        \>>
      PADD
        \<< DUP2 SIZE
SWAP SIZE \-> A B nB
nA
          \<< A L\178A B
L\178A
            IF nA
nB <
            THEN
SWAP
            END
            IF nA
nB \=/
            THEN 1
nA nB - ABS
              START
0
              NEXT
            END nA
nB - ABS 1 + ROLL
OBJ\-> 1 GET nA nB -
ABS + \->ARRY + L\178A
          \>>
        \>>
      PMUL
        \<< DUP2 SIZE
SWAP SIZE \-> X Y  ny
nx
          \<<
	    1 nx ny + 1 - FOR I
	       0 
	    NEXT
	    1 nx FOR I
	       1 ny FOR J
		 I J + 1 - ROLL
		 X I GET Y J GET * +
		 I J + 1 - ROLLD
	       NEXT
	    NEXT
	    { }
	    1 nx ny + 1 - START
	      SWAP +
	    NEXT
	 \>>
    \>>
      EVPLY
        \<< OVER
          IF DUP
TYPE 5 ==
          THEN SIZE
          ELSE SIZE
1 GET
          END \-> a r
n
          \<< a 1 GET
            IF n 1
>
            THEN 2
n
              FOR i
r * a i GET +
              NEXT
            END
          \>>
        \>>
      COEF
        \<< \-> E n
          \<< 0 n
            FOR I 0
'X' STO E EVAL 'X'
PURGE E 'X' \.d 'E'
STO I ! /
            NEXT 2
n 1 +
            FOR I I
ROLL
            NEXT n
1 + \->LIST
          \>>
        \>>
      EQ 1
  DIVV
    \<< DUP 1 GET \-> a
b c
      \<< a 1 GET c /
DUP b * a SIZE RDM
a SWAP - OBJ\-> 1
GETI 1 - PUT \->ARRY
SWAP DROP b
      \>>
    \>>
  QUD
    \<< LIST\-> \->ARRY
DUP 1 GET / ARRY\->
DROP ROT DROP SWAP
2 / NEG DUP SQ ROT
- \v/ DUP2 + 3 ROLLD
-
    \>>
  BAIRS
    \<< OBJ\-> 1 1 \-> n
R S
      \<<
        DO 0 n 1 +
PICK 0 0 0 4 PICK 5
n + 7
          FOR J J
PICK R 7 PICK * + S
8 PICK * + 7 ROLL
DROP DUP 6 ROLLD R
3 PICK * + S 4 PICK
* + 5 ROLL DROP -1
          STEP 3
PICK SQ 3 PICK 6
PICK * -
          IF DUP 0
==
          THEN DROP
1 1
          ELSE 6
PICK 6 PICK * 5
PICK 9 PICK * -
OVER / 4 PICK 9
PICK * 8 PICK 7
PICK * - ROT /
          END DUP
'S' STO+ SWAP DUP
'R' STO+
        UNTIL (0,1) * +
ABS .000000001 < 7
ROLLD 6 DROPN
        END n DROPN
1 R NEG S NEG 3
\->LIST
      \>>
    \>>
END

-- 
_______________________________________________________________________________
Wayne Scott             |  INTERNET:   wscott@en.ecn.purdue.edu
Electrical Engineering  |  BITNET:     wscott%ea.ecn.purdue.edu@purccvm
Purdue University       |  UUCP:      {purdue, pur-ee}!en.ecn.purdue.edu!wscott

-- 
_________________________________________________________________________
Wayne Scott             |  INTERNET: wscott@ecn.purdue.edu
Electrical Engineering  |  BITNET:   wscott%ecn.purdue.edu@purccvm
Purdue University       |  UUCP:     purdue, pur-ee}!ecn.purdue.edu!wscott