[comp.sys.handhelds] Generalized unit conversion on the HP48sx

austern@ux5.lbl.gov (Matt Austern) (08/02/90)

A few days ago, I posted an article saying that I'd written a
generalized form of CONVERT for the unit systems that are generally
used in high-energy physics, where we set hbar=c=1.  I asked for
suggestions about a better way to do one step, which I was doing by a
horrible kludge.

One person suggested using one of the MATCH commands.  I played with
them for a while, but couldn't find a way to make them do what I
needed.  Other than that, I have received no suggestions.  I have,
however, received several requests for my code, so here it is, kludge
and all.

The method of performing generalized unit conversion is to find out
how many powers of hbar and c are needed to make the units compatible,
do the multiplication, and then convert.

Finding out how many powers are necessary ought to be simple: take the
ratio between the two unit objects, then find out how many powers of
each base unit are in that ratio.  The rest is a little algebra.

The hard part is finding out how many powers of each base unit there
are.  That information must be there, somewhere, in the internal
representation of a unit object, but I couldn't find any way to get at
it.  So here's the disgusting part: I use UBASE to convert the unit
object to base units, then convert it to a string and do string
searches.  There must be a better way...

Here's the program, finally:

\<< DUP2 SWAP / ULST				@@@ CVT
    \-> u1 u2 rat
    \<< h rat 2 GET ^ 
	c rat 1 GET rat 2 GET2 * - ^ 
	* u1 * u2
	IFERR CONVERT THEN DROP2 u1 u2 #2818d DOERR END
    \>>
\>>	'CVT' STO

\<< UBASE \->STR DUP SIZE \-> s l		@@@ ULST
	\<< s "/" POS 
	    IF DUP 0 == THEN DROP l 1 + END
	    \-> sl
		\<< s sl "m" CNUN
		    s sl "kg" CNUN
		    s sl "s" CNUN
		    s sl "A" CNUN
		    s sl "K" CNUN
		    s sl "cd" CNUN
		    s sl "mol" CNUN
		    7 \->LIST
		\>>
	\>>
\>>     'ULST' STO

\<< \-> s sp un					@@@ UCNT
	\<< s u POS \-> pos
		\<< IF pos 0 == 
		    THEN 0
		    ELSE
			IF s pos 1 + DUP SUB "^" ==
			THEN
			    s pos 2 + DUP
                            IF s pos 3 + DUP SUB NUM DUP  
                               "0" NUM \>= SWAP "9" NUM \<=
                               AND  	@@@ This checks if power is 2 digits.
                            THEN 1 + 
                            END
                            SUB STR\->
			ELSE 1
			END
		    END
		    IF pos sp >
		    THEN NEG
		    END
		\>>
	\>>
\>>	'UCNT' STO

29979245800_cm/s	'c' STO			@@@ c
6.582122E-22_MeV*s	'h' STO			@@@ hbar


NOTES:
	(1) UCNT is very incomplete.  It won't handle negative powers;
	    however, UBASE never returns negative powers.  It also won't
	    handle fractional powers; but, again, UBASE (incorrectly)
            never returns fractional powers.  Another bug
            (easily fixable, but is it worth the trouble?) is that 
	    UCNT can't handle three-digit powers.
	(2) I don't bother checking in CVT to see if the types of the
	    two unit objects are compatible; it's easier to just let
	    CONVERT discover the error and trap it.
	(3) The value for 'c' given above is exact; the value for hbar
            is from the 1988 Review of Particle Properties.
	(4) As I said above, my implementation of ULST is disgusting.
	    Surely there must be a better way?
-- 
Matthew Austern    austern@lbl.bitnet     It's not very subtle, but, uh, 
(415) 644-2618     austern@ux5.lbl.gov    neither is blowing up a whole school.

billw@hpcvra.CV.HP.COM (William C Wickes) (08/03/90)

The program listed below converts a unit object into a list, where
the first element of the list is the unit magnitude, and the remaining
elements are the powers of the base units represented in the unit object,
in the order { kg m s A K cd mol }.

This is still not an elegant solution to Mr. Austern's problem, but
it might be a little less disgusting.  

%%HP: T(3)A(R)F(.);
\<< 1 1 1 1 1 1 1 \-> kg m s A K cd mol	@Make local variables
  \<< OBJ\-> UBASE \->STR 		@Convert normalized unit ob to string
      4 OVER SIZE SUB			@Strip off "'1_"
      "'" SWAP + OBJ\->			@Convert to an expression
      \<< 				@Start of subroutine prog
         { kg m s A K cd mol } SWAP GET @Get the ith base unit
         10 OVER STO 			@Assign it value 10
	 OVER EVAL LOG 			@Get the power of the base unit
         1 ROT STO			@Restore value 1
      \>> 				@End of subroutine prog
      { } \-> prog list			@Store prog, and an empty list
      \<< 1 7				@For each base unit:
         FOR i i prog EVAL 		@Get the power
            'list' SWAP STO+		@Add the power to the list
         NEXT 
	 DROP				@Discard the expression
	 list				@Retrieve the list
	 +				@Add the unit magnitude at the head
      \>>
   \>>
\>>

billw@hpcvra.CV.HP.COM (William C Wickes) (08/08/90)

OK, so I'm not a typist.  The OBJ\-> UBASE following the initial local
variable assignments should be UBASE OBJ\->.