Examples

| Home | Libraries | People | FAQ | More

## Examples

### Dimension Example

(dimension.cpp)

By using MPL metafunctions and the template specializations for operations on composite dimensions (defined in `boost/units/dimension.hpp`) it is possible to perform compile time arithmetic according to the dimensional analysis rules described above to produce new composite dimensions :

    typedef mpl::times<length_dimension,mass_dimension>::type   LM_type;
    typedef mpl::divides<length_dimension,time_dimension>::type L_T_type;
    typedef static_root<
        mpl::divides<energy_dimension,mass_dimension>::type,
        static_rational<2>
    >::type    V_type;

outputting (with symbol demangling, implemented in `boost/units/detail/utility.hpp`)

    length_dimension  = list<dim<length_base_dimension, static_rational<1l, 1l> >, dimensionless_type>
    mass_dimension    = list<dim<mass_base_dimension, static_rational<1l, 1l> >, dimensionless_type>
    time_dimension    = list<dim<time_base_dimension, static_rational<1l, 1l> >, dimensionless_type>
    energy_dimension  = list<dim<length_base_dimension, static_rational<2l, 1l> >, list<dim<mass_base_dimension, static_rational<1l, 1l> >, list<dim<time_base_dimension, static_rational<-2l, 1l> >, dimensionless_type> > >
    LM_type      = list<dim<length_base_dimension, static_rational<1l, 1l> >, list<dim<mass_base_dimension, static_rational<1l, 1l> >, dimensionless_type> >
    L_T_type     = list<dim<length_base_dimension, static_rational<1l, 1l> >, list<dim<time_base_dimension, static_rational<-1l, 1l> >, dimensionless_type> >
    V_type       = list<dim<length_base_dimension, static_rational<1l, 1l> >, list<dim<time_base_dimension, static_rational<-1l, 1l> >, dimensionless_type> >

### Unit Example

(unit.cpp)

This example demonstrates the use of the simple but functional unit system implemented in `libs/units/example/test_system.hpp` :

    const length                    L;
    const mass                      M;
    // needs to be namespace-qualified because of global time definition
    const boost::units::test::time  T;
    const energy                    E;

We can perform various algebraic operations on these units, resulting in the following output:

    L             = m
    L+L           = m
    L-L           = m
    L/L           = dimensionless
    meter*meter   = m^2
    M*(L/T)*(L/T) = m^2 kg s^-2
    M*(L/T)^2     = m^2 kg s^-2
    L^3           = m^3
    L^(3/2)       = m^(3/2)
    2vM           = kg^(1/2)
    (3/2)vM       = kg^(2/3)

### Quantity Example

(quantity.cpp)

This example demonstrates how to use quantities of our toy unit system :

    quantity<length> L = 2.0*meters;                     // quantity of length
    quantity<energy> E = kilograms*pow<2>(L/seconds);    // quantity of energy

giving us the basic quantity functionality :

    L                                 = 2 m
    L+L                               = 4 m
    L-L                               = 0 m
    L*L                               = 4 m^2
    L/L                               = 1 dimensionless
    L*meter                           = 2 m^2
    kilograms*(L/seconds)*(L/seconds) = 4 m^2 kg s^-2
    kilograms*(L/seconds)^2           = 4 m^2 kg s^-2
    L^3                               = 8 m^3
    L^(3/2)                           = 2.82843 m^(3/2)
    2vL                               = 1.41421 m^(1/2)
    (3/2)vL                           = 1.5874 m^(2/3)

As a further demonstration of the flexibility of the system, we replace the `double` value type with a `std::complex<double>` value type (ignoring the question of the meaningfulness of complex lengths and energies) :

    quantity<length,std::complex<double> > L(std::complex<double>(3.0,4.0)*meters);
    quantity<energy,std::complex<double> > E(kilograms*pow<2>(L/seconds));

and find that the code functions exactly as expected with no additional work, delegating operations to `std::complex<double>` and performing the appropriate dimensional analysis :

    L                                 = (3,4) m
    L+L                               = (6,8) m
    L-L                               = (0,0) m
    L*L                               = (-7,24) m^2
    L/L                               = (1,0) dimensionless
    L*meter                           = (3,4) m^2
    kilograms*(L/seconds)*(L/seconds) = (-7,24) m^2 kg s^-2
    kilograms*(L/seconds)^2           = (-7,24) m^2 kg s^-2
    L^3                               = (-117,44) m^3
    L^(3/2)                           = (2,11) m^(3/2)
    2vL                               = (2,1) m^(1/2)
    (3/2)vL                           = (2.38285,1.69466) m^(2/3)

### Kitchen Sink Example

(kitchen_sink.cpp)

This example provides a fairly extensive set of tests covering most of the `quantity` functionality. It uses the SI unit system defined in `boost/units/systems/si.hpp`.

If we define a few units and associated quantities,

    /// scalar
    const double    s1 = 2;

    const long                  x1 = 2;
    const static_rational<4,3>  x2;

    /// define some units
    force       u1 = newton;
    energy      u2 = joule;

    /// define some quantities
    quantity<force>      q1(1.0*u1);
    quantity<energy>     q2(2.0*u2);

the various algebraic operations between scalars, units, and quantities give

    S1 :    2
    X1 :    2
    X2 :    (4/3)
    U1 :    N
    U2 :    J
    Q1 :    1 N
    Q2 :    2 J

Scalar/unit operations :

    U1*S1 : 2 N
    S1*U1 : 2 N
    U1/S1 : 0.5 N
    S1/U1 : 2 m^-1 kg^-1 s^2

Unit/unit operations and integral/rational powers of units :

    U1+U1 : N
    U1-U1 : N
    U1*U1 : m^2 kg^2 s^-4
    U1/U1 : dimensionless
    U1*U2 : m^3 kg^2 s^-4
    U1/U2 : m^-1
    U1^X  : m^2 kg^2 s^-4
    X1vU1 : m^(1/2) kg^(1/2) s^-1
    U1^X2 : m^(4/3) kg^(4/3) s^(-8/3)
    X2vU1 : m^(3/4) kg^(3/4) s^(-3/2)

