Boost logo

Boost :

From: Reece Dunn (msclrhd_at_[hidden])
Date: 2006-06-08 15:59:36


David Greene wrote:
> Andy Little wrote:
>
> > If kilograms played by the rules its exponent would be 3 , but for whatever
> > historical reasons its 0.
> >
> > Without the prefix_offset, because kilograms has an exponent of 0, then its
> > unit output would be worked out as 'g', which is plainly wrong.
> >
> > Does this help?
>
> Why not just give kg anb exponent of "3" like everywhere else and then
> adjust the other mass exponents accordingly. Why special-case this?

I have been playing around with implementing a unit system. What I have
for SI units is something like:

namespace boost { namespace unit { namespace si
{

struct si_tag{};

namespace prefix
{

typedef power< 10, 6 > mega;
typedef power< 10, 3 > kilo;
typedef power< 10, 0 > base;
typedef power< 10, -3 > milli;

typedef kilo k;
typedef milli m;

}

struct length_tag{};
struct mass_tag{};
struct time_tag{};

typedef base_unit_type< length_tag, 0 >
        length;

typedef base_unit_type< mass_tag, 1 >
        mass;

typedef base_unit_type< time_tag, 2 >
        time;

/** @brief length */

typedef base_unit< si_tag, length, prefix::base > meter;

typedef scaled_unit< meter, prefix::kilo > km;
typedef scaled_unit< meter, prefix::base > m;
typedef scaled_unit< meter, prefix::milli > mm;

/** @brief mass */

typedef base_unit< si_tag, mass, prefix::kilo > kilogram;

typedef scaled_unit< kilogram, prefix::kilo > kg;
typedef scaled_unit< kilogram, prefix::base > g;
typedef scaled_unit< kilogram, prefix::milli > mg;

/** @brief time */

typedef base_unit< si_tag, time, prefix::base > second;

typedef scaled_unit< second, prefix::kilo > ks;
typedef scaled_unit< second, prefix::base > s;
typedef scaled_unit< second, prefix::milli > ms;

/** @brief force */

typedef derived_unit< kilogram, meter, per< second >, per< second > >
        newton; // N = m.kg.s-2

typedef scaled_unit< newton, prefix::kilo > kN;
typedef scaled_unit< newton, prefix::base > N;
typedef scaled_unit< newton, prefix::milli > mN;

}}}

With the following unit concepts:

namespace boost { namespace unit
{

template< int Base, int Exponent >
struct power{};

/** @brief A single unit in a given unit system.
  */

template< typename System, typename Dimension, typename Scale, int Exponent = 1 >
struct unit{};

/** @brief A fundamental unit type within a unit system.
  */

template< typename Tag, int Index >
struct base_unit_type
{
};

/** @brief A fundamental unit within a unit system.
  */

template< typename System, typename Dimension, typename Scale >
struct base_unit
{
};

/** @brief A unit scaled up or down by a given magnitude.
  */

template< typename Unit, typename Scale >
struct scaled_unit{};

/** @brief The inverse (reciprocal) of a unit.
  */

template< typename Unit >
struct per{};

/** @brief A composite unit type.
  */

template< typename Unit1, typename Unit2 >
struct composite_unit{};

struct none{};

/** @brief A unit derived from a series of other units.
  */

template< typename Unit1, typename Unit2 = none,
          typename Unit3 = none, typename Unit4 = none,
          typename Unit5 = none, typename Unit6 = none,
          typename Unit7 = none, typename Unit8 = none,
          typename Unit9 = none, typename Unit10 = none
>
struct derived_unit{};

}}

I also have simple type manipulation inside these concepts that
can reduce units of the same type, Allowing:

namespace si = boost::unit::si;

template< typename Unit >
void print( const Unit & )
{
    std::cout << typeid(Unit::type).name() << std::endl << std::endl;
}

    print(si::mm());
    print(si::kg());
    print(si::hertz());
    print(si::tesla());

    std::cout << typeid(si::mm() * si::mm()).name() << std::endl << std::endl;
    print(si::mm() * si::mm() * si::mm());

The last two giving:

struct boost::unit::composite_unit<struct boost::unit::unit<struct boost::unit::
si::si_tag,struct boost::unit::base_unit_type<struct boost::unit::si::length_tag
,0>,struct boost::unit::power<10,-3>,1>,struct boost::unit::unit<struct boost::u
nit::si::si_tag,struct boost::unit::base_unit_type<struct boost::unit::si::lengt
h_tag,0>,struct boost::unit::power<10,-3>,1> >

struct boost::unit::unit<struct boost::unit::si::si_tag,struct boost::unit::base
_unit_type<struct boost::unit::si::length_tag,0>,struct boost::unit::power<10,-3
>,3>

Currently tested on VC8 and will only reduce adjacent similar types. The idea is
to support values like this:

template< typename ValueUnit, typename ValueType = float >
class boost::unit::value;

//...

boost::unit::value< si::mm > dist( 1.5 );
boost::unit::value< typeof(si::mm() * si::mm()) > dist( dist * dist );

If there is interest, I'd be willing to persue this, especially with Andy's
expertise in this area :). At the moment it is just a toy example. I can
upload the full code as well.

NOTE: It will require a conformant compiler!

- Reece
_________________________________________________________________
Express yourself instantly with MSN Messenger! Download today it's FREE!
http://messenger.msn.click-url.com/go/onm00200471ave/direct/01/


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