![]() |
Home | Libraries | People | FAQ | More |
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