Scalar/quantity operations :

    Q1*S1 : 2 N
    S1*Q1 : 2 N
    Q1/S1 : 0.5 N
    S1/Q1 : 2 m^-1 kg^-1 s^2

Unit/quantity operations :

    U1*Q1 : 1 m^2 kg^2 s^-4
    Q1*U1 : 1 m^2 kg^2 s^-4
    U1/Q1 : 1 dimensionless
    Q1/U1 : 1 dimensionless

Quantity/quantity operations and integral/rational powers of quantities :

    +Q1   : 1 N
    -Q1   : -1 N
    Q1+Q1 : 2 N
    Q1-Q1 : 0 N
    Q1*Q1 : 1 m^2 kg^2 s^-4
    Q1/Q1 : 1 dimensionless
    Q1*Q2 : 2 m^3 kg^2 s^-4
    Q1/Q2 : 0.5 m^-1
    Q1^X1 : 1 m^2 kg^2 s^-4
    X1vQ1 : 1 m^(1/2) kg^(1/2) s^-1
    Q1^X2 : 1 m^(4/3) kg^(4/3) s^(-8/3)
    X2vQ1 : 1 m^(3/4) kg^(3/4) s^(-3/2)

Logical comparison operators are also defined between quantities :

    /// check comparison tests
    quantity<length>    l1(1.0*meter),
                        l2(2.0*meters);

giving

    l1 == l2    false
    l1 != l2    true
    l1 <= l2    true
    l1 < l2     true
    l1 >= l2    false
    l1 > l2     false

Implicit conversion is allowed between dimensionless quantities and their corresponding value types :

    /// check implicit unit conversion from dimensionless to value_type
    const double    dimless = (q1/q1);

A generic function for computing mechanical work can be defined that takes force and distance arguments in an arbitrary unit system and returns energy in the same system:

    /// the physical definition of work - computed for an arbitrary unit system
    template<class System,class Y>
    quantity<unit<energy_dimension,System>,Y>
    work(quantity<unit<force_dimension,System>,Y> F,
         quantity<unit<length_dimension,System>,Y> dx)
    {
        return F*dx;
    }

    /// test calcuation of work
    quantity<force>       F(1.0*newton);
    quantity<length>      dx(1.0*meter);
    quantity<energy>      E(work(F,dx));

which functions as expected for SI quantities :

    F  = 1 N
    dx = 1 m
    E  = 1 J

The ideal gas law can also be implemented in SI units :

    /// the ideal gas law in si units
    template<class Y>
    quantity<si::amount,Y>
    idealGasLaw(const quantity<si::pressure,Y>& P,
                const quantity<si::volume,Y>& V,
                const quantity<si::temperature,Y>& T)
    {
        using namespace boost::units::si;

        #if BOOST_UNITS_HAS_TYPEOF
        using namespace constants::codata;
        return (P*V/(R*T));
        #else
        return P*V/(8.314472*(joules/(kelvin*mole))*T);
        #endif // BOOST_UNITS_HAS_TYPEOF
    }

    /// test ideal gas law
    quantity<temperature>   T = (273.+37.)*kelvin;
    quantity<pressure>      P = 1.01325e5*pascals;
    quantity<length>        r = 0.5e-6*meters;
    quantity<volume>        V = (4.0/3.0)*3.141592*pow<3>(r);
    quantity<amount>        n(idealGasLaw(P,V,T));

with the resulting output :

    r = 5e-07 m
    P = 101325 Pa
    V = 5.23599e-19 m^3
    T = 310 K
    n = 2.05835e-17 mol
    R = 8.314472 m^2 kg s^-2 K^-1 mol^-1 (rel. unc. = 1.8e-06)

Trigonometric and inverse trigonometric functions can be implemented for any unit system that provides an angular base dimension. For radians, these functions are found in `boost/units/cmath.hpp` These behave as one expects, with trigonometric functions taking an angular quantity and returning a dimensionless quantity, while the inverse trigonometric functions take a dimensionless quantity and return an angular quantity :

Defining a few angular quantities,

    /// test trig stuff
    quantity<plane_angle>           theta = 0.375*radians;
    quantity<dimensionless>         sin_theta = sin(theta);
    quantity<plane_angle>           thetap = asin(sin_theta);

yields

    theta            = 0.375 rd
    sin(theta)       = 0.366273 dimensionless
    asin(sin(theta)) = 0.375 rd

Dealing with complex quantities is trivial. Here is the calculation of complex impedance :

    quantity<electric_potential,complex_type> v = complex_type(12.5,0.0)*volts;
    quantity<current,complex_type>            i = complex_type(3.0,4.0)*amperes;
    quantity<resistance,complex_type>         z = complex_type(1.5,-2.0)*ohms;

giving

    V   = (12.5,0) V
    I   = (3,4) A
    Z   = (1.5,-2) Ohm
    I*Z = (12.5,0) V

#### User-defined value types

User-defined value types that support the appropriate arithmetic operations are automatically supported as quantity value types. The operators that are supported by default for quantity value types are unary plus, unary minus, addition, subtraction, multiplication, division, equal-to, not-equal-to, less-than, less-or-equal-to, greater-than, and greater-or-equal-to. Support for rational powers and roots can be added by overloading the `power_typeof_helper` and `root_typeof_helper` classes. Here we implement a user-defined `measurement` class that models a numerical measurement with an associated measurement error and the appropriate algebra and demonstrates its use as a quantity value type; the full code is found in measurement.hpp.

Then, defining some `measurement` `quantity` variables

    quantity<length,measurement<double> >
        u(measurement<double>(1.0,0.0)*meters),
        w(measurement<double>(4.52,0.02)*meters),
        x(measurement<double>(2.0,0.2)*meters),
        y(measurement<double>(3.0,0.6)*meters);

gives

    x+y-w         = 0.48(+/-0.632772) m
    w*x           = 9.04(+/-0.904885) m^2
    x/y           = 0.666667(+/-0.149071) dimensionless

If we implement the overloaded helper classes for rational powers and roots then we can also compute rational powers of measurement quantities :

    w*y^2/(u*x)^2 = 10.17(+/-3.52328) m^-1
    w/(u*x)^(1/2) = 3.19612(+/-0.160431) dimensionless

### Conversion Example

(conversion.cpp)

This example demonstrates the various allowed conversions between SI and CGS units. Defining some quantities

    quantity<si::length>     L1 = quantity<si::length,int>(int(2.5)*si::meters);
    quantity<si::length,int> L2(quantity<si::length,double>(2.5*si::meters));

illustrates implicit conversion of quantities of different value types where implicit conversion of the value types themselves is allowed. N.B. The conversion from double to int is treated as an explicit conversion because there is no way to emulate the exact behavior of the built-in conversion. Explicit constructors allow conversions for two cases:

- explicit casting of a `quantity` to a different `value_type` :

    quantity<si::length,int> L3 = static_cast<quantity<si::length,int> >(L1);

- and explicit casting of a `quantity` to a different unit :

    quantity<cgs::length>    L4 = static_cast<quantity<cgs::length> >(L1);

giving the following output :

    L1 = 2 m
    L2 = 2 m
    L3 = 2 m
    L4 = 200 cm
    L5 = 5 m
    L6 = 4 m
    L7 = 200 cm

A few more explicit unit system conversions :

    quantity<si::volume>    vs(1.0*pow<3>(si::meter));
    quantity<cgs::volume>   vc(vs);
    quantity<si::volume>    vs2(vc);

    quantity<si::energy>    es(1.0*si::joule);
    quantity<cgs::energy>   ec(es);
    quantity<si::energy>    es2(ec);

    quantity<si::velocity>  v1 = 2.0*si::meters/si::second,
                            v2(2.0*cgs::centimeters/cgs::second);

which produces the following output:

    volume (m^3)  = 1 m^3
    volume (cm^3) = 1e+06 cm^3
    volume (m^3)  = 1 m^3

    energy (joules) = 1 J
    energy (ergs)   = 1e+07 erg
    energy (joules) = 1 J

    velocity (2 m/s)  = 2 m s^-1
    velocity (2 cm/s) = 0.02 m s^-1

### User Defined Types

(quaternion.cpp)

This example demonstrates the use of `boost::math::quaternion` as a value type for `quantity` and the converse. For the first case, we first define specializations of `power_typeof_helper` and `root_typeof_helper` for powers and roots, respectively:

    /// specialize power typeof helper
    template<class Y,long N,long D>
    struct power_typeof_helper<boost::math::quaternion<Y>,static_rational<N,D> >
    {
        // boost::math::quaternion only supports integer powers
        BOOST_STATIC_ASSERT(D==1);

        typedef boost::math::quaternion<
            typename power_typeof_helper<Y,static_rational<N,D> >::type
        > type;

        static type value(const boost::math::quaternion<Y>& x)
        {
            return boost::math::pow(x,static_cast<int>(N));
        }
    };

    /// specialize root typeof helper
    template<class Y,long N,long D>
    struct root_typeof_helper<boost::math::quaternion<Y>,static_rational<N,D> >
    {
        // boost::math::quaternion only supports integer powers
        BOOST_STATIC_ASSERT(N==1);

        typedef boost::math::quaternion<
            typename root_typeof_helper<Y,static_rational<N,D> >::type
        > type;

        static type value(const boost::math::quaternion<Y>& x)
        {
            return boost::math::pow(x,static_cast<int>(D));
        }
    };

We can now declare a `quantity` of a `quaternion` :

    typedef quantity<length,quaternion<double> >     length_dimension;

    length_dimension    L(quaternion<double>(4.0,3.0,2.0,1.0)*meters);

so that all operations that are defined in the `quaternion` class behave correctly. If rational powers were defined for this class, it would be possible to compute rational powers and roots with no additional changes.

    +L      = (4,3,2,1) m
    -L      = (-4,-3,-2,-1) m
    L+L     = (8,6,4,2) m
    L-L     = (0,0,0,0) m
    L*L     = (2,24,16,8) m^2
    L/L     = (1,0,0,0) dimensionless
    L^3     = (-104,102,68,34) m^3

Now, if for some reason we preferred the `quantity` to be the value type of the `quaternion` class we would have :

    typedef quaternion<quantity<length> >     length_dimension;

    length_dimension    L(4.0*meters,3.0*meters,2.0*meters,1.0*meters);

Here, the unary plus and minus and addition and subtraction operators function correctly. Unfortunately, the multiplication and division operations fail because `quaternion` implements them in terms of the `*=` and `/=` operators, respectively, which are incapable of representing the heterogeneous unit algebra needed for quantities (an identical problem occurs with `std::complex<T>`, for the same reason). In order to compute rational powers and roots, we need to specialize `power_typeof_helper` and `root_typeof_helper` as follows:

    /// specialize power typeof helper for quaternion<quantity<Unit,Y> >
    template<class Unit,long N,long D,class Y>
    struct power_typeof_helper<
        boost::math::quaternion<quantity<Unit,Y> >,
        static_rational<N,D> >
    {
        typedef typename power_typeof_helper<
            Y,
            static_rational<N,D>
        >::type     value_type;

        typedef typename power_typeof_helper<
            Unit,
            static_rational<N,D>
        >::type  unit_type;

        typedef quantity<unit_type,value_type>         quantity_type;
        typedef boost::math::quaternion<quantity_type> type;

        static type value(const boost::math::quaternion<quantity<Unit,Y> >& x)
        {
            const boost::math::quaternion<value_type>   tmp =
                pow<static_rational<N,D> >(boost::math::quaternion<Y>(
                    x.R_component_1().value(),
                    x.R_component_2().value(),
                    x.R_component_3().value(),
                    x.R_component_4().value()));

            return type(quantity_type::from_value(tmp.R_component_1()),
                        quantity_type::from_value(tmp.R_component_2()),
                        quantity_type::from_value(tmp.R_component_3()),
                        quantity_type::from_value(tmp.R_component_4()));
        }
    };

    /// specialize root typeof helper for quaternion<quantity<Unit,Y> >
    template<class Unit,long N,long D,class Y>
    struct root_typeof_helper<
        boost::math::quaternion<quantity<Unit,Y> >,
        static_rational<N,D> >
    {
        typedef typename root_typeof_helper<
            Y,
            static_rational<N,D>
        >::type      value_type;

        typedef typename root_typeof_helper<
            Unit,
            static_rational<N,D>
        >::type   unit_type;

        typedef quantity<unit_type,value_type>         quantity_type;
        typedef boost::math::quaternion<quantity_type> type;

        static type value(const boost::math::quaternion<quantity<Unit,Y> >& x)
        {
            const boost::math::quaternion<value_type>   tmp =
                root<static_rational<N,D> >(boost::math::quaternion<Y>(
                    x.R_component_1().value(),
                    x.R_component_2().value(),
                    x.R_component_3().value(),
                    x.R_component_4().value()));

            return type(quantity_type::from_value(tmp.R_component_1()),
                        quantity_type::from_value(tmp.R_component_2()),
                        quantity_type::from_value(tmp.R_component_3()),
                        quantity_type::from_value(tmp.R_component_4()));
        }
    };

