Checking C++ Programs for Dimensional Consistency
Ingo Josopait
Astrophysikalisches Institut Potsdam, 14482 Potsdam, Germany
I will present my implementation ’n-units’ of physical units into C++ programs. It allows the
compiler to check for dimensional consistency.

arXiv:cs/0512026v1 [] 7 Dec 2005

I.

INTRODUCTION

Computer simulations and other scientific programs often deal with physical quantities that have dimensional
meanings, like length scales or time scales. The internal representation of such quantities is done by floating point
numbers. The actual numbers have no direct meaning by themselves. Their meanings rely on the definition of the
measuring units (for example, the length ’5 meters’ could equally well be written as ’500 centimeters’ or ’16.4 feet’).
The addition, subtraction or comparison of two numbers of different dimensions, like time scales and length scales, is
physically not meaningful and can be regarded as an error. This follows from the principle of dimensional invariance,
i.e. from the demand that the meaning of a formula should not depend on the choice of the system of measuring
units. Dimensional inconsistencies are a frequent source of errors in programs and much debugging time is usually
spent to check a program for dimensional consistency.
However, the checking for dimensional consistency can be done automatically [1, 5]. Implementations of units into
programming languages like python [3] and C++ [2, 6] exist.
I will present another implementation of units into the programming language C++. The source code is available
at http://starburst.sourceforge.net/n-units/. The emphasis lies on computational speed. As in [2] and [6], a
check for dimensional consistency is done at compile time.
The main differences to these existing implementations are:
• Checking for dimensional consistency is designed to be deactivated for production runs, which results in better
runtime performance (and reduced compile time).
• Template definitions are simplified and the set of base units can easily be extended.
• A function is provided that takes quantities to a fractional power.
II.

DIMENSIONS, UNITS AND QUANTITIES

Let me first give 3 definitions:
a. quantity A quantity is a property of some kind that can be quantified (e.g. the height of an object or its
velocity).
b. dimension A dimension specifies the type of a quantity (e.g. a length scale or a time scale). Only quantities
of the same dimension can be compared.
c. unit A unit is a quantity that has been defined in order to measure other quantities and to be able to express
them in terms of numbers. Quantities can then be expressed as multiples of units. More than one unit can be defined
per dimension. For example, cm, m and feet are all units that represent length scales.
There are typically at least 3 independent dimensions used in a computer simulation:
• length scale
• mass scale
• time scale
This set can be extended. The Système International d’unités (SI) is based on 7 base units. But also other dimensions
like currencies, the amount of information (in bits or bytes), or the cosmological scale factor can be used. More complex
units (like energies or velocities) are derived from the base units.

2
III.

CHECKING FOR DIMENSIONAL CONSISTENCY

A dimension is uniquely defined by the exponents of the base units. For example, velocities (cm1 s−1 ) are composed
of a length scale of exponent 1 and a time scale of exponent -1. This can formally be expressed by vectors: If we
represent length scales by the vector (1,0,0), mass scales by (0,1,0) and time scales by (0,0,1), velocities would be
represented by the vector (1,0,-1).
For practical purposes it is sufficient to use a single integer number to represent the dimensional class. This has
two advantages:
• Template definitions are simplified.
• Additional base units can be easily defined.
Quantities are represented by the following template class:
template <int n, class T=double> struct units
{
T data;
static units<n, T> construct(const T& a)
{
// somewhat hidden constructor for explicit use
units<n, T> r;
r.data = a;
return r;
}
...
};
The template parameter n specifies the dimension of the quantity, and T specifies the underlying floating point type.
A.

Base Units

