www.delorie.com/gnu/docs/units/units_8.html   search  
Buy GNU books!

Units: A Unit Conversion Program

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

8. Defining nonlinear units

Some units conversions of interest are nonlinear; for example, temperature conversions between the Fahrenheit and Celsius scales cannot be done by simply multiplying by conversions factors.

When you give a linear unit definition such as `inch 2.54 cm' you are providing information that units uses to convert values in inches into primitive units of meters. For nonlinear units, you give a functional definition that provides the same information.

Nonlinear units are represented using a functional notation. It is best to regard this notation not as a function call but as a way of adding units to a number, much the same way that writing a linear unit name after a number adds units to that number. Internally, nonlinear units are defined by a pair of functions which convert to and from linear units in the data file, so that an eventual conversion to primitive units is possible.

Here is an example nonlinear unit definition:

tempF(x) [1;K] (x+(-32)) degF + stdtemp ; (tempF+(-stdtemp))/degF + 32

A nonlinear unit definition comprises a unit name, a dummy parameter name, two functions, and two corresponding units. The functions tell units how to convert to and from the new unit. In order to produce valid results, the arguments of these functions need to have the correct dimensions. To facilitate error checking, you may specify the dimensions.

The definition begins with the unit name followed immediately (with no spaces) by a `(' character. In parentheses is the name of the parameter. Next is an optional specification of the units required by the functions in this definition. In the example above, the `tempF' function requires an input argument conformable with `1'. For normal nonlinear units definitions the forward function will always take a dimensionless argument. The inverse function requires an input argument conformable with `K'. In general the inverse function will need units that match the quantity measured by your nonlinear unit. The sole purpose of the expression in brackets to enable units to perform error checking on function arguments.

Next the function definitions appear. In the example above, the `tempF' function is defined by

    tempF(x) = (x+(-32)) degF + stdtemp

This gives a rule for converting `x' in the units `tempF' to linear units of absolute temperature, which makes it possible to convert from tempF to other units.

In order to make conversions to Fahrenheit possible, you must give a rule for the inverse conversions. The inverse will be `x(tempF)' and its definition appears after a `;' character. In our example, the inverse is

    x(tempF) = (tempF+(-stdtemp))/degF + 32

This inverse definition takes an absolute temperature as its argument and converts it to the Fahrenheit temperature. The inverse can be omitted by leaving out the `;' character, but then conversions to the unit will be impossible. If the inverse is omitted then the `--check' option will display a warning. It is up to you to calculate and enter the correct inverse function to obtain proper conversions. The `--check' option tests the inverse at one point and print an error if it is not valid there, but this is not a guarantee that your inverse is correct.

If you wish to make synonyms for nonlinear units, you still need to define both the forward and inverse functions. Inverse functions can be obtained using the `~' operator. So to create a synonym for `tempF' you could write

    fahrenheit(x) [1;K] tempF(x); ~tempF(fahrenheit)

You may occasionally wish to define a function that operates on units. This can be done using a nonlinear unit definition. For example, the definition below provides conversion between radius and the area of a circle. Note that this definition requires a length as input and produces an area as output, as indicated by the specification in brackets.

    circlearea(r) [m;m^2] pi r^2 ; sqrt(circlearea/pi)

Sometimes you may be interested in a piecewise linear unit such as many wire gauges. Piecewise linear units can be defined by specifying conversions to linear units on a list of points. Conversion at other points will be done by linear interpolation. A partial definition of zinc gauge is

    zincgauge[in] 1 0.002, 10 0.02, 15 0.04, 19 0.06, 23 0.1

In this example, `zincgauge' is the name of the piecewise linear unit. The definition of such a unit is indicated by the embedded `[' character. After the bracket, you should indicate the units to be attached to the numbers in the table. No spaces can appear before the `]' character, so a definition like `foo[kg meters]' is illegal; instead write `foo[kg*meters]'. The definition of the unit consists of a list of pairs optionally separated by commas. This list defines a function for converting from the piecewise linear unit to linear units. The first item in each pair is the function argument; the second item is the value of the function at that argument (in the units specified in brackets). In this example, we define `zincgauge' at five points. For example, we set `zincgauge(1)' equal to `0.002 in'. Definitions like this may be more readable if written using continuation characters as

    zincgauge[in] \
         1 0.002  \
        10 0.02   \
        15 0.04   \
        19 0.06   \
        23 0.1

With the preceeding definition, the following conversion can be performed:

    You have: zincgauge(10)
    You want: in
        * 0.02
        / 50
    You have: .01 inch
    You want: zincgauge

If you define a piecewise linear unit that is not strictly monotonic, then the inverse will not be well defined. If the inverse is requested for such a unit, units will return the smallest inverse. The `--check' option will print a warning if a non-monotonic piecewise linear unit is encountered.

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

  webmaster     delorie software   privacy  
  Copyright 2003   by The Free Software Foundation     Updated Jun 2003