giving:

    +L      = (4 m,3 m,2 m,1 m)
    -L      = (-4 m,-3 m,-2 m,-1 m)
    L+L     = (8 m,6 m,4 m,2 m)
    L-L     = (0 m,0 m,0 m,0 m)
    L^3     = (-104 m^3,102 m^3,68 m^3,34 m^3)

### Complex Example

(complex.cpp)

This example demonstrates how to implement a replacement `complex` class that functions correctly both as a quantity value type and as a quantity container class, including heterogeneous multiplication and division operations and rational powers and roots. Naturally, heterogeneous operations are only supported on compilers that implement `typeof`. The primary differences are that binary operations are not implemented using the `op=` operators and use the utility classes `add_typeof_helper`, `subtract_typeof_helper`, `multiply_typeof_helper`, and `divide_typeof_helper`. In addition, `power_typeof_helper` and `root_typeof_helper` are defined for both cases :

    namespace boost {

    namespace units {

    /// replacement complex class
    template<class T>
    class complex
    {
        public:
            typedef complex<T>  this_type;

            complex(const T& r = 0,const T& i = 0) : r_(r),i_(i) { }
            complex(const this_type& source) : r_(source.r_),i_(source.i_) { }

            this_type& operator=(const this_type& source)
            {
                if (this == &source) return *this;

                r_ = source.r_;
                i_ = source.i_;

                return *this;
            }

            T& real()                   { return r_; }
            T& imag()                   { return i_; }

            const T& real() const       { return r_; }
            const T& imag() const       { return i_; }

            this_type& operator+=(const T& val)
            {
                r_ += val;
                return *this;
            }

            this_type& operator-=(const T& val)
            {
                r_ -= val;
                return *this;
            }

            this_type& operator*=(const T& val)
            {
                r_ *= val;
                i_ *= val;
                return *this;
            }

            this_type& operator/=(const T& val)
            {
                r_ /= val;
                i_ /= val;
                return *this;
            }

            this_type& operator+=(const this_type& source)
            {
                r_ += source.r_;
                i_ += source.i_;
                return *this;
            }

            this_type& operator-=(const this_type& source)
            {
                r_ -= source.r_;
                i_ -= source.i_;
                return *this;
            }

            this_type& operator*=(const this_type& source)
            {
                *this = *this * source;
                return *this;
            }

            this_type& operator/=(const this_type& source)
            {
                *this = *this / source;
                return *this;
            }

        private:
            T   r_,i_;
    };

    }

    }

    #if BOOST_UNITS_HAS_BOOST_TYPEOF

    #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()

    BOOST_TYPEOF_REGISTER_TEMPLATE(boost::units::complex, 1)

    #endif

    namespace boost {

    namespace units {

    template<class X>
    complex<typename unary_plus_typeof_helper<X>::type>
    operator+(const complex<X>& x)
    {
        typedef typename unary_plus_typeof_helper<X>::type  type;

        return complex<type>(x.real(),x.imag());
    }

    template<class X>
    complex<typename unary_minus_typeof_helper<X>::type>
    operator-(const complex<X>& x)
    {
        typedef typename unary_minus_typeof_helper<X>::type type;

        return complex<type>(-x.real(),-x.imag());
    }

    template<class X,class Y>
    complex<typename add_typeof_helper<X,Y>::type>
    operator+(const complex<X>& x,const complex<Y>& y)
    {
        typedef typename boost::units::add_typeof_helper<X,Y>::type type;

        return complex<type>(x.real()+y.real(),x.imag()+y.imag());
    }

    template<class X,class Y>
    complex<typename boost::units::subtract_typeof_helper<X,Y>::type>
    operator-(const complex<X>& x,const complex<Y>& y)
    {
        typedef typename boost::units::subtract_typeof_helper<X,Y>::type    type;

        return complex<type>(x.real()-y.real(),x.imag()-y.imag());
    }

    template<class X,class Y>
    complex<typename boost::units::multiply_typeof_helper<X,Y>::type>
    operator*(const complex<X>& x,const complex<Y>& y)
    {
        typedef typename boost::units::multiply_typeof_helper<X,Y>::type    type;

        return complex<type>(x.real()*y.real() - x.imag()*y.imag(),
                             x.real()*y.imag() + x.imag()*y.real());

    //  fully correct implementation has more complex return type
    //
    //    typedef typename boost::units::multiply_typeof_helper<X,Y>::type xy_type;
    //
    //    typedef typename boost::units::add_typeof_helper<
    //      xy_type,xy_type>::type         xy_plus_xy_type;
    //    typedef typename
    //        boost::units::subtract_typeof_helper<xy_type,xy_type>::type
    //        xy_minus_xy_type;
    //
    //    BOOST_STATIC_ASSERT((boost::is_same<xy_plus_xy_type,
    //                                       xy_minus_xy_type>::value == true));
    //
    //    return complex<xy_plus_xy_type>(x.real()*y.real()-x.imag()*y.imag(),
    //                                    x.real()*y.imag()+x.imag()*y.real());
    }

    template<class X,class Y>
    complex<typename boost::units::divide_typeof_helper<X,Y>::type>
    operator/(const complex<X>& x,const complex<Y>& y)
    {
        // naive implementation of complex division
        typedef typename boost::units::divide_typeof_helper<X,Y>::type type;

        return complex<type>((x.real()*y.real()+x.imag()*y.imag())/
                                (y.real()*y.real()+y.imag()*y.imag()),
                             (x.imag()*y.real()-x.real()*y.imag())/
                                (y.real()*y.real()+y.imag()*y.imag()));

    //  fully correct implementation has more complex return type
    //
    //  typedef typename boost::units::multiply_typeof_helper<X,Y>::type xy_type;
    //  typedef typename boost::units::multiply_typeof_helper<Y,Y>::type yy_type;
    //
    //  typedef typename boost::units::add_typeof_helper<xy_type, xy_type>::type
    //      xy_plus_xy_type;
    //  typedef typename boost::units::subtract_typeof_helper<
    //      xy_type,xy_type>::type xy_minus_xy_type;
    //
    //  typedef typename boost::units::divide_typeof_helper<
    //      xy_plus_xy_type,yy_type>::type      xy_plus_xy_over_yy_type;
    //  typedef typename boost::units::divide_typeof_helper<
    //      xy_minus_xy_type,yy_type>::type     xy_minus_xy_over_yy_type;
    //
    //  BOOST_STATIC_ASSERT((boost::is_same<xy_plus_xy_over_yy_type,
    //                                  xy_minus_xy_over_yy_type>::value == true));
    //
    //  return complex<xy_plus_xy_over_yy_type>(
    //      (x.real()*y.real()+x.imag()*y.imag())/
    //          (y.real()*y.real()+y.imag()*y.imag()),
    //      (x.imag()*y.real()-x.real()*y.imag())/
    //          (y.real()*y.real()+y.imag()*y.imag()));
    }

    template<class Y>
    complex<Y>
    pow(const complex<Y>& x,const Y& y)
    {
        std::complex<Y> tmp(x.real(),x.imag());

        tmp = std::pow(tmp,y);

        return complex<Y>(tmp.real(),tmp.imag());
    }

    template<class Y>
    std::ostream& operator<<(std::ostream& os,const complex<Y>& val)
    {
        os << val.real() << " + " << val.imag() << " i";

        return os;
    }

    /// specialize power typeof helper for complex<Y>
    template<class Y,long N,long D>
    struct power_typeof_helper<complex<Y>,static_rational<N,D> >
    {
        typedef complex<
            typename power_typeof_helper<Y,static_rational<N,D> >::type
        > type;

        static type value(const complex<Y>& x)
        {
            const static_rational<N,D>  rat;

            const Y    m = Y(rat.numerator())/Y(rat.denominator());

            return boost::units::pow(x,m);
        }
    };

    /// specialize root typeof helper for complex<Y>
    template<class Y,long N,long D>
    struct root_typeof_helper<complex<Y>,static_rational<N,D> >
    {
        typedef complex<
            typename root_typeof_helper<Y,static_rational<N,D> >::type
        > type;

        static type value(const complex<Y>& x)
        {
            const static_rational<N,D>  rat;

            const Y    m = Y(rat.denominator())/Y(rat.numerator());

            return boost::units::pow(x,m);
        }
    };

    /// specialize power typeof helper for complex<quantity<Unit,Y> >
    template<class Y,class Unit,long N,long D>
    struct power_typeof_helper<complex<quantity<Unit,Y> >,static_rational<N,D> >
    {
        typedef typename
            power_typeof_helper<Y,static_rational<N,D> >::type       value_type;
        typedef typename
            power_typeof_helper<Unit,static_rational<N,D> >::type    unit_type;
        typedef quantity<unit_type,value_type>                      quantity_type;
        typedef complex<quantity_type>                              type;

        static type value(const complex<quantity<Unit,Y> >& x)
        {
            const complex<value_type>   tmp =
                pow<static_rational<N,D> >(complex<Y>(x.real().value(),
                                                      x.imag().value()));

            return type(quantity_type::from_value(tmp.real()),
                        quantity_type::from_value(tmp.imag()));
        }
    };

    /// specialize root typeof helper for complex<quantity<Unit,Y> >
    template<class Y,class Unit,long N,long D>
    struct root_typeof_helper<complex<quantity<Unit,Y> >,static_rational<N,D> >
    {
        typedef typename
            root_typeof_helper<Y,static_rational<N,D> >::type       value_type;
        typedef typename
            root_typeof_helper<Unit,static_rational<N,D> >::type    unit_type;
        typedef quantity<unit_type,value_type>                      quantity_type;
        typedef complex<quantity_type>                              type;

        static type value(const complex<quantity<Unit,Y> >& x)
        {
            const complex<value_type>   tmp =
                root<static_rational<N,D> >(complex<Y>(x.real().value(),
                                                       x.imag().value()));

            return type(quantity_type::from_value(tmp.real()),
                       quantity_type::from_value(tmp.imag()));
        }
    };

    } // namespace units

    } // namespace boost

