Boost logo

Boost :

From: Deane_Yang_at_[hidden]
Date: 2001-06-28 12:23:14


I've been reading and learning a lot from the boost list.
Although my experience with C++ is much less than everyone
else here, I have implemented template base classes representing
units very successfully. I have found these classes to be
extraordinarily useful in catching errors in formulas coded in C++.

Although the discussions I've seen seem to be converging to what
I consider to be the "correct" view, I thought I'd try to describe
how I see things.

1) There are basically two types of units

First, I have found that units come in two different types.
I used to call one "absolute units" and the other "relative units".
I now call them "affine units" and "linear units", because the former
corresponds to a 1-dimensional affine space, while the latter
corresponds to a 1-dimensional linear space.

Linear units are familiar to everyone. For example, any physical unit
like meters, seconds, ergs, etc. is linear. You can add, subtract, or
rescale any quantity that has linear units. In other words, a
quantity in linear units is simply an element of
a 1-dimensional vector space).

A quantity in affine units corresponds to an element of a 1-
dimensional affine space. An affine space is like a vector space
without an origin. You can't add or rescale an affine object.
There is, however, a vector space naturally associated with an affine
space. Given two affine objects, you can subtract them and get a
corresponding linear quantity.

Let me illustrate with one very useful example. The set of all
possible calendar dates is an affine space. It does not make sense to
add or rescale a date. It does, however, make sense to subtract two
of them and get a quantity in days, which is a linear quantity.

The other example was given by Dave: an iterator is an affine object,
while the difference of two iterators is a linear quantity.

By writing code that uses classes to represent unit and that
distinguishes between affine and linear units,
my compiler now catches virtually every error I make when coding
a formula in C++.

I see implementations of affine units in various specific cases,
like iterators, but I think it's worth identifying the common
abstract notion that guides all of them.

2) It is important to identify "unitless" quantities

It is obvious that the ratio of two quantities with the same units
must be unitless. What is not always so obvious is that some "units"
are really unitless quanities. The two I know about are percentage
(which is obviously a ratio) and radians.

And then there are quantities that seem unitless but are not.
The simplest example is an interest rate, which is always
stated as a percentage. To see what it really is, you just
ask yourself how it's used in a formula. The first thing you
always do is multiply the interest rate by a time and get a
ratio (interest/principal). So the units
of an interest rate are always given by 1/(time unit).

3) Transcendental functions

Any standard transcendental function, such as sin, cos, exp, log,
MUST take only unitless quantities and return unitless quantities.
If not, there is an error in the formula. You can sort of see why by
observing that these functions are computed using a Taylor series
with unitless coefficients and there is no way to have every term in
the series have the same units unless the argument is unitless.

There are logarithmic units such as decibels and pH. I'm not familiar
with how these are used in formulas. I think these are sufficiently
strange so that they should be treated specially.

Deane

--- In boost_at_y..., "David Abrahams" <david.abrahams_at_r...> wrote:
> Helmut,
>
> What you're saying makes sense, but I think we need to be careful. A
> conforming compiler will generate these functions even if unused,
so it
> could break code.
>
> Actually, I thought of a pretty strong counterexample: take a look
at
> random_access_iterator_helper. It makes sense to subtract the
distance type
> from the iterator type. Does it make sense to convert the distance
type to
> the iterator type? I don't think so.
>
> So, I think we'd better stay with what we've got, or at most, add an
> additional operator template.
>
> -Dave
> ----- Original Message -----
> From: <helmut.zeisel_at_a...>
> To: <boost_at_y...>
> Sent: Thursday, June 28, 2001 10:21 AM
> Subject: [boost] operators.hpp issue
>
>
> > In operators.hpp,
> > the commutative two-type versions of the operators,
> > such as addable2 have both versions of the operators defined:
> >
> > struct addable2 : B
> > {
> > friend T operator+(T x, const U& y) { return x += y; }
> > friend T operator+(const U& y, T x) { return x += y; }
> > };
> >
> > the non-commutative versions, such as subtractable2
> >
> > have only one version:
> >
> > struct subtractable2 : B
> > {
> > friend T operator-(T x, const U& y) { return x -= y; }
> > };
> >
> > Shouldn't there be a second version such as
> >
> > friend T operator-(const U& x, const T& y)
> >
>
> > T x1(x);
> > return x1 -= y;
> > }
> >
> > IMHO, it does not make much sense to provide the
> > two-type versions of the operators when U is not convertible to T.
> >
> > Helmut
> >
> >
> >
> >
> >
> > Info: http://www.boost.org Unsubscribe:
> <mailto:boost-unsubscribe_at_y...>
> >
> > Your use of Yahoo! Groups is subject to
http://docs.yahoo.com/info/terms/
> >
> >


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk