Units package (was Method names)

stan at stanheckman.com stan at stanheckman.com
Mon Nov 9 08:53:53 UTC 1998


I have been playing with a toy units package for squeak. It doesn't do
very much yet, just keeps units during arithmetic and tries to
simplify them when appropriate. 

I considered two methods of entering units; a bunch of methods named
"meter", "inch", and so on defined for Numbers and PhysicalQuantities,
or a collection of global symbols. I see two advantages for the named
methods: polluting the method space of Numbers is less offensive than
polluting the global namespace, and methods allow great freedom in
defining the syntax. Five meters can be entered as '5 meters', and 5
kilogram meters per second squared could be entered as the string of
messages '5 kilogram meters per second squared'. I see one advantage
of the collection of global symbols; their algebra is exactly the same
as all other algebra in Smalltalk, so there's nothing new to learn
about how to specify units of kilogram meters per second squared, it
must be '5 * Kilogram * Meter / Second squared'.  I think I prefer the
second choice, staying with standard Smalltalk syntax, but I'm
interested in reading arguments for the first. Or maybe someone sees a
better, third way?

Because I used the second method, I have the problem of deciding where
all these symbols should go. In the example below I put them in the
global namespace, but I think in the end that's not where they should
live. Ideas?

For that matter, what's the recommended way to code with such a group
of symbols? Should I just write them to the global namespace and clean
up when I'm done, or should I be using a pool, or what?

There's also the issue of how we should print the units out. I've
spelled them out in what I hope is a human readable form, but I know
from experience that many users prefer abbreviations, so they can 
see all the units at a glance, and so the units don't take up so much
space. Typeset units, with small abbreviations above and below a solidus
would be very satisfying; maybe someday, with Math Morphs...

I don't know how to do automatic unit simplification without some
linear algebra. For this purpose I hacked up Kurt Hebel's
(hebel at uinova.cerl.uiuc.edu) arithmetic package, from the Smalltalk
archive at
ftp://st.cs.uiuc.edu/pub/Smalltalk/st80_r4/arithmetic.st. I'm afraid I
made Kurt's code unbearably ugly; it doesn't look at all like
Smalltalk anymore. I'm sure someone out there could write beautiful
Gaussian elimination code if they had a good package for handling
vectors and matrices. Travis, do you still think matrices are relatively
uninteresting?

Here's a sample session cut and pasted from a workspace, illustrating
the toy units package. I've added some comments in double quotes.

-------%<--------%<--------------------------------------

"Load the symbols #Meter, #Kilogram, #Calorie, and the like. "

BasisUnit basisUnitsPoolHack
BasisUnit loadBasisUnitsIntoSmalltalk

"This package simplifies units. Let's start with a couple examples
that students sometimes have a hard time simplifying."

pi := Float pi.
vacuumPermeability := 4 * pi / 1.0e7 * Henry / Meter.
vacuumPermittivity := 8.85419e-12 * Farad / Meter.
vacuumImpedance := (vacuumPermeability / vacuumPermittivity) sqrt.
speedOfLight := 1 / (vacuumPermeability * vacuumPermittivity) sqrt.

"Note the input syntax is standard Smalltalk algebra.  Below are the
printIt's, showing the output syntax, and showing the automatic unit
simplification."

vacuumPermeability 1.256637061435917e-6 henrys per meter
vacuumPermittivity 8.85419e-12 farads per meter
vacuumImpedance 376.730267033548 ohms
speedOfLight 2.997924210535944e8 meters per second

"The package decided that we would rather see vacuumImpedance with
units of ohms than with units of sqrt(Henry/Farad), and that we would
rather see speedOfLight with units of meter per second than with units
of (Meter/sqrt(Henry Farad))."

"Now let's do a more real problem, using squeak as a calculator. We'll
solve for the rate at which the sun consumes mass to make light."

"We happen to know (or, if in school, the problem probably tells us)
that in the absence of any atmospheric losses, a flat black panel held
facing the sun receives 1370 watts per square meter."

solarConstant := 1370 * Watt / Meter squared.
 1370.0 watts per meter squared

"This energy is spread uniformly over a sphere of radius equal to the
distance from the earth to the sun. We could look up the distance from
the earth to the sun in the back of the book, but since this is a
units package, defining all sorts of obscure units, the simplest way
to express the distance to the sun is to use astronomical units. :-)"

earthSunDistance := 1 * AstronomicalUnit.
 1.000000000000002 astronomical units

"The rounding errors above made that printout ugly. :-( 
Well, onward. The surface area of a sphere is 4 pi r squared, so"

surfaceAreaOfEarthRadiusSphere := 4 * pi * earthSunDistance squared.
 12.56637061435921 astronomical units squared

"Note that here the units package leaves our units alone, because it
can't make them any simpler. "

"The total power output of the sun is this surface area times the
energy per unit area we considered at the start of the problem."

solarPowerOutput := solarConstant * surfaceAreaOfEarthRadiusSphere.
 3.85187053882097e26 watts

"We computed the speed of light at the top of this page, so using 
E = m c squared, the rate at which mass is consumed to make light is:"

solarPowerBillInKilograms := solarPowerOutput / speedOfLight squared
 4.28578502729018e9 kilograms per second

"The package guessed exactly what units we wanted to see that in. (We
were lucky; that was a hard job for the heuristics, because we hadn't
explicitly specified kilograms anywhere in the problem.)"

" Now let's pick up all our symbols and put them back in the toy
box. :-)"

BasisUnit unloadBasisUnitsFromSmalltalk

-------%<--------%<--------------------------------------

If anyone wants it, the code is available at 
 http://www.stanheckman.com/a/98h/glimpsedotter/Numeric-Units.st

In addition to the file-in above, you will need to add the following
two methods to Number:

adaptPhysicalQuantity: aPhysicalQuantity
	"If I am involved in arithmetic with an Integer, I must know 
whether to convert it."
	^ aPhysicalQuantity

adaptToPhysicalQuantity
	"If I am involved in arithmetic with a PhysicalQuantity, I must 
always be converted."
	^ PhysicalQuantity fromNumber: self

I haven't checked yet, but I suspect Dan's coercion fixes will break this
code. Just as well, the coercion of LnPhysicalUnits was ugly, and needed
a redesign. :-)

-- 
Stan





More information about the Squeak-dev mailing list