The base units are defined in the following way (as a convention, all units end with an underscore):
Length scale: const units<1> m_ = units<1>::construct(1);
Mass scale: const units<10> g_ = units<10>::construct(1E-3);
Time scale: const units<100> s_ = units<100>::construct(1);
...
This would define that the actual floating point representation follows the SI system (numbers are given in meters,
kilograms and seconds) and that the dimensions of length scale, mass scale and time scale are represented by the
template parameters 1, 10 and 100, respectively.
Note that with the above definition the compiler cannot distinguish between, for instance, cm10 and g. Since such
large exponents of units are rare, however, it is unlikely that this will be of practical importance.
B.

Basic Operations

The following operations between quantities are allowed:
• Addition and subtraction are allowed between quantities of the same dimension.
• Multiplication of two quantities of types units<m> and units<n> returns a quantity of type units<m + n>.
• Dividing a quantity of type units<m> by a quantity of type units<n> returns a quantity of type units<m − n>.
• Relational operators (==, <, >) are allowed between quantities of the same dimension.
In the framework of C++ templates, this can be written as:

3
template <int n, class T=double> struct units
{
...
template
template
template
template

<class B> units<n, typename addtype<T,B>::type> operator +
<class B> units<n, typename subtype<T,B>::type> operator <int nb, class B> units<n+nb, typename multype<T,B>::type>
<int nb, class B> units<n-nb, typename divtype<T,B>::type>

(const units<n, B>& b) const;
(const units<n, B>& b) const;
operator * (const units<nb, B>& b) const;
operator / (const units<nb,B>& b) const;

...
};

The classes addtype, subtype, multype and divtype are used to correctly determine the return type of the
underlying floating point number (so that, for instance, operations involving a float and a double always return a
double).
The dimensionless type units<0> is never used. Specializations of the above operators ensure that a bare floating
point number (such as double or float) is returned instead.
C.

Fractional Powers

Taking fractional powers of quantities can be defined in the following way:
• Taking the square root of a quantity of type units<n> returns a quantity of type units<n/2>.
• More generally, taking a quantity of type units<n> to the fractional power
units<n qp >.

p
q

returns a quantity of type

For this purpose, the following template functions are provided:
template <int n, class T> units<n/2, T> sqrt(const units<n, T>& a);
template <int pa, int pb, int n, class T> units<(pa*n)/pb, T> pow(const units<n, T>& a);
The expression ap/q can then be written as pow<p,q>(a), where p and q are constant integers. Apart from the
possibility to check for dimensional correctness, another advantage of using the above pow<> template function is that
the exponent pq is known to the compiler. The template function pow<> can therefore attempt to use the standard
functions sqrt(double) (which takes the square root) and cbrt(double) (which takes the cubic root) in order to
avoid the considerably slower function double pow(double, double).
D.

Data Types

The dimension has to be specified for every quantity in the program. The typeof extension of the gcc compiler is
very useful for this. typeof(x) returns the type of the object x. A velocity variable, for instance, can be defined by
typeof(cm_/s_) v

= 5*m_/s_;

Because the units are defined to be constant, typeof expressions that involve only one unit should be written as a
product to remove the constness. A length h should therefore be defined as:
typeof(1*cm_) h = 2*km_;
Unfortunately, the typeof keyword is not part of the ISO C++ standard. However, it is possible to emulate the
typeof extension [4] with the help of the sizeof keyword (which is part of the ISO C++ specification), at the
cost of having to register every type (and dimension) to which typeof is applied. To emulate typeof, disable the
HAVE_TYPEOF option in the header file.
The following small sample program illustrates the use of units in a program. It calculates the time a slice of bread
needs to fall from a table (of height 1 meter) to the floor.
#include <iostream>
#include "units.h"
using namespace std;

4

int main()
{
typeof(1*cm_) height = 1*m_;
typeof(cm_/s_/s_) g = 9.81*m_/s_/s_;
typeof(1*s_) t = sqrt(2*height/g);
cout << "free fall time=" << t/s_ << " seconds" << endl;
}
Any violation of dimensional consistency would trigger a compiler error.
IV.

DISABLED CHECKING