With this replacement `complex` class, we can declare a complex variable :

    typedef quantity<length,complex<double> >     length_dimension;

    length_dimension    L(complex<double>(2.0,1.0)*meters);

to get the correct behavior for all cases supported by `quantity` with a `complex` value type :

    +L      = 2 + 1 i m
    -L      = -2 + -1 i m
    L+L     = 4 + 2 i m
    L-L     = 0 + 0 i m
    L*L     = 3 + 4 i m^2
    L/L     = 1 + 0 i dimensionless
    L^3     = 2 + 11 i m^3
    L^(3/2) = 2.56713 + 2.14247 i m^(3/2)
    3vL     = 1.29207 + 0.201294 i m^(1/3)
    (3/2)vL = 1.62894 + 0.520175 i m^(2/3)

and, similarly, `complex` with a `quantity` value type

    typedef complex<quantity<length> >     length_dimension;

    length_dimension    L(2.0*meters,1.0*meters);

gives

    +L      = 2 m + 1 m i
    -L      = -2 m + -1 m i
    L+L     = 4 m + 2 m i
    L-L     = 0 m + 0 m i
    L*L     = 3 m^2 + 4 m^2 i
    L/L     = 1 dimensionless + 0 dimensionless i
    L^3     = 2 m^3 + 11 m^3 i
    L^(3/2) = 2.56713 m^(3/2) + 2.14247 m^(3/2) i
    3vL     = 1.29207 m^(1/3) + 0.201294 m^(1/3) i
    (3/2)vL = 1.62894 m^(2/3) + 0.520175 m^(2/3) i

