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