Dimensional checking can be disabled by the preprocessor option UNITCHECK in the header file. For performance
reasons it is advisable to disable it for production runs and to enable it only to check newly written code. If UNITCHECK
is disabled, the definitions of the base units (see section III A) are replaced by constant floating point numbers:
const double m_ = 1;
const double g_ = 1E-3;
const double s_ = 1;
...
The use of units will then have no negative influence on the runtime performance.
I would like to stress that even though the compile-time check of units in this implementation relies on the use of
template classes, units that are not checked for dimensional consistency can still be used in virtually any programming
language, simply by defining the corresponding units as constant floating point numbers.
V.

DERIVING ADDITIONAL UNITS

Once the set of base units is defined, other units can be derived from it, like for example:
const
const
const
const

typeof(1*m_) cm_ = m_/100;
typeof(1*g_) kg_ = 1000*g_;
typeof(kg_*m_*m_/s_/s_) J_ = kg_*m_*m_/s_/s_;
typeof(m_/s_) c_ = 2.99792458e8 * m_ / s_;

//
//
//
//

centimeter
kilogram
Joule
speed of light

Given these definitions, units can be used directly in a program. One does not need to know the set of underlying
measuring units that is used to represent quantities. Even the combination of different units is possible. For example,
the following expression is perfectly valid:
typeof(1*cm_) height = 1*m_ + 75*cm_;
The compiler will correctly add these two length scales. Since the system of base units is known at compile time, the
compiler can optimize this expression and perform the calculation during the compilation.
VI.

CHOOSING THE BASE TYPE

Sometimes the programmer wants to use a specific base type other than double, like float or complex<>. This
can be accomplished either by explicitly using cm_f (float), cm_d (double) or cm_ld (long double) instead of cm_
(which defaults to double) or by using the tof(..), tod(..), told(..) or to<> functions. For instance,
typeof(cm_f/s_f) v;
and
typeof(tof(cm_/s_)) v;
both define the velocity v to be of type float.

5
VII.

OUTPUT

Since UNITCHECK should be deactivated for production runs, the compiler has no information about the dimensions
of quantities. Therefore, the programmer has to take care of meaningful output of quantities. This can be done by
dividing the quantity by the desired unit, for example:
void foo(typeof(m_/s_) v)
{
cout << "v = " << v/(mile_/hour_) << " mph" << endl;
}
VIII.

CONCLUSIONS

I have presented an implementation of physical units into C++ programs. The code is checked for dimensional
consistency at compile time. The main advantages of this are:
• The programmer can use units directly in the code, without the need to know the system of base units.
• Implementing complex formulae is simplified, because the programmer can be more relaxed about the dimensional correctness.
• Dimensional correctness is guaranteed by the provided header files.

[1] Eric Allen, David Chase, Victor Luchangco, Jan-Willem Maessen, and Jr. Guy L. Steele. Object-oriented units of measurement. In OOPSLA ’04: Proceedings of the 19th annual ACM SIGPLAN conference on Object-oriented programming,
systems, languages, and applications, pages 384–403, New York, NY, USA, 2004. ACM Press.
[2] W. Brown. Applied template metaprogramming in siunits: the library of unit-based computation. In Proceedings of the
Second Workshop on C++ Template Programming, October 2001.
[3] Pierre Denis. Unum, numbers with units in python. available at http://home.tiscali.be/be052320/Unum.html.
[4] Bill Gibbons. A portable typeof operator, 2000. http://www.accu-usa.org/2000-05-Main.html.
[5] Andrew J. Kennedy. Relational parametricity and units of measure. In POPL ’97: Proceedings of the 24th ACM SIGPLANSIGACT symposium on Principles of programming languages, pages 442–455, New York, NY, USA, 1997. ACM Press.
[6] Kasper Peeters.
dimnum, c++ library for storage and conversion of dimensionful values.
available at
http://www.damtp.cam.ac.uk/user/kp229/dimnum/.

