Brian Silverman | a8ce4c3 | 2018-08-04 23:57:09 -0700 | [diff] [blame^] | 1 | // Boost.Units - A C++ library for zero-overhead dimensional analysis and |
| 2 | // unit/quantity manipulation and conversion |
| 3 | // |
| 4 | // Copyright (C) 2003-2008 Matthias Christian Schabel |
| 5 | // Copyright (C) 2008 Steven Watanabe |
| 6 | // |
| 7 | // Distributed under the Boost Software License, Version 1.0. (See |
| 8 | // accompanying file LICENSE_1_0.txt or copy at |
| 9 | // http://www.boost.org/LICENSE_1_0.txt) |
| 10 | |
| 11 | /** |
| 12 | \file |
| 13 | |
| 14 | \brief complex.cpp |
| 15 | |
| 16 | \details |
| 17 | Demonstrate a complex number class that functions correctly with quantities. |
| 18 | |
| 19 | Output: |
| 20 | @verbatim |
| 21 | |
| 22 | //[complex_output_1 |
| 23 | +L = 2 + 1 i m |
| 24 | -L = -2 + -1 i m |
| 25 | L+L = 4 + 2 i m |
| 26 | L-L = 0 + 0 i m |
| 27 | L*L = 3 + 4 i m^2 |
| 28 | L/L = 1 + 0 i dimensionless |
| 29 | L^3 = 2 + 11 i m^3 |
| 30 | L^(3/2) = 2.56713 + 2.14247 i m^(3/2) |
| 31 | 3vL = 1.29207 + 0.201294 i m^(1/3) |
| 32 | (3/2)vL = 1.62894 + 0.520175 i m^(2/3) |
| 33 | //] |
| 34 | |
| 35 | //[complex_output_2 |
| 36 | +L = 2 m + 1 m i |
| 37 | -L = -2 m + -1 m i |
| 38 | L+L = 4 m + 2 m i |
| 39 | L-L = 0 m + 0 m i |
| 40 | L*L = 3 m^2 + 4 m^2 i |
| 41 | L/L = 1 dimensionless + 0 dimensionless i |
| 42 | L^3 = 2 m^3 + 11 m^3 i |
| 43 | L^(3/2) = 2.56713 m^(3/2) + 2.14247 m^(3/2) i |
| 44 | 3vL = 1.29207 m^(1/3) + 0.201294 m^(1/3) i |
| 45 | (3/2)vL = 1.62894 m^(2/3) + 0.520175 m^(2/3) i |
| 46 | //] |
| 47 | |
| 48 | @endverbatim |
| 49 | **/ |
| 50 | |
| 51 | #include <cmath> |
| 52 | #include <complex> |
| 53 | #include <iostream> |
| 54 | |
| 55 | #include <boost/mpl/list.hpp> |
| 56 | |
| 57 | #include <boost/units/io.hpp> |
| 58 | #include <boost/units/pow.hpp> |
| 59 | #include <boost/units/quantity.hpp> |
| 60 | |
| 61 | #include "test_system.hpp" |
| 62 | |
| 63 | //[complex_class_snippet_1 |
| 64 | namespace boost { |
| 65 | |
| 66 | namespace units { |
| 67 | |
| 68 | /// replacement complex class |
| 69 | template<class T> |
| 70 | class complex |
| 71 | { |
| 72 | public: |
| 73 | typedef complex<T> this_type; |
| 74 | |
| 75 | constexpr complex(const T& r = 0,const T& i = 0) : r_(r),i_(i) { } |
| 76 | constexpr complex(const this_type& source) : r_(source.r_),i_(source.i_) { } |
| 77 | |
| 78 | constexpr this_type& operator=(const this_type& source) |
| 79 | { |
| 80 | if (this == &source) return *this; |
| 81 | |
| 82 | r_ = source.r_; |
| 83 | i_ = source.i_; |
| 84 | |
| 85 | return *this; |
| 86 | } |
| 87 | |
| 88 | constexpr T& real() { return r_; } |
| 89 | constexpr T& imag() { return i_; } |
| 90 | |
| 91 | constexpr const T& real() const { return r_; } |
| 92 | constexpr const T& imag() const { return i_; } |
| 93 | |
| 94 | constexpr this_type& operator+=(const T& val) |
| 95 | { |
| 96 | r_ += val; |
| 97 | return *this; |
| 98 | } |
| 99 | |
| 100 | constexpr this_type& operator-=(const T& val) |
| 101 | { |
| 102 | r_ -= val; |
| 103 | return *this; |
| 104 | } |
| 105 | |
| 106 | constexpr this_type& operator*=(const T& val) |
| 107 | { |
| 108 | r_ *= val; |
| 109 | i_ *= val; |
| 110 | return *this; |
| 111 | } |
| 112 | |
| 113 | constexpr this_type& operator/=(const T& val) |
| 114 | { |
| 115 | r_ /= val; |
| 116 | i_ /= val; |
| 117 | return *this; |
| 118 | } |
| 119 | |
| 120 | constexpr this_type& operator+=(const this_type& source) |
| 121 | { |
| 122 | r_ += source.r_; |
| 123 | i_ += source.i_; |
| 124 | return *this; |
| 125 | } |
| 126 | |
| 127 | constexpr this_type& operator-=(const this_type& source) |
| 128 | { |
| 129 | r_ -= source.r_; |
| 130 | i_ -= source.i_; |
| 131 | return *this; |
| 132 | } |
| 133 | |
| 134 | constexpr this_type& operator*=(const this_type& source) |
| 135 | { |
| 136 | *this = *this * source; |
| 137 | return *this; |
| 138 | } |
| 139 | |
| 140 | constexpr this_type& operator/=(const this_type& source) |
| 141 | { |
| 142 | *this = *this / source; |
| 143 | return *this; |
| 144 | } |
| 145 | |
| 146 | private: |
| 147 | T r_,i_; |
| 148 | }; |
| 149 | |
| 150 | } |
| 151 | |
| 152 | } |
| 153 | |
| 154 | #if BOOST_UNITS_HAS_BOOST_TYPEOF |
| 155 | |
| 156 | #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() |
| 157 | |
| 158 | BOOST_TYPEOF_REGISTER_TEMPLATE(boost::units::complex, 1) |
| 159 | |
| 160 | #endif |
| 161 | |
| 162 | namespace boost { |
| 163 | |
| 164 | namespace units { |
| 165 | |
| 166 | template<class X> |
| 167 | constexpr |
| 168 | complex<typename unary_plus_typeof_helper<X>::type> |
| 169 | operator+(const complex<X>& x) |
| 170 | { |
| 171 | typedef typename unary_plus_typeof_helper<X>::type type; |
| 172 | |
| 173 | return complex<type>(x.real(),x.imag()); |
| 174 | } |
| 175 | |
| 176 | template<class X> |
| 177 | constexpr |
| 178 | complex<typename unary_minus_typeof_helper<X>::type> |
| 179 | operator-(const complex<X>& x) |
| 180 | { |
| 181 | typedef typename unary_minus_typeof_helper<X>::type type; |
| 182 | |
| 183 | return complex<type>(-x.real(),-x.imag()); |
| 184 | } |
| 185 | |
| 186 | template<class X,class Y> |
| 187 | constexpr |
| 188 | complex<typename add_typeof_helper<X,Y>::type> |
| 189 | operator+(const complex<X>& x,const complex<Y>& y) |
| 190 | { |
| 191 | typedef typename boost::units::add_typeof_helper<X,Y>::type type; |
| 192 | |
| 193 | return complex<type>(x.real()+y.real(),x.imag()+y.imag()); |
| 194 | } |
| 195 | |
| 196 | template<class X,class Y> |
| 197 | constexpr |
| 198 | complex<typename boost::units::subtract_typeof_helper<X,Y>::type> |
| 199 | operator-(const complex<X>& x,const complex<Y>& y) |
| 200 | { |
| 201 | typedef typename boost::units::subtract_typeof_helper<X,Y>::type type; |
| 202 | |
| 203 | return complex<type>(x.real()-y.real(),x.imag()-y.imag()); |
| 204 | } |
| 205 | |
| 206 | template<class X,class Y> |
| 207 | constexpr |
| 208 | complex<typename boost::units::multiply_typeof_helper<X,Y>::type> |
| 209 | operator*(const complex<X>& x,const complex<Y>& y) |
| 210 | { |
| 211 | typedef typename boost::units::multiply_typeof_helper<X,Y>::type type; |
| 212 | |
| 213 | return complex<type>(x.real()*y.real() - x.imag()*y.imag(), |
| 214 | x.real()*y.imag() + x.imag()*y.real()); |
| 215 | |
| 216 | // fully correct implementation has more complex return type |
| 217 | // |
| 218 | // typedef typename boost::units::multiply_typeof_helper<X,Y>::type xy_type; |
| 219 | // |
| 220 | // typedef typename boost::units::add_typeof_helper< |
| 221 | // xy_type,xy_type>::type xy_plus_xy_type; |
| 222 | // typedef typename |
| 223 | // boost::units::subtract_typeof_helper<xy_type,xy_type>::type |
| 224 | // xy_minus_xy_type; |
| 225 | // |
| 226 | // BOOST_STATIC_ASSERT((boost::is_same<xy_plus_xy_type, |
| 227 | // xy_minus_xy_type>::value == true)); |
| 228 | // |
| 229 | // return complex<xy_plus_xy_type>(x.real()*y.real()-x.imag()*y.imag(), |
| 230 | // x.real()*y.imag()+x.imag()*y.real()); |
| 231 | } |
| 232 | |
| 233 | template<class X,class Y> |
| 234 | constexpr |
| 235 | complex<typename boost::units::divide_typeof_helper<X,Y>::type> |
| 236 | operator/(const complex<X>& x,const complex<Y>& y) |
| 237 | { |
| 238 | // naive implementation of complex division |
| 239 | typedef typename boost::units::divide_typeof_helper<X,Y>::type type; |
| 240 | |
| 241 | return complex<type>((x.real()*y.real()+x.imag()*y.imag())/ |
| 242 | (y.real()*y.real()+y.imag()*y.imag()), |
| 243 | (x.imag()*y.real()-x.real()*y.imag())/ |
| 244 | (y.real()*y.real()+y.imag()*y.imag())); |
| 245 | |
| 246 | // fully correct implementation has more complex return type |
| 247 | // |
| 248 | // typedef typename boost::units::multiply_typeof_helper<X,Y>::type xy_type; |
| 249 | // typedef typename boost::units::multiply_typeof_helper<Y,Y>::type yy_type; |
| 250 | // |
| 251 | // typedef typename boost::units::add_typeof_helper<xy_type, xy_type>::type |
| 252 | // xy_plus_xy_type; |
| 253 | // typedef typename boost::units::subtract_typeof_helper< |
| 254 | // xy_type,xy_type>::type xy_minus_xy_type; |
| 255 | // |
| 256 | // typedef typename boost::units::divide_typeof_helper< |
| 257 | // xy_plus_xy_type,yy_type>::type xy_plus_xy_over_yy_type; |
| 258 | // typedef typename boost::units::divide_typeof_helper< |
| 259 | // xy_minus_xy_type,yy_type>::type xy_minus_xy_over_yy_type; |
| 260 | // |
| 261 | // BOOST_STATIC_ASSERT((boost::is_same<xy_plus_xy_over_yy_type, |
| 262 | // xy_minus_xy_over_yy_type>::value == true)); |
| 263 | // |
| 264 | // return complex<xy_plus_xy_over_yy_type>( |
| 265 | // (x.real()*y.real()+x.imag()*y.imag())/ |
| 266 | // (y.real()*y.real()+y.imag()*y.imag()), |
| 267 | // (x.imag()*y.real()-x.real()*y.imag())/ |
| 268 | // (y.real()*y.real()+y.imag()*y.imag())); |
| 269 | } |
| 270 | |
| 271 | template<class Y> |
| 272 | complex<Y> |
| 273 | pow(const complex<Y>& x,const Y& y) |
| 274 | { |
| 275 | std::complex<Y> tmp(x.real(),x.imag()); |
| 276 | |
| 277 | tmp = std::pow(tmp,y); |
| 278 | |
| 279 | return complex<Y>(tmp.real(),tmp.imag()); |
| 280 | } |
| 281 | |
| 282 | template<class Y> |
| 283 | std::ostream& operator<<(std::ostream& os,const complex<Y>& val) |
| 284 | { |
| 285 | os << val.real() << " + " << val.imag() << " i"; |
| 286 | |
| 287 | return os; |
| 288 | } |
| 289 | |
| 290 | /// specialize power typeof helper for complex<Y> |
| 291 | template<class Y,long N,long D> |
| 292 | struct power_typeof_helper<complex<Y>,static_rational<N,D> > |
| 293 | { |
| 294 | typedef complex< |
| 295 | typename power_typeof_helper<Y,static_rational<N,D> >::type |
| 296 | > type; |
| 297 | |
| 298 | static type value(const complex<Y>& x) |
| 299 | { |
| 300 | const static_rational<N,D> rat; |
| 301 | |
| 302 | const Y m = Y(rat.numerator())/Y(rat.denominator()); |
| 303 | |
| 304 | return boost::units::pow(x,m); |
| 305 | } |
| 306 | }; |
| 307 | |
| 308 | /// specialize root typeof helper for complex<Y> |
| 309 | template<class Y,long N,long D> |
| 310 | struct root_typeof_helper<complex<Y>,static_rational<N,D> > |
| 311 | { |
| 312 | typedef complex< |
| 313 | typename root_typeof_helper<Y,static_rational<N,D> >::type |
| 314 | > type; |
| 315 | |
| 316 | static type value(const complex<Y>& x) |
| 317 | { |
| 318 | const static_rational<N,D> rat; |
| 319 | |
| 320 | const Y m = Y(rat.denominator())/Y(rat.numerator()); |
| 321 | |
| 322 | return boost::units::pow(x,m); |
| 323 | } |
| 324 | }; |
| 325 | |
| 326 | /// specialize power typeof helper for complex<quantity<Unit,Y> > |
| 327 | template<class Y,class Unit,long N,long D> |
| 328 | struct power_typeof_helper<complex<quantity<Unit,Y> >,static_rational<N,D> > |
| 329 | { |
| 330 | typedef typename |
| 331 | power_typeof_helper<Y,static_rational<N,D> >::type value_type; |
| 332 | typedef typename |
| 333 | power_typeof_helper<Unit,static_rational<N,D> >::type unit_type; |
| 334 | typedef quantity<unit_type,value_type> quantity_type; |
| 335 | typedef complex<quantity_type> type; |
| 336 | |
| 337 | static type value(const complex<quantity<Unit,Y> >& x) |
| 338 | { |
| 339 | const complex<value_type> tmp = |
| 340 | pow<static_rational<N,D> >(complex<Y>(x.real().value(), |
| 341 | x.imag().value())); |
| 342 | |
| 343 | return type(quantity_type::from_value(tmp.real()), |
| 344 | quantity_type::from_value(tmp.imag())); |
| 345 | } |
| 346 | }; |
| 347 | |
| 348 | /// specialize root typeof helper for complex<quantity<Unit,Y> > |
| 349 | template<class Y,class Unit,long N,long D> |
| 350 | struct root_typeof_helper<complex<quantity<Unit,Y> >,static_rational<N,D> > |
| 351 | { |
| 352 | typedef typename |
| 353 | root_typeof_helper<Y,static_rational<N,D> >::type value_type; |
| 354 | typedef typename |
| 355 | root_typeof_helper<Unit,static_rational<N,D> >::type unit_type; |
| 356 | typedef quantity<unit_type,value_type> quantity_type; |
| 357 | typedef complex<quantity_type> type; |
| 358 | |
| 359 | static type value(const complex<quantity<Unit,Y> >& x) |
| 360 | { |
| 361 | const complex<value_type> tmp = |
| 362 | root<static_rational<N,D> >(complex<Y>(x.real().value(), |
| 363 | x.imag().value())); |
| 364 | |
| 365 | return type(quantity_type::from_value(tmp.real()), |
| 366 | quantity_type::from_value(tmp.imag())); |
| 367 | } |
| 368 | }; |
| 369 | |
| 370 | } // namespace units |
| 371 | |
| 372 | } // namespace boost |
| 373 | //] |
| 374 | |
| 375 | int main(void) |
| 376 | { |
| 377 | using namespace boost::units; |
| 378 | using namespace boost::units::test; |
| 379 | |
| 380 | { |
| 381 | //[complex_snippet_1 |
| 382 | typedef quantity<length,complex<double> > length_dimension; |
| 383 | |
| 384 | const length_dimension L(complex<double>(2.0,1.0)*meters); |
| 385 | //] |
| 386 | |
| 387 | std::cout << "+L = " << +L << std::endl |
| 388 | << "-L = " << -L << std::endl |
| 389 | << "L+L = " << L+L << std::endl |
| 390 | << "L-L = " << L-L << std::endl |
| 391 | << "L*L = " << L*L << std::endl |
| 392 | << "L/L = " << L/L << std::endl |
| 393 | << "L^3 = " << pow<3>(L) << std::endl |
| 394 | << "L^(3/2) = " << pow< static_rational<3,2> >(L) << std::endl |
| 395 | << "3vL = " << root<3>(L) << std::endl |
| 396 | << "(3/2)vL = " << root< static_rational<3,2> >(L) << std::endl |
| 397 | << std::endl; |
| 398 | } |
| 399 | |
| 400 | { |
| 401 | //[complex_snippet_2 |
| 402 | typedef complex<quantity<length> > length_dimension; |
| 403 | |
| 404 | const length_dimension L(2.0*meters,1.0*meters); |
| 405 | //] |
| 406 | |
| 407 | std::cout << "+L = " << +L << std::endl |
| 408 | << "-L = " << -L << std::endl |
| 409 | << "L+L = " << L+L << std::endl |
| 410 | << "L-L = " << L-L << std::endl |
| 411 | << "L*L = " << L*L << std::endl |
| 412 | << "L/L = " << L/L << std::endl |
| 413 | << "L^3 = " << pow<3>(L) << std::endl |
| 414 | << "L^(3/2) = " << pow< static_rational<3,2> >(L) << std::endl |
| 415 | << "3vL = " << root<3>(L) << std::endl |
| 416 | << "(3/2)vL = " << root< static_rational<3,2> >(L) << std::endl |
| 417 | << std::endl; |
| 418 | } |
| 419 | |
| 420 | return 0; |
| 421 | } |