Metropoli BBS
VIEWER: primefac.all MODE: TEXT (ASCII)
Article 2282 of comp.sys.handhelds:
Path: en.ecn.purdue.edu!noose.ecn.purdue.edu!samsung!usc!apple!bionet!ames!eos!data.nas.nasa.gov!mustang!nntp-server.caltech.edu!piglet!madler
From: madler@piglet.caltech.edu (Mark Adler)
Newsgroups: comp.sys.handhelds
Subject: Breaking out of loops on the HP-48SX
Message-ID: <1990Nov11.002758.4933@nntp-server.caltech.edu>
Date: 11 Nov 90 00:27:58 GMT
Sender: news@nntp-server.caltech.edu
Organization: California Institute of Technology, Pasadena
Lines: 69
Nntp-Posting-Host: piglet.caltech.edu


I just discovered a technique that I thought I'd share.  The HP-48SX
appears to lack a way to break out of loops.  But appearances can be
deceiving.  There is a kludgey way to do it.  You can put the loop
in an IFERR statement, and then divide by zero or some such thing to
cause an error.  This appears to cleanly exit the loop (or loops).
As an example of this tehcnique, here is a program (FACNUM) which
will take a whole number and return its prime factorization as a
list of primes, repeated if necessary.  I wanted to avoid having the
inner loop do two tests, so it could be a simple FOR loop, and so
the loop exit is done inside IF statements with a divide by zero.

A note to HP: please include a throw/catch operation for exiting
loops on the next calculator (48SY?  49?).  The code to handle
cleaning up leftover constructs appears to already be there for
IFERR.  Thanks.

Mark Adler
madler@piglet.caltech.edu

program follows ...

%%HP: T(3)A(R)F(.);
@ FACNUM (BYTES = 277.5, #74FFh)
@ Given an integer, return its prime factorization as a list.
@ For example, 16353 FACNUM returns { 3 3 23 79 }.
\<<
  @ initialize factor list
  { } SWAP

  @ For this part of the program the stack is: n factorlist, where the two are
  @ kept so that the product of the list times n is the original integer.

  @ factor out 2's
  WHILE DUP 2 MOD NOT REPEAT
    2 / SWAP 2 + SWAP END

  @ factor out 3's
  WHILE DUP 3 MOD NOT REPEAT
    3 / SWAP 3 + SWAP END

  @ start factor search at 5
  5

  @ The stack is now: k n factorlist, where the second two are maintained as
  @ before, and k is the largest 5 mod 6 integer less than or equal to the
  @ last factor found (execpt initially when it is set to 5).

  @ search from k to sqrt(n) for factors---k must be 5 mod 6
  WHILE OVER 1 \=/ REPEAT       @ do while n is not one
    OVER \v/ FLOOR              @ go up to the floor of the square root
    IFERR                       @ (divide by zero used as a loop breaker)
      FOR i                     @ look at factors that are 1 and 5 mod 6
	IF DUP i MOD NOT THEN
	  i 0 / END             @ if 5 mod 6 divides n, then cause error
	IF DUP i 2 + MOD NOT THEN
	  i 2 + 0 / END         @ if 1 mod 6 divides n, then cause error
      6 STEP
    THEN DROP                   @ got an error---trash the zero
    ELSE DUP                    @ end of loop---n divides n
    END                         @ after this, stack is: factor n factorlist
    ROT OVER + ROT ROT          @ add factor to list (factor n factorlist')
    SWAP OVER / SWAP            @ divide out divisor (factor n' factorlist')
    DUP 6 MOD 5 - 2 / +         @ set k' to largest 5 mod 6 <= divisor
  END                           @ find next factor (k' n' factorlist')

  @ return list, dropping n and k
  DROP2
\>>


[ RETURN TO DIRECTORY ]