### Performance Example

(performance.cpp)

This example provides an ad hoc performance test to verify that zero runtime overhead is incurred when using `quantity` in place of `double`. Note that performance optimization and testing is not trivial, so some care must be taken in profiling. It is also critical to have a compiler capable of optimizing the many template instantiations and inline calls effectively to achieve maximal performance. Zero overhead for this test has been verified using gcc 4.0.1, and icc 9.0, 10.0, and 10.1 on Mac OS 10.4 and 10.5, and using msvc 8.0 on Windows XP.

### Radar Beam Height

(radar_beam_height.cpp)

This example demonstrates the implementation of two non-SI units of length, the nautical mile :

    namespace nautical {

    struct length_base_unit :
        boost::units::base_unit<length_base_unit, length_dimension, 1>
    {
        static std::string name()       { return "nautical mile"; }
        static std::string symbol()     { return "nmi"; }
    };

    typedef boost::units::make_system<length_base_unit>::type system;

    /// unit typedefs
    typedef unit<length_dimension,system>    length;

    static const length mile,miles;

    } // namespace nautical

    // helper for conversions between nautical length and si length
    BOOST_UNITS_DEFINE_CONVERSION_FACTOR(nautical::length_base_unit,
                                         boost::units::si::meter_base_unit,
                                         double, 1.852e3);

and the imperial foot :

    namespace imperial {

    struct length_base_unit :
        boost::units::base_unit<length_base_unit, length_dimension, 2>
    {
        static std::string name()       { return "foot"; }
        static std::string symbol()     { return "ft"; }
    };

    typedef boost::units::make_system<length_base_unit>::type system;

    /// unit typedefs
    typedef unit<length_dimension,system>    length;

    static const length foot,feet;

    } // imperial

    // helper for conversions between imperial length and si length
    BOOST_UNITS_DEFINE_CONVERSION_FACTOR(imperial::length_base_unit,
                                         boost::units::si::meter_base_unit,
                                         double, 1.0/3.28083989501312);

These units include conversions between themselves and the meter. Three functions for computing radar beam height from radar range and the local earth radius are defined. The first takes arguments in one system and returns a value in the same system :

    template<class System,typename T>
    quantity<unit<boost::units::length_dimension,System>,T>
    radar_beam_height(const quantity<unit<length_dimension,System>,T>& radar_range,
                      const quantity<unit<length_dimension,System>,T>& earth_radius,
                      T k = 4.0/3.0)
    {
        return quantity<unit<length_dimension,System>,T>
            (pow<2>(radar_range)/(2.0*k*earth_radius));
    }

The second is similar, but is templated on return type, so that the arguments are converted to the return unit system internally :

    template<class return_type,class System1,class System2,typename T>
    return_type
    radar_beam_height(const quantity<unit<length_dimension,System1>,T>& radar_range,
                      const quantity<unit<length_dimension,System2>,T>& earth_radius,
                      T k = 4.0/3.0)
    {
        // need to decide which system to use for calculation
        const return_type   rr(radar_range),
                            er(earth_radius);

        return return_type(pow<2>(rr)/(2.0*k*er));
    }

Finally, the third function is an empirical approximation that is only valid for radar ranges specified in nautical miles, returning beam height in feet. This function uses the heterogeneous unit of nautical miles per square root of feet to ensure dimensional correctness :

    quantity<imperial::length>
    radar_beam_height(const quantity<nautical::length>& range)
    {
        return quantity<imperial::length>
            (pow<2>(range/(1.23*nautical::miles/root<2>(imperial::feet))));
    }

With these, we can compute radar beam height in various unit systems :

    const quantity<nautical::length> radar_range(300.0*miles);
    const quantity<si::length>       earth_radius(6371.0087714*kilo*meters);

    const quantity<si::length>       beam_height_1(radar_beam_height(quantity<si::length>(radar_range),earth_radius));
    const quantity<nautical::length> beam_height_2(radar_beam_height(radar_range,quantity<nautical::length>(earth_radius)));
    const quantity<si::length>       beam_height_3(radar_beam_height< quantity<si::length> >(radar_range,earth_radius));
    const quantity<nautical::length> beam_height_4(radar_beam_height< quantity<nautical::length> >(radar_range,earth_radius));

giving

    radar range        : 300 nmi
    earth radius       : 6.37101e+06 m
    beam height 1      : 18169.7 m
    beam height 2      : 9.81085 nmi
    beam height 3      : 18169.7 m
    beam height 4      : 9.81085 nmi
    beam height approx : 59488.4 ft
    beam height approx : 18132.1 m

### Heterogeneous Unit Example

(heterogeneous_unit.cpp)

Mixed units and mixed unit conversions.

This code:

    quantity<si::length>        L(1.5*si::meter);
    quantity<cgs::mass>         M(1.0*cgs::gram);

    std::cout << L << std::endl
              << M << std::endl
              << L*M << std::endl
              << L/M << std::endl
              << std::endl;

    std::cout << 1.0*si::meter*si::kilogram/pow<2>(si::second) << std::endl
              << 1.0*si::meter*si::kilogram/pow<2>(si::second)/si::meter
              << std::endl << std::endl;

    std::cout << 1.0*cgs::centimeter*si::kilogram/pow<2>(si::second) << std::endl
              << 1.0*cgs::centimeter*si::kilogram/pow<2>(si::second)/si::meter
              << std::endl << std::endl;

gives

    1.5 m
    1 g
    1.5 m g
    1.5 m g^-1

    1 N
    1 kg s^-2

    1 cm kg s^-2
    1 cm m^-1 kg s^-2

