SI Units
Checked and Unchecked

Christoph Grein
http://home.T-Online.de/home/Christ-Usch.Grein/

Original Version  9 September 2002
Last Update  12 March 2003

In From The Big Bang To The Universe, I have shown that Ada is not suited to implementing physical dimensions with its type concept. Therefore a method was presented applicable also to hard real-time systems which gives up dimension checking within the SI units system, while keeping the advantages of strong typing in critical cases when units from different systems have to be mixed. And indeed, this method has been in use in several avionics projects for more than a decade.

But the request to have full dimensional checking persists as can be seen from the pertinent discussions in newsgroup Comp.Lang.Ada. There are two basic ways one can try to solve the problem, either by adding to the numeric value its dimension as attribute, or by using different types for different dimensions. Since the first method is runtime-consuming, whereas the second one is only compiletime-consuming, all effort naturally concentrates on the second method. This is doomed to fail as is shown in the paper cited above - although a plethora of overloaded operations is used, the result is not really satisfactory. Physical equations with all their powers and roots evade these attempts.

So here a different method is presented to deal with physical items in full generality by adding to the value its dimension as an attribute, i.e. the first way rejected above because of its runtime-expensiveness. Hence this method might appear prohibitive for use in hard real-time systems. This is not the case!

By changing only a few lines of code, dimensions can be switched off, leaving the program, however big it may be, with only the pure numerics.

The method comes in two variants, unconstrained and constrained:

Both variants differ only in the declaration of objects; expressions and assignments look the same.

Test programs for all packages presented below can be found in the subdirectory Test.

1. Unconstrained

The first variant uses the type declaration

  type Item is private;

where the full declaration composes the physical item of dimension and value, where the values for the SI base units Meter, Kilogram, Second, Ampere, Kelvin, Candela, Mole are rational numbers representing the exponent (e.g. m2). We have to use rational numbers because we want ot be able to represent the most general physical equations.

  type Dimension is record
    m, kg, s, A, K, cd, mol: Rational;
  end record;

  type Item is record
    Unit : Dimension;
    Value: Real;
  end record;

Two implementations are provided: The package hierarchy

  Unconstrained_Checked_SI
  Unconstrained_Checked_SI.Generic_Item_Subtype
  Unconstrained_Checked_SI.Generic_Units
  Unconstrained_Checked_SI.Generic_Text_IO
  Unconstrained_Checked_SI.Generic_Temperatures
  Unconstrained_Checked_SI.Generic_Temperatures.Generic_Text_IO
  Unconstrained_Checked_SI.Generic_Polynomial_Numerics
  Unconstrained_Checked_SI.Generic_Vector_Space
  Unconstrained_Checked_SI.Generic_Natural_Constants
  Unconstrained_Checked_SI.Generic_Non_SI_Units

provides operations for dealing with checked dimensions (the last two packages are only proposals for further additions and do not appear in the other variants).

The package Unconstrained_Checked_SI defines the private SI base type Item as shown above and all operations on it, including mathematical functions. Several children are defined:

Since the type Item is private, no subtypes with range constraints can be defined. The child package Generic_Item_Subtype provides a substitute. It allows to define a new type Constrained with a range constraint and provides operations that make Constrained completely compatible with Item so that virtually there is no difference to using Ada subtypes.

The child package Generic_Units defines all derived units like Newton and Tesla.

The child package Generic_Text_IO defines facilities like those in Ada.Text_IO.Float_IO, but includes the dimension. Like the Ada prefined input operations, the corresponding operations leave the offending character in the input stream when Data_Error is raised.

The child packages Generic_Temperatures and Generic_Temperatures.Generic_Text_IO define the temparture scales Celsius, Fahrenheit, Rankine, and Reaumur and the correpsonding dimensioned IO operations.

The child package Generic_Polynomial_Numerics defines operations for polynomials, linear interpolation and second order curve approximation.

The child package Generic_Vector_Space defines operations for 3-dimensional vectors (inner and cross products, matrix multiplication). Neither the inner nor the cross product of vectors are defined as operators to avoid ambiguities. The procedure Ambiguities in the subdirectory Examples shows the kind of ambiguities that would be present if they were defined as operators. This package is not a linear algebraics package.

These packages can very easily be replaced by the corresponding ones in the parallel hierarchy

  Unconstrained_Unchecked_SI
  Unconstrained_Unchecked_SI.Generic_Item_Subtype
  Unconstrained_Unchecked_SI.Generic_Units
  Unconstrained_Unchecked_SI.Generic_Text_IO
  Unconstrained_Unchecked_SI.Generic_Temperatures
  Unconstrained_Unchecked_SI.Generic_Temperatures.Generic_Text_IO
  Unconstrained_Unchecked_SI.Generic_Polynomial_Numerics
  Unconstrained_Unchecked_SI.Generic_Vector_Space

