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 | |
30 | length() : len_(1) {} |
31 | length(const double& len) : len_(len) {} |
32 | |
33 | // conversions |
34 | template <class R> |
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 | |
41 | double count() const {return len_;} |
42 | |
43 | // arithmetic |
44 | |
45 | length& operator+=(const length& d) {len_ += d.count(); return *this;} |
46 | length& operator-=(const length& d) {len_ -= d.count(); return *this;} |
47 | |
48 | length operator+() const {return *this;} |
49 | length operator-() const {return length(-len_);} |
50 | |
51 | length& operator*=(double rhs) {len_ *= rhs; return *this;} |
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> ; // 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; |
80 | quantity() : q_(1) {} |
81 | |
82 | double get() const {return 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: |
91 | quantity() : q_(1) {} |
92 | quantity(seconds d) : q_(d.count()) {} // note: only User1::seconds needed here |
93 | |
94 | double get() const {return 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: |
103 | quantity() : q_(1) {} |
104 | quantity(meter d) : q_(d.count()) {} // note: only User1::meter needed here |
105 | |
106 | double get() const {return 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: |
115 | quantity() : q_(1) {} |
116 | quantity(double d) : q_(d) {} |
117 | |
118 | double get() const {return 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> |
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> |
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> |
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> |
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 |
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 | |
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(v0: s, t: 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 | |