]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
11fdf7f2 TL |
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_) { } | |
7c673cae | 77 | |
11fdf7f2 | 78 | constexpr this_type& operator=(const this_type& source) |
7c673cae FG |
79 | { |
80 | if (this == &source) return *this; | |
81 | ||
82 | r_ = source.r_; | |
83 | i_ = source.i_; | |
84 | ||
85 | return *this; | |
86 | } | |
87 | ||
11fdf7f2 TL |
88 | constexpr T& real() { return r_; } |
89 | constexpr T& imag() { return i_; } | |
7c673cae | 90 | |
11fdf7f2 TL |
91 | constexpr const T& real() const { return r_; } |
92 | constexpr const T& imag() const { return i_; } | |
7c673cae | 93 | |
11fdf7f2 | 94 | constexpr this_type& operator+=(const T& val) |
7c673cae FG |
95 | { |
96 | r_ += val; | |
97 | return *this; | |
98 | } | |
99 | ||
11fdf7f2 | 100 | constexpr this_type& operator-=(const T& val) |
7c673cae FG |
101 | { |
102 | r_ -= val; | |
103 | return *this; | |
104 | } | |
105 | ||
11fdf7f2 | 106 | constexpr this_type& operator*=(const T& val) |
7c673cae FG |
107 | { |
108 | r_ *= val; | |
109 | i_ *= val; | |
110 | return *this; | |
111 | } | |
112 | ||
11fdf7f2 | 113 | constexpr this_type& operator/=(const T& val) |
7c673cae FG |
114 | { |
115 | r_ /= val; | |
116 | i_ /= val; | |
117 | return *this; | |
118 | } | |
119 | ||
11fdf7f2 | 120 | constexpr this_type& operator+=(const this_type& source) |
7c673cae FG |
121 | { |
122 | r_ += source.r_; | |
123 | i_ += source.i_; | |
124 | return *this; | |
125 | } | |
126 | ||
11fdf7f2 | 127 | constexpr this_type& operator-=(const this_type& source) |
7c673cae FG |
128 | { |
129 | r_ -= source.r_; | |
130 | i_ -= source.i_; | |
131 | return *this; | |
132 | } | |
133 | ||
11fdf7f2 | 134 | constexpr this_type& operator*=(const this_type& source) |
7c673cae FG |
135 | { |
136 | *this = *this * source; | |
137 | return *this; | |
138 | } | |
139 | ||
11fdf7f2 | 140 | constexpr this_type& operator/=(const this_type& source) |
7c673cae FG |
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> | |
11fdf7f2 | 167 | constexpr |
7c673cae FG |
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> | |
11fdf7f2 | 177 | constexpr |
7c673cae FG |
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> | |
11fdf7f2 | 187 | constexpr |
7c673cae FG |
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> | |
11fdf7f2 | 197 | constexpr |
7c673cae FG |
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> | |
11fdf7f2 | 207 | constexpr |
7c673cae FG |
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> | |
11fdf7f2 | 234 | constexpr |
7c673cae FG |
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 | { | |
7c673cae FG |
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 | ||
11fdf7f2 | 384 | const length_dimension L(complex<double>(2.0,1.0)*meters); |
7c673cae FG |
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 | ||
11fdf7f2 | 404 | const length_dimension L(2.0*meters,1.0*meters); |
7c673cae FG |
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 | } |