si_physics.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. // ratio_test.cpp ----------------------------------------------------------//
  2. // Copyright 2008 Howard Hinnant
  3. // Copyright 2008 Beman Dawes
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // See http://www.boost.org/LICENSE_1_0.txt
  6. #include <iostream>
  7. #include <boost/ratio/ratio.hpp>
  8. #include "duration.hpp"
  9. namespace User1
  10. {
  11. // Example type-safe "physics" code interoperating with chrono::duration types
  12. // and taking advantage of the std::ratio infrastructure and design philosophy.
  13. // length - mimics chrono::duration except restricts representation to double.
  14. // Uses boost::ratio facilities for length units conversions.
  15. template <class Ratio>
  16. class length
  17. {
  18. public:
  19. typedef Ratio ratio;
  20. private:
  21. double len_;
  22. public:
  23. length() : len_(1) {}
  24. length(const double& len) : len_(len) {}
  25. // conversions
  26. template <class R>
  27. length(const length<R>& d)
  28. : len_(d.count() * boost::ratio_divide<Ratio, R>::type::den /
  29. boost::ratio_divide<Ratio, R>::type::num) {}
  30. // observer
  31. double count() const {return len_;}
  32. // arithmetic
  33. length& operator+=(const length& d) {len_ += d.count(); return *this;}
  34. length& operator-=(const length& d) {len_ -= d.count(); return *this;}
  35. length operator+() const {return *this;}
  36. length operator-() const {return length(-len_);}
  37. length& operator*=(double rhs) {len_ *= rhs; return *this;}
  38. length& operator/=(double rhs) {len_ /= rhs; return *this;}
  39. };
  40. // Sparse sampling of length units
  41. typedef length<boost::ratio<1> > meter; // set meter as "unity"
  42. typedef length<boost::centi> centimeter; // 1/100 meter
  43. typedef length<boost::kilo> kilometer; // 1000 meters
  44. typedef length<boost::ratio<254, 10000> > inch; // 254/10000 meters
  45. // length takes ratio instead of two integral types so that definitions can be made like so:
  46. typedef length<boost::ratio_multiply<boost::ratio<12>, inch::ratio>::type> foot; // 12 inchs
  47. typedef length<boost::ratio_multiply<boost::ratio<5280>, foot::ratio>::type> mile; // 5280 feet
  48. // Need a floating point definition of seconds
  49. typedef boost_ex::chrono::duration<double> seconds; // unity
  50. // Demo of (scientific) support for sub-nanosecond resolutions
  51. typedef boost_ex::chrono::duration<double, boost::pico> picosecond; // 10^-12 seconds
  52. typedef boost_ex::chrono::duration<double, boost::femto> femtosecond; // 10^-15 seconds
  53. typedef boost_ex::chrono::duration<double, boost::atto> attosecond; // 10^-18 seconds
  54. // A very brief proof-of-concept for SIUnits-like library
  55. // Hard-wired to floating point seconds and meters, but accepts other units (shown in testUser1())
  56. template <class R1, class R2>
  57. class quantity
  58. {
  59. double q_;
  60. public:
  61. typedef R1 time_dim;
  62. typedef R2 distance_dim;
  63. quantity() : q_(1) {}
  64. double get() const {return q_;}
  65. void set(double q) {q_ = q;}
  66. };
  67. template <>
  68. class quantity<boost::ratio<1>, boost::ratio<0> >
  69. {
  70. double q_;
  71. public:
  72. quantity() : q_(1) {}
  73. quantity(seconds d) : q_(d.count()) {} // note: only User1::seconds needed here
  74. double get() const {return q_;}
  75. void set(double q) {q_ = q;}
  76. };
  77. template <>
  78. class quantity<boost::ratio<0>, boost::ratio<1> >
  79. {
  80. double q_;
  81. public:
  82. quantity() : q_(1) {}
  83. quantity(meter d) : q_(d.count()) {} // note: only User1::meter needed here
  84. double get() const {return q_;}
  85. void set(double q) {q_ = q;}
  86. };
  87. template <>
  88. class quantity<boost::ratio<0>, boost::ratio<0> >
  89. {
  90. double q_;
  91. public:
  92. quantity() : q_(1) {}
  93. quantity(double d) : q_(d) {}
  94. double get() const {return q_;}
  95. void set(double q) {q_ = q;}
  96. };
  97. // Example SI-Units
  98. typedef quantity<boost::ratio<0>, boost::ratio<0> > Scalar;
  99. typedef quantity<boost::ratio<1>, boost::ratio<0> > Time; // second
  100. typedef quantity<boost::ratio<0>, boost::ratio<1> > Distance; // meter
  101. typedef quantity<boost::ratio<-1>, boost::ratio<1> > Speed; // meter/second
  102. typedef quantity<boost::ratio<-2>, boost::ratio<1> > Acceleration; // meter/second^2
  103. template <class R1, class R2, class R3, class R4>
  104. quantity<typename boost::ratio_subtract<R1, R3>::type, typename boost::ratio_subtract<R2, R4>::type>
  105. operator/(const quantity<R1, R2>& x, const quantity<R3, R4>& y)
  106. {
  107. typedef quantity<typename boost::ratio_subtract<R1, R3>::type, typename boost::ratio_subtract<R2, R4>::type> R;
  108. R r;
  109. r.set(x.get() / y.get());
  110. return r;
  111. }
  112. template <class R1, class R2, class R3, class R4>
  113. quantity<typename boost::ratio_add<R1, R3>::type, typename boost::ratio_add<R2, R4>::type>
  114. operator*(const quantity<R1, R2>& x, const quantity<R3, R4>& y)
  115. {
  116. typedef quantity<typename boost::ratio_add<R1, R3>::type, typename boost::ratio_add<R2, R4>::type> R;
  117. R r;
  118. r.set(x.get() * y.get());
  119. return r;
  120. }
  121. template <class R1, class R2>
  122. quantity<R1, R2>
  123. operator+(const quantity<R1, R2>& x, const quantity<R1, R2>& y)
  124. {
  125. typedef quantity<R1, R2> R;
  126. R r;
  127. r.set(x.get() + y.get());
  128. return r;
  129. }
  130. template <class R1, class R2>
  131. quantity<R1, R2>
  132. operator-(const quantity<R1, R2>& x, const quantity<R1, R2>& y)
  133. {
  134. typedef quantity<R1, R2> R;
  135. R r;
  136. r.set(x.get() - y.get());
  137. return r;
  138. }
  139. // Example type-safe physics function
  140. Distance
  141. compute_distance(Speed v0, Time t, Acceleration a)
  142. {
  143. return v0 * t + Scalar(.5) * a * t * t; // if a units mistake is made here it won't compile
  144. }
  145. } // User1
  146. // Exercise example type-safe physics function and show interoperation
  147. // of custom time durations (User1::seconds) and standard time durations (std::hours).
  148. // Though input can be arbitrary (but type-safe) units, output is always in SI-units
  149. // (a limitation of the simplified Units lib demoed here).
  150. int main()
  151. {
  152. //~ typedef boost::ratio<8, BOOST_INTMAX_C(0x7FFFFFFFD)> R1;
  153. //~ typedef boost::ratio<3, BOOST_INTMAX_C(0x7FFFFFFFD)> R2;
  154. typedef User1::quantity<boost::ratio_subtract<boost::ratio<0>, boost::ratio<1> >::type,
  155. boost::ratio_subtract<boost::ratio<1>, boost::ratio<0> >::type > RR;
  156. //~ typedef boost::ratio_subtract<R1, R2>::type RS;
  157. //~ std::cout << RS::num << '/' << RS::den << '\n';
  158. std::cout << "*************\n";
  159. std::cout << "* testUser1 *\n";
  160. std::cout << "*************\n";
  161. User1::Distance d(( User1::mile(110) ));
  162. boost_ex::chrono::hours h((2));
  163. User1::Time t(( h ));
  164. //~ boost_ex::chrono::seconds sss=boost_ex::chrono::duration_cast<boost_ex::chrono::seconds>(h);
  165. //~ User1::seconds sss((120));
  166. //~ User1::Time t(( sss ));
  167. //typedef User1::quantity<boost::ratio_subtract<User1::Distance::time_dim, User1::Time::time_dim >::type,
  168. // boost::ratio_subtract<User1::Distance::distance_dim, User1::Time::distance_dim >::type > R;
  169. RR r=d / t;
  170. //r.set(d.get() / t.get());
  171. User1::Speed rc= r;
  172. (void)rc;
  173. User1::Speed s = d / t;
  174. std::cout << "Speed = " << s.get() << " meters/sec\n";
  175. User1::Acceleration a = User1::Distance( User1::foot(32.2) ) / User1::Time() / User1::Time();
  176. std::cout << "Acceleration = " << a.get() << " meters/sec^2\n";
  177. User1::Distance df = compute_distance(s, User1::Time( User1::seconds(0.5) ), a);
  178. std::cout << "Distance = " << df.get() << " meters\n";
  179. std::cout << "There are " << User1::mile::ratio::den << '/' << User1::mile::ratio::num << " miles/meter";
  180. User1::meter mt = 1;
  181. User1::mile mi = mt;
  182. std::cout << " which is approximately " << mi.count() << '\n';
  183. std::cout << "There are " << User1::mile::ratio::num << '/' << User1::mile::ratio::den << " meters/mile";
  184. mi = 1;
  185. mt = mi;
  186. std::cout << " which is approximately " << mt.count() << '\n';
  187. User1::attosecond as(1);
  188. User1::seconds sec = as;
  189. std::cout << "1 attosecond is " << sec.count() << " seconds\n";
  190. std::cout << "sec = as; // compiles\n";
  191. sec = User1::seconds(1);
  192. as = sec;
  193. std::cout << "1 second is " << as.count() << " attoseconds\n";
  194. std::cout << "as = sec; // compiles\n";
  195. std::cout << "\n";
  196. return 0;
  197. }