Arbitrary conversions also work:

    quantity<si::area>      A(1.5*si::meter*cgs::centimeter);

    std::cout << 1.5*si::meter*cgs::centimeter << std::endl
              << A << std::endl
              << std::endl;

yielding

    1.5 cm m
    0.015 m^2

### Absolute and Relative Temperature Example

(temperature.cpp)

This example demonstrates using of absolute temperatures and relative temperature differences in Fahrenheit and converting between these and the Kelvin temperature scale. This issue touches on some surprisingly deep mathematical concepts (see Wikipedia for a basic review), but for our purposes here, we will simply observe that it is important to be able to differentiate between an absolute temperature measurement and a measurement of temperature difference. This is accomplished by using the `absolute` wrapper class.

First we define a system using the predefined fahrenheit base unit:

    typedef temperature::fahrenheit_base_unit::unit_type    temperature;
    typedef get_system<temperature>::type                   system;

    BOOST_UNITS_STATIC_CONSTANT(degree,temperature);
    BOOST_UNITS_STATIC_CONSTANT(degrees,temperature);

Now we can create some quantities:

    quantity<absolute<fahrenheit::temperature> >    T1p(
        32.0*absolute<fahrenheit::temperature>());
    quantity<fahrenheit::temperature>               T1v(
        32.0*fahrenheit::degrees);

    quantity<absolute<si::temperature> >            T2p(T1p);
    quantity<si::temperature>                       T2v(T1v);

Note the use of `absolute` to wrap a unit. The resulting output is:

    { 32 } F
    { 273.15 } K
    { 273.15 } K
    [ 32 ] F
    [ 17.7778 ] K
    [ 17.7778 ] K

### Runtime Conversion Factor Example

(runtime_conversion_factor.cpp)

The Boost.Units library does not require that the conversion factors be compile time constants, as is demonstrated in this example:

    using boost::units::base_dimension;
    using boost::units::base_unit;

    static const long currency_base = 1;

    struct currency_base_dimension : base_dimension<currency_base_dimension, 1> {};

    typedef currency_base_dimension::dimension_type currency_type;

    template<long N>
    struct currency_base_unit :
        base_unit<currency_base_unit<N>, currency_type, currency_base + N> {};

    typedef currency_base_unit<0> us_dollar_base_unit;
    typedef currency_base_unit<1> euro_base_unit;

    typedef us_dollar_base_unit::unit_type us_dollar;
    typedef euro_base_unit::unit_type euro;

    // an array of all possible conversions
    double conversion_factors[2][2] = {
        {1.0, 1.0},
        {1.0, 1.0}
    };

    double get_conversion_factor(long from, long to) {
        return(conversion_factors[from][to]);
    }

    void set_conversion_factor(long from, long to, double value) {
        conversion_factors[from][to] = value;
        conversion_factors[to][from] = 1.0 / value;
    }

    BOOST_UNITS_DEFINE_CONVERSION_FACTOR_TEMPLATE((long N1)(long N2),
        currency_base_unit<N1>,
        currency_base_unit<N2>,
        double, get_conversion_factor(N1, N2));

### Units with Non-base Dimensions

(non_base_dimension.cpp)

It is also possible to define base units that have derived rather than base dimensions:

    struct imperial_gallon_tag :
        base_unit<imperial_gallon_tag, volume_dimension, 1> { };

    typedef make_system<imperial_gallon_tag>::type imperial;

    typedef unit<volume_dimension,imperial> imperial_gallon;

    struct us_gallon_tag : base_unit<us_gallon_tag, volume_dimension, 2> { };

    typedef make_system<us_gallon_tag>::type us;

    typedef unit<volume_dimension,us> us_gallon;

### Output for Composite Units

(composite_output.cpp)

If a unit has a special name and/or symbol, the free functions `name_string` and `symbol_string` can be overloaded directly.

    std::string name_string(const cgs::force&)
    {
        return "dyne";
    }

    std::string symbol_string(const cgs::force&)
    {
        return "dyn";
    }

In this case, any unit that reduces to the overloaded unit will be output with the replacement symbol.

Special names and symbols for the SI and CGS unit systems are found in `boost/units/systems/si/io.hpp` and `boost/units/systems/cgs/io.hpp`, respectively. If these headers are not included, the output will simply follow default rules using the appropriate fundamental dimensions. Note that neither of these functions is defined for quantities because doing so would require making assumptions on how the corresponding value type should be formatted.

Three `ostream` formatters, `symbol_format`, `name_format`, and `typename_format` are provided for convenience. These select the textual representation of units provided by `symbol_string` or `name_string` in the first two cases, while the latter returns a demangled typename for debugging purposes. Formatting of scaled unit is also done correctly.

### Conversion Factor

This code demonstrates the use of the `conversion_factor` free function to determine the scale factor between two units.

(conversion_factor.cpp)

    double dyne_to_newton =
        conversion_factor(cgs::dyne,si::newton);
    std::cout << dyne_to_newton << std::endl;

    double force_over_mass_conversion =
        conversion_factor(si::newton/si::kilogram,cgs::dyne/cgs::gram);
    std::cout << force_over_mass_conversion << std::endl;

    double momentum_conversion =
        conversion_factor(cgs::momentum(),si::momentum());
    std::cout << momentum_conversion << std::endl;

    double momentum_over_mass_conversion =
        conversion_factor(si::momentum()/si::mass(),cgs::momentum()/cgs::gram);
    std::cout << momentum_over_mass_conversion << std::endl;

    double acceleration_conversion =
        conversion_factor(cgs::gal,si::meter_per_second_squared);
    std::cout << acceleration_conversion << std::endl;

Produces

    1e-005
    100
    1e-005
    100
    0.01

### Runtime Units

(runtime_unit.cpp)

