Boost logo

Boost :

From: Hugo Duncan (hugoduncan_at_[hidden])
Date: 2003-10-14 09:29:51

Deane Yang <deane_yang_at_[hidden]> wrote:

> Hugo Duncan wrote:
>> This is a problem with a library that we use here. It defines
>> a quantity as a numeric type and a set of dimensions
>> template <typename T, typename Dimensions> class quantity;
>> where dimensions contains a mpl type sequence, with each
>> element holding instances of
>> template <
>> typename DimensionType
>> , long Numerator
>> , long Denominator=1
>> > struct dimension_power
>> Each DimensionType is then assosciated with a unit.
> This sounds like a very cool way to define a dimension/quantity/units
> library. Is there any chance an implementation of this could be made
> available? If not, could someone more fluent in MPL than me explain
> how you would multiply two different quantities?

To multiply two quantities is not so simple, and the trick is to
factor out the sperate operations required.

   template <typename NumericType, typename Dimensions> class quantity;

each operator defined on quantity essentially has to carry out the

   i) Type promotion on the NumericType's involved in the expression.
   ii) Compute resulting dimension
   iii) Ensure consistent units

   i) Type promotion on the NumericType's involved in the expression.

      To do this you can define type computation classes, and define
      tags for each operator Op that you want to support.

        template <typename Op, typename Arg1>
        struct op1 : public arithmetic_promotion<Arg1> {};

        template <typename Op, typename Arg1, typename Arg2>
        struct op2 : public promoted<Arg1, Arg2> {};

   ii) Compute resulting dimension

       Again, define type computation classes,

       template <typename Dimensions1,typename Dimensions2>
       struct plus_traits;

       To implement this you can require that the typelist of
       dimensional powers is sortable by the dimension tag. The
       maths itself can be implemented by an MPL type rational

  iii) Make sure that the unit used for each of the dimensions
       is consistent between operands. A simple way to do this
       is to convert all the units for dimensions common to
       multiple operands to match those in one of the operands.

       This requires a little care, eg if you have an integral
       seconds representation, and you convert to hours (say),
       you will need a non-integral representation.

So, declaration for operaor+ looks something like:

   template <typename T1, typename Dimensions1
           , typename T2, typename Dimensions2>
       typename type_promotion::op2<type_promotion::op_plus,T1,T2>::type
     , typename plus_traits<Dimensions1,Dimensions2>::type
   operator+(const quantity<T1,Dimensions1>& x,
             const quantity<T2,Dimensions2>& y);

> The cool thing about this approach is that you can multiply or
> divide any two quantities and create a new dimension automatically.
> The resulting typelist is a union of the original two typelists
> with the Numerator and Denominator suitably updated.

Yes, and there can even be a runtime version of the dimensions that
interoperates with the compile time version. Similarly the units
for each dimension can be fixed at compile time or run time.

The downside of this is that you start relying on this computation of
resulting dimension, so switching the dimensional checking off
becomes harder.

Working with compile time units elimates the need to do unit conversion
in iii) above, and is a good choice for computational simulations. It
dows require however some abilities to convert a quantity to arbitrary
units at runtime for user interface purposes.

> Given enough time, I might be able to figure out how to generate the
> resulting typelist from the two input typelists, but I'm happy to let
> someone provide some hints or even answers.

Hope that provides some hints, and is understandable.


Boost list run by bdawes at, gregod at, cpdaniel at, john at