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\->.