Physics::Unit - Manipulate physics units and dimensions.
use Physics::Unit ':ALL'; # exports all util. function names # Define your own unit named "ff" $ff = new Physics::Unit('furlong / fortnight', 'ff'); print $ff->type, "\n"; # prints: Speed # Convert to mph; this prints: One ff is 0.0003720... miles per hour print "One ", $ff->name, " is ", $ff->convert('mph'), " miles per hour\n"; # Get canonical string representation print $ff->expanded, "\n"; # prints: 0.0001663... m s^-1 # More intricate unit expression (using the newly defined unit 'ff'): $gonzo = new Physics::Unit "13 square millimeters per ff"; print $gonzo->expanded, "\n"; # prints: 0.07816... m s # Doing arithmetic maintains the types of units $m = $ff->copy->times("5 kg"); print "This ", $m->type, " unit is ", $m->ToString, "\n"; # prints: This Momentum unit is 0.8315... m gm s^-1
These modules provide classes for the representation of physical units and quantities, as well as a large library of predefined Physics::Unit objects. New units and quantities can be created with simple human-readable expressions (for example,
cubic meters per second). The resultant objects can then be manipulated arithmetically, with the dimensionality correctly maintained.
Physics::Unit objects generally represent standard, named units, like meter or electronvolt. Physics::Unit::Scalar and related classes, on the other hand, are used to represent various quantities that might occur as the result of a measurement or a specification, like "5.7 meters" or "7.4 teraelectronvolts".
A Physics::Unit object has a list of names, a dimensionality, and a magnitude. For example, the SI unit of force is the newton. In this module, it can be referred to with any of the names newton, nt, or newtons. It's dimensionality is that of a force: mass X distance / time^2. It's magnitude is 1000, which expresses how large it is in terms of the unprefixed base units gram, meter, and second.
Units are created through the use of unit expressions, which allow you to combine previously defined named units in new and interesting ways. In the synopsis above,
furlong / fortnight is a unit expression.
Units that have the same dimensionality (for example, acres and square kilometers) can be compared, and converted from one to the other.
Describes the Scalar class and all of the type-specific classes that derive from Scalar.
Describes the command-line utility that is included with this module.
Table of all of the units predefined in the unit library, alphabetically by name.
Tables listing all the units in the unit library, grouped by type.
Describes some implementation details for the Unit module.
Implementation details for the Scalar module.
A Unit can have one or more names associated with it, or it can be unnamed (anonymous). Named units are immutable. This ensures that expressions used to derive other Units will remain consistent. The values of anonymous Unit objects, however, can change.
Among named Units, there are three types: prefixes (for example, "kilo", "mega", etc.), base units, and derived units.
A prefix Unit is a special-case dimensionless Unit object that can be used in expressions attached to other Unit names with no intervening whitespace. For example, "kilogram" is a unit expression that uses the prefix kilo. For more details about the use of prefixes, see "Unit Expressions", below.
A base unit is one that defines a new base dimension. For example, the Unit meter is a base unit; it defines the dimension for Distance. The predefined unit library defines nine base units, for each of nine fundamental quantities. See "InitBaseUnit()" below for a list.
A derived Unit is one that is built up from other named Units, using a unit expression. Most Units are derived Units.
The terms base dimension and derived dimension (or derived type) are sometimes used. Distance is an example of a base dimension. It is not derived from any other set of dimensional quantities. Speed, however, is a derived dimension (or derived type), corresponding to Distance / Time.
Unit names are not allowed to contain whitespace, or any of the characters ^, *, /, (, or ). Case is not significant. Also, they may not begin with any sequence of characters that could be interpreted as a decimal number. Furthermore, the following reserved words are not allowed as unit names: per, square, sq, cubic, squared, or cubed. Other than that, pretty much anything goes.
Unit expressions allow you to create new Unit objects from the set of existing named Units. Some examples of unit expressions are:
megaparsec / femtosecond kg / feet^2 sec square millimeter kilogram meters per second squared
The operators allowed in unit expressions are, in order from high to low precedence:
Any prefix that is attached to a Unit name is applied to that Unit immediately (highest precedence). Note that if there is whitespace between the prefix and the Unit name, this would be the space operator, which is not the same (see below).
The unit library comes with a rather complete set of predefined SI prefixes; see the UnitsByType page.
The prefixes are allowed before units, or by themselves. Thus, these are equivalent:
(megameter) (mega meter)
But note that when used in expressions, there can be subtle differences, because the precedence of the prefix operation is higher than the space operator. So
square megameter is a unit of area, but
square mega meter is a unit of distance (equal to 10^12 meters).
Square or cube the next thing on the line
Square or cube the previous thing on the line.
Exponentiation (must be to an integral power)
Any amount of whitespace between units is considered a multiplication
Multiplication or division
Can be used to override the precedence of any of the operators.
For the most part, this precedence order lets you write unit expressions in a natural way. For example, note that the space operator has higher precedence than '*', '/', or 'per'. Thus "
meters/sec sec" is a unit of acceleration, but "
meters/sec*sec" is not. The latter is equivalent to just 'meters'.
This is the approximate grammar used by the parser.
expr : term | term '/' expr | term '*' expr | term 'per' expr term : factor | term <whitespace> factor factor : primary | primary '**' integer primary : number | word | '(' expr ')' | 'square' primary | 'sq' primary | 'cubic' primary | primary 'squared' | primary 'cubed'
A pound is a unit of force. I was very much tempted to make it a unit of mass, since that is the way it is used in everyday speech, but I just couldn't do it. The everyday pound, then, is named pound-mass, lbm, lbms, or pounds-mass.
However, I couldn't bring myself to do the same thing to all the other American units derived from a pound. Therefore, ounce, ton, long-ton, and hundredweight are all units of mass.
A few physical constants were defined as Unit objects. This list is very restricted, however. I limited them to physical constants which really qualify as universal, according to (as much as I know of) the laws of physics, and a few constants which have been defined by international agreement. Thus, they are:
A few unit names and abbreviations had to be changed in order to avoid name conflicts. These are:
By default, this module exports nothing. You can request all of the functions to be exported as follows:
use Physics::Unit ':ALL';
Or, you can just get specific ones. For example:
use Physics::Unit qw( GetUnit ListUnits );
This function is used to define any number of new, fundamental, independent dimensional quantities. Each such quantity is represented by a Unit object, which must have at least one name. From these base units, all the units in the system are derived.
The library is initialized to know about nine base quantities. These quantities, and the base units which represent them, are:
More base quantities can be added at run-time, by calling this function. The arguments to this function are in pairs. Each pair consists of a type name followed by a reference to an array. The array consists of a list of names which can be used to reference the unit. For example:
InitBaseUnit('Beauty' => ['sonja', 'sonjas', 'yh']);
This defines a new basic physical type, called Beauty. This also causes the creation of a single new Unit object, which has three names: sonja, sonjas, and yh. The type Beauty is refered to as a base type. The Unit sonja is refered to as the base unit corresponding to the type Beauty.
After defining a new base Unit and type, you can then create other Units derived from this Unit, and other types derived from this type.
This function defines new prefixes. For example:
InitPrefix('gonzo' => 1e100, 'piccolo' => 1e-100);
From then on, you can use those prefixes to define new units, as in:
$beautification_rate = new Physics::Unit('5 piccolosonjas / hour');
This function creates one or more new named Units. This is called at compile time to initialize the module with all the predefined units. It may also be called by users at runtime, to expand the unit system. For example:
InitUnit( ['chris', 'cfm'] => '3 piccolosonjas' );
creates another Unit of type Beauty equal to 3e-100 sonjas.
Both this utility function and the
new class method can be used to create new, named Unit objects. Units created with
InitUnit must have a name, however, whereas
new can be used to create anonymous Unit objects.
In this function and in others, an argument that specifies a Unit (a "unitDef") can be given either as Unit object, a single Unit name, or a unit expression. So, for example, these are the same:
InitUnit( ['mycron'], '3600 sec' ); InitUnit( ['mycron'], 'hour' ); InitUnit( ['mycron'], GetUnit('hour') );
No forward references are allowed.
Use this function to define derived types. For example:
InitTypes( 'Blooming' => 'sonja / year' );
defines a new type that for a rate of change of Beauty with time.
This function associates a type name with a specific dimensionality. The magnitude of the Unit is not used.
Returns a Unit object associated with the the argument passed in. The argument can either be a Unit object (in which case it is simply returned), a unit name (in which case the name is looked up and a reference to the corresponding Unit is returns), or a unit expression (in which case a new Unit object is created and a reference to it is returned).
Returns a list of all Unit names known, sorted alphabetically.
Returns a list of all the quantity types known to the library, sorted alphabetically.
Returns the number of base dimension units.
Returns the Unit object corresponding to a given type name, or undef if the type is not recognized.
Deletes the names indicated by the argument, which can either be a list of names, a reference to array of names, or a Unit object. If the argument is a Unit object, then all the names of that Unit are deleted.
This provides a mechanism to override specific definitions in the default unit library. Use with this with caution. If existing Unit objects had been constructed using these names, the
def value of those Units would be rendered invalid when these names are removed.
This method creates a new Unit object. The names are optional. If more than one name is given, the first is the "primary name", which means it is the one returned by the
Unit names must be unique. See the UnitsByName page to see an alphabetical list of all the pre-defined unit names.
If no names are given, then an anonymous Unit is created. Note that another way of creating new anonymous Units is with the
GetUnit() function. Unlike GetUnit(), however, the new method always creates a new object.
# Create a new, named unit: $u = new Physics::Unit ('3 pi furlongs', 'gorkon');
Get or set this Unit's type.
print GetUnit('rod')->type, "\n"; # 'Distance'
Usually it will not be necessary to set a Unit's type. The type is normally determined uniquely from the dimensionality. However, occasionally, more than one type can match a given Unit's dimensionality.
For example, Torque and Energy have the same dimensionality. In that case, all of the predefined, named Units are explicitly designated to be one type or the other. For example, the Unit newton is defined to have the type Energy. See the UnitsByType page to see which Units are defined as Energy and which as Torque.
If you create a new Unit object that has this dimensionality, then it will be necessary to explicitly specify which type that Unit object is.
When this method is called to set the Unit's type, only one type string argument is allowed, and it must be a predefined type name (see
This method returns one of:
no type was found to match the unit's dimensionality
in the special case where the unit is a named prefix
the prototype unit for this type name matches the unit's dimensionality
more than one type was found to match the unit's dimensionality
$u1 = new Physics::Unit('kg m^2/s^2'); $t = $u1->type; # ['Energy', 'Torque'] $u1->type('Energy'); # This establishes the type once and for all $t = $u1->type; # 'Energy' # Create a new copy of a predefined, typed unit: $u3 = GetUnit('joule')->new; $t = $u3->type; # 'Energy'
Returns the primary name of the Unit. If this Unit has no names, then
Returns the shortest name of the Unit. If this Unit has no names,
Returns a list of names that can be used to reference the Unit. Returns the empty list if the Unit is unnamed.
Returns the string that was used to define this Unit. Note that if the Unit has been manipulated with any of the arithmetic methods, then the
def method will return
undef, since the definition string is no longer a valid definition of the Unit.
Produces a string representation of the Unit, in terms of the base Units. For example:
print GetUnit('calorie')->expanded, "\n"; # "4184 m^2 gm s^-2"
There are several ways to serialize a Unit object to a string. This method is designed to give you what you usually want, and to always give something meaningful.
If the object is named, this does the same as the
name() method above. Otherwise, if the object's definition string is still valid, this does the same as the
def() method above. Otherwise, this does the same thing as the
Get or set the Unit's conversion factor (magnitude). If this is used to set a Unit's factor, then the Unit object must be anonymous.
Returns the number which converts this Unit to another. The types of the Units must match. For example:
print GetUnit('mile')->convert('foot'), "\n"; # 5280
Multiply this object by the given Unit. This will, in general, change a Unit's dimensionality, and hence its type.
Replaced a Unit with its reciprocal. This will, in general, change a Unit's dimensionality, and hence its type.
Divide this object by the given Unit. This will, in general, change a Unit's dimensionality, and hence its type.
$u = new Physics::Unit('36 m^2'); $u->divide('3 meters'); # now '12 m' $u->divide(3); # now '4 m' $u->divide('.5 sec'); # now '8 m/s'
Raises a Unit to an integral power. This will, in general, change its dimensionality, and hence its type.
Add a Unit, which must be of the same type.
Replace a Unit with its arithmetic negative.
Subtract a Unit, which must be of the same type.
This creates a copy of an existing Unit, without copying the names. So you are free to modify the copy (while modification of named Units is verboten). If the type of the existing Unit is well-defined, then it, also, is copied.
This is the same as the new method, when new is called as an object method with no names.
This returns 1 if the two Unit objects have the same type and the same magnitude.
Here are some other modules that might fit your needs better than this one:
Written by Chris Maloney <email@example.com>
Special thanks for major contributions and encouragement from Joel Berger. Thanks also to Ben Bullock, and initial help in formatting for distribution from Gene Boggs <firstname.lastname@example.org>.
Copyright 2002-2003 by Chris Maloney
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.