which have exactly the same visible specifications, but replace the full declaration of items by only its value:

  type Item is record
    Value: Real;
  end record;

The program Physical_Computations_Unconstrained in the subdirectory Examples shows how this is done. You really only have to change at most three lines of code, however big your whole program may be.

While this variant provides full internal consistency, an object's dimension may change:

  Dist: Item := 5.0 * Meter;
  Dist := Dist / (2.0 * Second);

Now Dist, contrary to its name, has the dimension [m/s]. This is why this variant is called the unconstrained variant.

2. Constrained

In the constrained variant, the declaration of Item adds an unknown discriminant

  type Item (<>) is private;

The full declaration uses the unconstrained item as above and adds numerator and denominator of each basic unit as discriminants:

  package SI is new Unconstrained_Checked_SI (Real);

  type Item (m_N, kg_N, s_N, A_N, K_N, cd_N, mol_N: Whole;
             m_D, kg_D, s_D, A_D, K_D, cd_D, mol_D: Positive_Whole) is record
    Inner: SI.Item;
  end record;

This prevents changes of dimension after declaration; assignments like the one above with Dist will inevitably raise an exception.

The two package hierarchies are

  Constrained_Checked_SI
  Constrained_Checked_SI.Generic_Item_Subtype
  Constrained_Checked_SI.Generic_Units
  Constrained_Checked_SI.Generic_Text_IO
  Constrained_Checked_SI.Generic_Temperatures
  Constrained_Checked_SI.Generic_Temperatures.Generic_Text_IO
  Constrained_Checked_SI.Generic_Polynomial_Numerics
  Constrained_Checked_SI.Generic_Vector_Space

and

  Constrained_Unchecked_SI
  Constrained_Unchecked_SI.Generic_Item_Subtype
  Constrained_Unchecked_SI.Generic_Units
  Constrained_Unchecked_SI.Generic_Text_IO
  Constrained_Unchecked_SI.Generic_Temperatures
  Constrained_Unchecked_SI.Generic_Temperatures.Generic_Text_IO
  Constrained_Unchecked_SI.Generic_Polynomial_Numerics
  Constrained_Unchecked_SI.Generic_Vector_Space

The program Physical_Computations_Constrained in the subdirectory Examples shows how this package is used. Again exchange of checked and unchecked is done with the same few changes as above.

While this variant prevents changes of dimension, its major drawback is that arrays of items cannot be defined:

  type Vector is array (Natural range <>) of Item;  -- illegal

This is why the child package Generic_Polynomial_Numerics has a specification different from the unconstrained one. The program Test_Constrained_Polynomial_Numerics in directory Test shows how to use it. Also for Generic_Vector_Space, something special has been invented, again using unknown discriminants.

3. Measurements

There is a program to measure the computation speeds in directory Examples. The relative results are as follows:

Constrained Checked 15.8
Unchecked 1.2
Unconstrained Checked 9.8
Unchecked 1.0

These figures are for the full set of SI base units. The packages are easily customizable by commenting out the less frequently used units (Mole, Candela, Kelvin), which should increase the speed accordingly.

4. Licencing

The software is published under the Gnat Modified GPL, see file gpl.txt and the header of each compilation unit.

5. Download

Download from here.
If you have however Gnat in a version before 3.16w, you need some work-arounds for compiler bugs like qualified expressions Rational'(-2/3) instead of the simple (rational) expression -2/3 (the compiler will tell you where).


This work has been published in Softwaretechnik-Trends Vol. 22.4 (November 2002), the periodical of Ada-Deutschland, special interest group 2.1.5 Ada within Gesellschaft für Informatik, the German Informatics Society.


All about SI units and general information about the foundation of modern science and technology can be found at the National Institute of Standards and Technology.


Updates Reason
12 March 2003 IO customization improved.
26 February 2003 Generic_Polynomial_Numerics in the constrained family is new.
With the advent of Gnat 3.16a, the last work-arounds could be removed except one in program Measure in directory Examples.
4 February 2003 Syntax for reading unit symbols changed; it now resembles the reading of enumeration literals. Only input raising Data_Error is treated differently.
20 December 2002 Added subtyping capability for all variants, vector arithmetics for the unconstrained variant.
Added the volume of Softwaretechnik-Trends in which this work was published.
21 October 2002 XHTML successfully validated with W3C validation facility. No functional change.
14 October 2002 Graphic files were missing in zip file.
11 October 2002 Temperature scales Celsius, Fahrenheit, Rankine, Réaumur added.
27 September 2002 Some of the work-arounds for a Gnat 3.14p bug could be removed with the arrival of 3.16w.
15 September 2002 Added unit Katal and a link to the NIST.
The argument of trigonometric functions with cycle parameter can be dimensioned.
9 September 2002 First release.

English Home Contents
Deutsch Inhaltsverzeichnis
welcome homepage

Valid XHTML 1.0 Transitional!