Metropoli BBS
VIEWER: 2q_new.all MODE: TEXT (ASCII)
Date: Thu, 21 Mar 1991 21:26 CST
Subject: HP 48 Improved ->Q
Lines: 65

%%HP:T(3);
@ DEC2FRAC for the HP 48SX (obsoletes ->Q)
@ Improved Decimal-to-Fraction, by Joseph K. Horn.
@
@ Faster & more complete than HP 48SX (->Q function) and HP 32SII
@   (with maximum denominator set), both of which miss many solutions,
@   and slowly recalculate the summations for each term rather than
@   using a fast recursion formula to get each term from the last two.
@ This new algorithm finds the very best solution, very quickly.
@ Algorithm: Continued Fractions by fast recursion formula, then jump
@   backwards to the best possible fraction before the specified
@   maximum denominator.
@
@   Copyright (c) 1991 by Joseph K. Horn.
@   May be used freely in any application that has no documentation.
@   May be in a documented application if the above author is credited.
@
@ Input:
@
@ 2: Decimal Number to be converted to a fraction
@ 1: Maximum Allowed Denominator (a positive integer)
@
@ Output:
@
@ 1: 'Numerator/Denominator'
@
@ Example: What fraction is closest to the number "e", but
@   with a denominator not bigger than 20?  It's 49/18.
@
@ The HP 48SX and the HP 32SII say it's 19/7.  They say that the next
@   better fraction is 87/32.  But there are two fractions between
@   these which are missed: 49/18 and 68/25.
@
@ Press 1 EXP 20 DEC2FRAC and see '49/18', the correct answer.
@
@ An example of speed increase is the golden ratio, (sqr(5)+1)/2, which
@   is approximately 514229/317811.  This is found by the HP 48SX ->Q
@   function in 3.23 seconds, and by DEC2FRAC in 1.29 seconds.
@
@ Checksum = # 4F52h; Size on stack = 296.5 bytes.
@
\<< DUP2 @ Must be two arguments.  Exit now if max denominator < 2, or
  IF 1 > SWAP FP AND @ if decimal fraction is an integer.
  THEN \-> f c @ Store decimal fraction, and max denominator.
    \<< 0 1 f @ Calculate only denominators.  Do numerator only at end.
      WHILE OVER c < OVER AND @ Do until bigger than max denominator
      REPEAT INV DUP FP 4 ROLLD IP OVER * ROT + ROT @ This is the
      END DROP DUP2 c @ recursion formula continued fraction expansion.
      IF DUP2 > @ Is there a possible "missing" fraction?
      THEN - OVER / CEIL * - @ This is the new, fast "jump backwards".
      ELSE 3 DROPN @ (Sometimes there's no need to jump.)
      END DUP2 1 2 @ Take the new denominator & the previous one, and
      START DUP f * 0 RND SWAP / f - ABS SWAP @ turn into fractions.
      NEXT @ See which one's closest to the original decimal fraction.
      IF > @ Compare the two solutions, and
      THEN SWAP @ pick the better one.
      END DROP DUP f * 0 RND SWAP @ Calculate the numerator.
    \>> @ End of real work; now clean up the output.
    IF DUP ABS 1 > @ Is the denominator greater than 1?
    THEN # 5603Eh SYSEVAL @ If so, make output into 'A/B' form.
    ELSE DROP @ Otherwise, get rid of extraneous denominator,
    END @ and exit program.
  ELSE DROP @ If bad arguments, do nothing to "decimal fraction", but
  END @ get rid of "maximum denominator" and exit program.
\>>

Subject: Re: HP 48 Improved ->Q
Date: 25 Mar 91 05:40:06 GMT
Lines: 16

re: DEC2FRAC by Joseph K. Horn, posted 21 March 1991.

At the March 22nd meeting of the Orange/Los Angeles Counties Chapter
of the HP-48 users club, Harry Bertucelli objected to my contention
that DEC2FRAC finds ALL possible fractions.

Harry is a professional mathematician, and accepts nothing without a
formal proof.  So he withdrew to a corner of the room and into a
deeper corner of his mind, and in short order developed a complete
proof that DEC2FRAC does in fact find all possible fractions (up to
the point where the HP 48 begins to introduce round-off errors, of
course).  It made his day to see (and prove the validity of) a
completely new algorithm in number theory.  It made my day to know
that the very first computer to run it was an HP 48SX.

--  Joseph K. Horn  --  Peripheral Vision, Ltd.  --


Subject: DEC2FRAC-II for the HP48SX
Date: 27 Mar 91 05:29:25 GMT
Organization: The Portal System (TM)
Lines: 124


*** HP 48SX ***

First, congratulations to Joe Horn for his recently posted algorithm
which improves on the ->Q function of the HP48.  Joe's program (which
he calls DEC2FRAC, and I call TO.Q, requires two inputs:

    2:  real number to be "fractionalized"
    1:  maximum value of the denominator

By specifying the maximum denominator, the user can greatly control
the output of the program.  However, if you're performing many
computations which all involve the same maximum denominator, it is
tiresome to have to repeatedly re-enter this denominator.

I've written a small calling program which allows you to maintain the
same denominator.  This is done by entering the maximum denominator
only when you wish to change it -- and in that case, it must be the
only element in a list in level one.  That is, on executing the
calling program (which I call TO.Q2), if level 1 contains a list, the
value in the list is stored into a global variable named 'denom'.
Then 'denom' is recalled to level 1, and execution dumps into TO.Q.

If, on executing TO.Q2, level 1 contains a real number (actually,
anything other than a list), 'denom' is recalled to level 1, and
execution continues with TO.Q.

Example:  What are the best fractional approximations for e and the
	  square root of 2 ( v/2 ) with a maximum denominator of 100?

   Solution:  First do e:  1  EXP  { 100 }   TO.Q2   ==>  '193/71'

	      Now do v/2:  Since the max denom is the same, just
			   enter v/2:
				      2  v/  TO.Q2   ==>  '140/99'


NOTES:

1.  There is not much error-checking for valid inputs in these
    routines.  Perhaps an internal RPL version could do this without
    slowing down execution much (Joe?).

2.  Storing to and recalling 'denom' are subject to all the rules of
    the directory structure: "You can RCL from anyplace, but you STO
    where you sit."  That is, you can use (recall) 'denom' if it's in
    a parent directory, but if you create a new value for 'denom',
    it's stored in the current subdirectory.

3.  I've assigned Joe's main program to the ->Q position on my 48,
    and TO.Q2 to the ->NUM position, so both are readily available.


4.  Again, all credit for DEC2FRAC (or TO.Q) goes to Joe Horn.

Following TO.Q2, I've listed Joe's program, in case you missed it.

%%HP: T(3)A(D)F(.);
@
@ TO.Q2 -- Calling program for TO.Q  (or DEC2FRAC, by Joe Horn)
@
@ Input:   2: real number to be converted to a fraction
@          1: list containing maximum denominator
@      or
@          1: real number to be converted to a fraction
@             (using previous maximum denominator)
@
\<< DUP TYPE
  IF 5 ==                 @ Does level 1 contain a list?
  THEN OBJ\-> DROP        @ If so, then extract the max denom and
'denom' STO               @ STOre it
  END denom               @ Recall max denom to level 1
 TO.Q                     @ Dump to TO.Q -- change this to DEC2FRAC
\>>                       @   if you use the original name

Note:  My first version of TO.Q2 used a binary value rather than a
list in level 1 to specify a new max denom.  But -- my 48 is
usually in HEX mode -- I often forgot to add the 'd' to the binary.
If you prefer using a binary value, change:
     5    to    10
     OBJ\->  DROP   to   B\->R


Stephen J Thomas
sjthomas@cup.portal.com
akcs.sjthomas@hpcvbbs.uucp


%%HP: T(3)A(D)F(.);
@ TO.Q  (or DEC2FRAC)  by Joseph K. Horn
\<< DUP2
  IF 1 > SWAP FP
AND
  THEN \-> f c
    \<< 0 1 f
      WHILE OVER c
< OVER AND
      REPEAT INV
DUP FP 4 ROLLD IP
OVER * ROT + ROT
      END DROP DUP2
c
      IF DUP2 >
      THEN - OVER /
CEIL * -
      ELSE 3 DROPN
      END DUP2 1 2
      START DUP f *
0 RND SWAP / f -
ABS SWAP
      NEXT
      IF >
      THEN SWAP
      END DROP DUP
f * 0 RND SWAP
    \>>
    IF DUP ABS 1 >
    THEN # 5603Eh
SYSEVAL
    ELSE DROP
    END
  ELSE DROP
  END
\>>



Subject: Re: DEC2FRAC-II for the HP48SX
Date: 27 Mar 91 20:51:18 GMT
Sender: news@ai.mit.edu
Organization: nil
Article-I.D.: life.14393
Lines: 37

In a posting of [27 Mar 91 12:55:28 GMT]
   wscott@en.ecn.purdue.edu (Wayne H Scott) writes:

 > 2: '.5*X-.75'
 > 1: 10
 > DEC2FRAC                     <-- ->Q works this way but I don't know how
 > 1: '1/2*X-3/4'                          to duplicate it.


   The following program used ->Q instead of DEC2FRAC (only for
illustrative purposes, I don't have DEC2FRAC at hand):

DO->Q:

<< IFERR OBJ->                  @ Break up algebraic
   -> n oper                    @ Save operand count and operator (e.g. +)
     << 1 n START               @ Loop operands
	  DO->Q                 @ Convert operand
	  n ROLL                @ Move to next operand circularly
	NEXT
	oper EVAL               @ Join back together
     >>
   THEN ->Q END                 @ Not algebraic - apply your ->Q here
>>


Thus, '(.5+.2)/.1' DO->Q results in '(1/2+1/5)/(1/10)'

   Limitations are of course arguments made up of lists, programs,
strings, etc, that are acceptable to OBJ->. The IFERR construct can be
replaced by a rather extensive type check, much easier done with
system RPL. I didn't keep Joe's DEC2FRAC (assuming I can get it from
your server whenever I need it), but the code above should be fairly
trivial to adapt to it. (So we'll leave that as a reader exercise.)

						-- Jan Brittenson
						   bson@ai.mit.edu

Subject: Re: HP 48 Improved ->Q
Date: 28 Mar 91 07:40:05 GMT
Lines: 63

re: DEC2FRAC by Joseph K. Horn, posted 21 March 1991.

In a followup message, I said:

> ... a completely new algorithm in number theory.  It made my day
> to know that the very first computer to run it was an HP 48SX.

Well, darn it, this is only half true.  It may well be that the 48
has the honors, but the algorithm IS NOT NEW.

Bummer.  I thought I'd discovered something new.  Turns out that I
was 102 years late!!  In a book called _Textbook of Algebra_ by G.
Chrystal, 1st edition in 1889, in Part II, Chapter 32, this improved
continued fraction algorithm is presented and proven.  Odd to tell,
Chrystal speaks of it as if it were ancient knowledge.  The original
discoverer is not named, nor is the algorithm.  Hmmm.  Thanks to
Harry Bertucelli for exhuming this obscure reference.

In any case, it seems to have lay dormant for many years; it is not
mentioned in modern books about number theory.  It's time for us to
revitalize it!  An HP 48 Fraction Library could easily give us the
same power over "fractional objects" that the UNITS menu gives over
unit objects, plus the power of the HP 32SII's ability to handle
fractions as single "objects".

How would you like to be able to divide '2_hr+34_min+56.78_sec' by 4
and see '38_min+44.195_sec'?  Sure, you can use the HMS-> and ->HMS
functions... but why should PEOPLE do what a CALCULATOR should do for
them???  An HP 48 Fraction Library should have:

User-defined unit names and divisors.  Lots of modes: show decimal
after last unit; drop last unit remainder; round last unit; show last
unit as a fraction; maximum allowable denominator; maximum allowable
numerator; maximum allowable numerator AND denominator; force denomi-
nator to always be n; force denominator to always be a factor of n;
allow denominator to be whatever it takes to get the most accuracy;
easy entry of decimal and fractional units...

A few obvious applications are:

yards, feet, inches (e.g. with denominator set to 16ths)
days, hours, min, sec (100ths)
inches, picas, points, HP PCL units (4ths)
gallons, quarts, pints, cups
pounds, shillings, pence, farthings (???)

Everybody has their own messy fractions to deal with every day.
The new thing this library will do is let you specify what YOU want.
It'd make the old "postage stamp problem" trivial to solve.

I just did a bulk rate mailing; 25 raffle tickets per book, two books
per envelope, 10 envelopes per bundle, 20 bundles per sack.  Juggling
uneven sacks isn't difficult math... but I hate it!  It's work that
a machine should do, not a human mind, which should be concerned with
things machines can't do, like what the accompanying letter should
say!  With a Fraction Library it'd be almost pleasant.

If you have any ideas you'd like to see included in a Fraction Library
like this, please post it soon, so that this doesn't become another
dribbleware item.  It'll be freeware, of course.  Right now it's 100%
vaporware, and will be available Real Soon Now.

--  Joseph K. Horn  --  Peripheral Vision, Ltd.  --


Subject: Re: DEC2FRAC-II for the HP48SX
Organization: Purdue University Engineering Computer Network
Lines: 94

In article <27f2c9cd:1772.4comp.sys.handhelds;1
>Wayne Scott asks for DEC2FRAC to parse equations like ->Q does.
>
>No problem.  I'm on it...
>
>-- Joe Horn --

Sorry I've already done it...

This program handles:
	real numbers
	complex numbers
	equations
	TAGGED objects
	lists
	and any combination of the above

{ .25 '.5*X-.75' (.25, -.333) }
10
DO\->Q
{ '1/4' '1/2*X-3/4' '1/4-1/3*i' }


I now have this programs assigned to my old \->Q key.
Many thanks to:
	Joseph Korn for writing the DEC2FRAC program
and     Jan Brittenson for showing me how to handle equations.
		(I never knew OBJ\-> would do that)

[ sorry typed in by hand }
DO\->Q
Checksum: # C215h
Size:   386

\<< \-> A D
\<< A TYPE \-> T \<<
  CASE T 0 ==
	THEN A D D2F END
	T 9 == THEN A OBJ\-> \-> n oper \<<
	1 n START D DO\->Q n ROLL NEXT
	oper EVAL \>>
	END
	T 1 == THEN A RE D DO\->Q A IM D DO\->Q i * + END
	T 5 == THEN A OBJ\-> \-> n \<< 1 n
	START D DO\->Q n ROLL NEXT
	n \->LIST \>>
	END
	T 12 == THEN
	A OBJ\-> SWAP D DO\->Q SWAP \->TAG END
	A
  END
\>> \>> \>>


D2F is the same program posted eariler with the following changes.

D2F
Checksum: # 2667h
Size: 339
%%HP:T(3);
\<< DUP2
  IF 1 > SWAP FP AND
  THEN SWAP EVAL \-> c f        @ added EVAL so it can handle '2/4'
    \<< 0 1 f
      WHILE OVER c < OVER AND
      REPEAT INV DUP FP 4 ROLLD IP OVER * ROT + ROT
      END DROP DUP2 c
      IF DUP2 >
      THEN - OVER / CEIL * -
      ELSE 3 DROPN
      END DUP2 1 2
      START DUP f * 0 RND SWAP / f - ABS SWAP
      NEXT
      IF >
      THEN SWAP
      END DROP DUP f * 0 RND
    \>>
IF OVER 0 < THEN NEG SWAP NEG ELSE SWAP END     @ so -.25 -> -(1/4) not 1/-4
    IF DUP ABS 1 >
    THEN # 5603Eh SYSEVAL
    ELSE DROP
    END
  ELSE DROP
  END
\>>

Joe --  Is there a better way to handle negitive fractions?


--
_________________________________________________________________________
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


Subject: ->Q or Not ->Q
Organization: Hewlett-Packard Co., Corvallis, OR, USA
Lines: 108

From the HP 48 Design Team:


	       ->Q OR NOT ->Q, THAT IS THE QUESTION

Thanks to Joseph Horn, the HP28/48 community now has additional fast
rationalization functionality for their machines (see "HP 48 Improved
->Q".)  We congratulate him for this elegant solution!  There are a
number of interesting points regarding DEC2FRACs relation to ->Q
which deserve some mention.  Perhaps these will stimulate discussion
and further contributions.

DEC2FRAC is an addition and not a replacement for ->Q because its aim
is rather different. DEC2FRAC's aim is to produce the fraction with
the _smallest error_ and a given denominator size. ->Q's aim is to
produce the fraction with the _smallest denominator_ and a given error
size. This is best illustrated with the golden mean, '(1+\sqr(5))/2'.
Given this and 1E11, DEC2FRAC returns '139583862445/86267571272' while
->Q returns (in STD mode) '514229/317811'. When evaluated, these
return _exactly_ the same floating point number. The idea of ->Q is
to "round to simpler" rather than "round to closer." This is useful
where you have what you believe to be a "simple" fraction contaminated
with roundoff or other noise.

The HP48 manuals did little to clarify this issue, especially since we
wanted to make no specific claim with only a conjecture of correctness. In
this regard, posting a proof that the algorithm fills in all possible
fractions would be a great boon to the community.

While for many "interesting" numbers the continued fraction sequence as
generated by DUP IP SWAP FP INV ... is exact, even though the floating
point representation is not, in other cases, you get "noise" unexpectedly
early. Does this have any significance regarding the "safety" of generating
the numerator of the fraction from the denominator by division?

While ->Q keeps around the entire continued fraction sequence entailing
some speed penalty, there may be other statistics about the sequence
(such as periodicity) which can be of interest in "deciphering" a
floating point number. Suggestions along these lines are most welcome.

Thanks again to J. Horn for a stimulating and useful post.


Included below is a program, NEW2Q which follows Horn's algorithm, but
uses exit conditions like those of ->Q.

@ NEW2Q: Version of ->Q based on J.K.Horn's Algorithm
@
@ Input:
@
@ 2: Decimal Number to be converted to a fraction
@ 1: Number of decimal places of zeros required in the error.
@
@ Output:
@
@ 1: 'Numerator/Denominator'
@
@ Example:
@
@ What's the simplest fraction which agrees with sqrt(3) to 4 decimal places?
@   3 \sqr 4 NEQ2Q returns '97/56'
@   '97/56-\sqr(3)' EVAL returns .00009294957
@                                 ^^^^  note 4 zeros.
@
@ Checksum and bytes:
@   #3992d
@   620.5

%%HP: T(3)A(R)F(.);
\<< DUP2
  IF 1 > SWAP FP AND
  THEN OVER XPON 1 -                        @ calculate the input exponent.
    \<< \-> X 'IFTE(X==0,-500,XPON(X))' \>> @ define a 0-tolerant XPON.
  \-> f c x expo
    \<< 0 1 1 f DUP IP SWAP FP              @ set recursion initial cond.s.
      WHILE
       OVER 5 PICK / f - ABS expo EVAL      @ calculate expon. of error
       x SWAP - c <                         @ and compare with input.
       OVER AND                             @ if not close enough and
					    @ the remainder's non-zero
      REPEAT
       INV DUP FP SWAP IP                   @ then calculate next iterate.
       \-> B0 B1 A0 A1 R B
	\<< B1 'B*B1+B0' EVAL
	    A1 'B*A1+A0' EVAL
	    R
	\>>
      END
      DROP SWAP DROP SWAP
      DUP 4 ROLL - DUP f * 0 RND            @ calc. "missing" den. and num.
      \-> N D D0 N0
      \<<
	IF 'x-expo(ABS(f-N0/D0))<c'         @ if "missing" frac. is not
	THEN N D                            @ good enough, use original.
	ELSE N0 D0
	  IF 'N0\=/N'                       @ If it is really new,
	  THEN 200 .2 BEEP                  @ then beep.
	  END
	END
      \>>
    \>>                                     @ We're done, now clean up.
    IF DUP ABS 1 >
    THEN # 352318d SYSEVAL
    ELSE DROP
    END
  ELSE DROP
  END
\>>


Subject: DEC2FRAC problem
Date: 3 Apr 91 01:12:09 GMT
Sender: news@nntp-server.caltech.edu
Organization: California Institute of Technology
Lines: 46


Joseph K. Horn's recent posting of DEC2FRAC was modified to more
closely emulate the capabilities of the \->Q function on the keyboard,
i.e. to operate on any (reasonable) object type (apologies for not
saving the modifier's name, I excitedly copied the code to my calculator
without saving references). I found one incompatability:

When fractions (quotients) and decimals are represented in the same
algebraic repeated calling of DO\->Q swaps the two representations,
but there is never a time when all are in quotient form. I.e.

2: '1/2 + .25'   produces    1: '.5 + 1/4'
1: 10
DO\->Q

Calling DO\->Q again reproduces the original input. \->Q on the otherhand
will produce quotients from decimals without evaluating already extant
quotients to decimals. I.e., the above example produces

1: '1/2 + 1/4'

The problem seems to be the code fragment "oper EVAL" after the START loop.
EVAL is not the inverse of OBJ\-> in this case:

1: '1/2'  produces    4: 1
OBJ\->                3: 2
		      2: 2
		      1: /
But

3: 1      produces    1: .5
2: 2
1: /
EVAL

So I guess the question is, what is the "correct" way to invert this
operation of OBJ\->? How does one re-assemble an algebraic from the stack
without evaluating quotients to real numbers?

Surely there's a SYSEVAL for this, there always is :-) ???

Despite this tiny bug, the algorithm is wonderful. And the process is quite
educational. Thanks for the routines, guys!!

-- Tim Conrow
tim@ipac.caltech.edu


Subject: Re: DEC2FRAC problem
Date: 3 Apr 91 03:47:26 GMT
Organization: nil
Lines: 21

In a posting of [3 Apr 91 01:12:09 GMT]
   tim@nijinsky.ipac.caltech.edu (Tim Conrow) writes:

 > The problem seems to be the code fragment "oper EVAL" after the START
 > loop.  EVAL is not the inverse of OBJ\-> ... Surely there's a SYSEVAL
 > for this, there always is :-) ???

Yeah, #546d puts together an Algebraic. Try replacing:

	oper EVAL

with:

	oper
	n 1 + # 18CEAh SYSEVAL          @ n+1 as system binary
	# 546Dh SYSEVAL                 @ join as algebraic

Let's hope this works better!

						-- Jan Brittenson
						   bson@ai.mit.edu


Subject: Re: ->Q or Not ->Q
Date: 11 Apr 91 00:27:44 GMT
Organization: State University of New York @ Buffalo
Lines: 171

In article <25590130@hpcvra.cv.hp.com.> billw@hpcvra.cv.hp.com. (William C
 Wickes) writes:
>From the HP 48 Design Team:
>
[ETC]
>
>Included below is a program, NEW2Q which follows Horn's algorithm, but
>uses exit conditions like those of ->Q.
>
>@ NEW2Q: Version of ->Q based on J.K.Horn's Algorithm
>@
>@ Input:
>@
>@ 2: Decimal Number to be converted to a fraction
>@ 1: Number of decimal places of zeros required in the error.
>@
>@ Output:
>@
>@ 1: 'Numerator/Denominator'
>@
>@ Example:
>@
>@ What's the simplest fraction which agrees with sqrt(3) to 4 decimal places?
>@   3 \sqr 4 NEQ2Q returns '97/56'
>@   '97/56-\sqr(3)' EVAL returns .00009294957
>@                                 ^^^^  note 4 zeros.
>@
>@ Checksum and bytes:
>@   #3992d
>@   620.5
>
>%%HP: T(3)A(R)F(.);
>\<< DUP2
>  IF 1 > SWAP FP AND
>  THEN OVER XPON 1 -                        @ calculate the input exponent.
>    \<< \-> X 'IFTE(X==0,-500,XPON(X))' \>> @ define a 0-tolerant XPON.
>  \-> f c x expo
>    \<< 0 1 1 f DUP IP SWAP FP              @ set recursion initial cond.s.
>      WHILE
>       OVER 5 PICK / f - ABS expo EVAL      @ calculate expon. of error
>       x SWAP - c <                         @ and compare with input.
>       OVER AND                             @ if not close enough and
>                                            @ the remainder's non-zero
>      REPEAT
>       INV DUP FP SWAP IP                   @ then calculate next iterate.
>       \-> B0 B1 A0 A1 R B
>        \<< B1 'B*B1+B0' EVAL
>            A1 'B*A1+A0' EVAL
>            R
>        \>>
>      END
>      DROP SWAP DROP SWAP
>      DUP 4 ROLL - DUP f * 0 RND            @ calc. "missing" den. and num.
>      \-> N D D0 N0
>      \<<
>        IF 'x-expo(ABS(f-N0/D0))<c'         @ if "missing" frac. is not
>        THEN N D                            @ good enough, use original.
>        ELSE N0 D0
>          IF 'N0\=/N'                       @ If it is really new,
>          THEN 200 .2 BEEP                  @ then beep.
>          END
>        END
>      \>>
>    \>>                                     @ We're done, now clean up.
>    IF DUP ABS 1 >
>    THEN # 352318d SYSEVAL
>    ELSE DROP
>    END
>  ELSE DROP
>  END
>\>>

When I saw this article, I immediately typed the program in (the set-up
here makes that easier for ascii programs than using Kermit ;^( ), assigned
it to key 33.2 (where \->Q normally is), and have been happily using it
ever since.  I did run into a couple of problems today, though.  They are
listed below with suggested work arounds.

After playing around with the recently posted LSQ, I had left the
calculator in Numeric Evaluation mode (ie, flag -3 was set).  I discovered
that this makes for a bit of a problem in using NEW2Q, a problem that does
not show up in \->Q.  For the curious, the routine at 5603Eh (351218d) is
just the symbolic divide function; the same one that is called by the user
language / function when it sees that its arguments are both either Global
Names or Algebraics.  If numeric evaluation is in effect, you might as well
call \->NUM right after the SYSEVAL above; the effect is the same.  The end
result is that you get another real to the stack rather than the symbolic
you were expecting.  If the rational is exact, it'll look just like the
level 1 argument is simply DROPed.

The solution is to save the flags in a local, clear -3, and restore the
flags at the end.

The other problem is more of a bug.  If the value you are trying to
rationalize, to the number of decimal places specified in level 1, comes
out as an integer, then you will get a 0-divided-by-0 error.  Specifically,
in this case the locals 'N0' and 'D0' are both 0.  To solve this, I took
the following section:

\-> N D N0 D0
\<<
  IF 'x-expo(ABS(f-N0/D0))<c'
  THEN N D
  ELSE N0 D0
    IF 'N0\=/N'
    THEN 200 .2 BEEP
    END
  END
\>>

and changed it to:

\-> N D N0 D0
\<<
  IF D0
  THEN
    IF 'x-expo(ABS(f-N0/D0))<c'
    THEN N D
    ELSE N0 D0
      IF 'N0\=/N'
      THEN 200 .2 BEEP
      END
    END
  ELSE N D
  END
\>>


While looking at the code in my 48 just now to make sure I got the above
changes correct, I discovered another small change I made.  As written, if
the real is negative, you can get results like '5/-2', which I don't exacly
like.  The change I made to ensure that the result would look like '-(5/2)'
instead, is from:

  IF DUP ABS 1 >
  THEN # 352318d SYSEVAL
  ELSE DROP
  END

to:

  IF DUP ABS 1 .
  THEN DUP2 * SIGN ROT ABS ROT ABS # 5603Eh SYSEVAL *
  ELSE DROP
  END

I used * after the DUP2 rather than / because multiplication is usually
faster than division, but as the speed difference in this case is so
minimal, change it to / if you think it looks more understandable.


On a slightly different topic, if you would like a \->ZQ function using
this algorithm (ZQ meaning integer+rational), change the section
immediately above to look like:

  IF DUP ABS 1 >
  THEN DUP2 / DUP SIGN SWAP ABS IP 4 ROLL ABS 4
PICK ABS MOD 4 ROLL ABS # 352318d SYSEVAL + *
  ELSE DROP
  END

I'm presently calling this version of the function NW2ZQ, as it fits better
in the menu.

(As a side note, I would tend to expect that if these were written in
the internal

-JimC
--
James H. Cloos, Jr.             Phone:  +1 716 673-1250
cloos@ACSU.Buffalo.EDU          Snail:  PersonalZipCode:  14048-0772, USA
cloos@ub.UUCP                   Quote:  <>
[ RETURN TO DIRECTORY ]