This example shows how to implement an interface that allow different units at runtime while still maintaining type safety for internal calculations.

    namespace {

    using namespace boost::units;
    using imperial::foot_base_unit;

    std::map<std::string, quantity<si::length> > known_units;

    }

    quantity<si::length> calculate(const quantity<si::length>& t)
    {
        return(boost::units::hypot(t, 2.0 * si::meters));
    }

    int main()
    {
        known_units["meter"] = 1.0 * si::meters;
        known_units["centimeter"] = .01 * si::meters;
        known_units["foot"] =
            conversion_factor(foot_base_unit::unit_type(), si::meter) * si::meter;

        std::string output_type("meter");
        std::string input;

        while((std::cout << "> ") && (std::cin >> input))
        {
            if(!input.empty() && input[0] == '#')
            {
                std::getline(std::cin, input);
            }
            else if(input == "exit")
            {
                break;
            }
            else if(input == "help")
            {
                std::cout << "type \"exit\" to exit\n"
                    "type \"return 'unit'\" to set the return units\n"
                    "type \"'number' 'unit'\" to do a simple calculation"
                    << std::endl;
            }
            else if(input == "return")
            {
                if(std::cin >> input)
                {
                    if(known_units.find(input) != known_units.end())
                    {
                        output_type = input;
                        std::cout << "Done." << std::endl;
                    }
                    else
                    {
                        std::cout << "Unknown unit \"" << input << "\""
                             << std::endl;
                    }
                }
                else
                {
                    break;
                }
            }
            else
            {
                try
                {
                    double value = boost::lexical_cast<double>(input);

                    if(std::cin >> input)
                    {
                        if(known_units.find(input) != known_units.end())
                        {
                            std::cout << static_cast<double>(
                                calculate(value * known_units[input]) /
                                known_units[output_type])
                                << ' ' << output_type << std::endl;
                        }
                        else
                        {
                            std::cout << "Unknown unit \"" << input << "\""
                                << std::endl;
                        }
                    }
                    else
                    {
                        break;
                    }
                }
                catch(...)
                {
                    std::cout << "Input error" << std::endl;
                }
            }
        }
    }

### Interoperability with Boost.Lambda

(lambda.cpp)

The header `boost/units/lambda.hpp` provides overloads and specializations needed to make Boost.Units usable with the Boost.Lambda library.

    int main(int argc, char **argv) {

       using namespace std;
       namespace bl = boost::lambda;
       namespace bu = boost::units;
       namespace si = boost::units::si;

       ////////////////////////////////////////////////////////////////////////
       // Mechanical example: linear accelerated movement
       ////////////////////////////////////////////////////////////////////////

       // Initial condition variables for acceleration, speed, and displacement
       bu::quantity<si::acceleration> a = 2.0 * si::meters_per_second_squared;
       bu::quantity<si::velocity> v = 1.0 * si::meters_per_second;
       bu::quantity<si::length> s0 = 0.5 * si::meter;

       // Displacement over time
       boost::function<bu::quantity<si::length> (bu::quantity<si::time>) >
           s = 0.5 * bl::var(a) * bl::_1 * bl::_1
               + bl::var(v) * bl::_1
               + bl::var(s0);

       cout << "Linear accelerated movement:" << endl
            << "a = " << a << ", v = " << v << ", s0 = " << s0 << endl
            << "s(1.0 * si::second) = " << s(1.0 * si::second) << endl
            << endl;

       // Change initial conditions
       a = 1.0 * si::meters_per_second_squared;
       v = 2.0 * si::meters_per_second;
       s0 = -1.5 * si::meter;

       cout << "a = " << a << ", v = " << v << ", s0 = " << s0 << endl
            << "s(1.0 * si::second) = " << s(1.0 * si::second) << endl
            << endl;

       ////////////////////////////////////////////////////////////////////////
       // Electrical example: oscillating current
       ////////////////////////////////////////////////////////////////////////

       // Constants for the current amplitude, frequency, and offset current
       const bu::quantity<si::current> iamp = 1.5 * si::ampere;
       const bu::quantity<si::frequency> f = 1.0e3 * si::hertz;
       const bu::quantity<si::current> i0 = 0.5 * si::ampere;

       // The invocation of the sin function needs to be postponed using
       // bind to specify the oscillation function. A lengthy static_cast
       // to the function pointer referencing boost::units::sin() is needed
       // to avoid an "unresolved overloaded function type" error.
       boost::function<bu::quantity<si::current> (bu::quantity<si::time>) >
           i = iamp
               * bl::bind(static_cast<bu::dimensionless_quantity<si::system, double>::type (*)(const bu::quantity<si::plane_angle>&)>(bu::sin),
                          2.0 * pi * si::radian * f * bl::_1)
               + i0;

       cout << "Oscillating current:" << endl
            << "iamp = " << iamp << ", f = " << f << ", i0 = " << i0 << endl
            << "i(1.25e-3 * si::second) = " << i(1.25e-3 * si::second) << endl
            << endl;

       ////////////////////////////////////////////////////////////////////////
       // Geometric example: area calculation for a square
       ////////////////////////////////////////////////////////////////////////

       // Length constant
       const bu::quantity<si::length> l = 1.5 * si::meter;

       // Again an ugly static_cast is needed to bind pow<2> to the first
       // function argument.
       boost::function<bu::quantity<si::area> (bu::quantity<si::length>) >
           A = bl::bind(static_cast<bu::quantity<si::area> (*)(const bu::quantity<si::length>&)>(bu::pow<2>),
                        bl::_1);

       cout << "Area of a square:" << endl
            << "A(" << l <<") = " << A(l) << endl << endl;

       ////////////////////////////////////////////////////////////////////////
       // Thermal example: temperature difference of two absolute temperatures
       ////////////////////////////////////////////////////////////////////////

       // Absolute temperature constants
       const bu::quantity<bu::absolute<si::temperature> >
           Tref = 273.15 * bu::absolute<si::temperature>();
       const bu::quantity<bu::absolute<si::temperature> >
           Tamb = 300.00 * bu::absolute<si::temperature>();

       boost::function<bu::quantity<si::temperature> (bu::quantity<bu::absolute<si::temperature> >,
                                                      bu::quantity<bu::absolute<si::temperature> >)>
           dT = bl::_2 - bl::_1;

       cout << "Temperature difference of two absolute temperatures:" << endl
            << "dT(" << Tref << ", " << Tamb << ") = " << dT(Tref, Tamb) << endl
            << endl;

       return 0;
    }