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
13namespace 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
21template <class Ratio>
22class length
23{
24public:
25 typedef Ratio ratio;
26private:
27 double len_;
28public:
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
56typedef length<boost::ratio<1> > meter; // set meter as "unity"
57typedef length<boost::centi> centimeter; // 1/100 meter
58typedef length<boost::kilo> kilometer; // 1000 meters
59typedef 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:
61typedef length<boost::ratio_multiply<boost::ratio<12>, inch::ratio>::type> foot; // 12 inchs
62typedef length<boost::ratio_multiply<boost::ratio<5280>, foot::ratio>::type> mile; // 5280 feet
63
64// Need a floating point definition of seconds
65typedef boost_ex::chrono::duration<double> seconds; // unity
66// Demo of (scientific) support for sub-nanosecond resolutions
67typedef boost_ex::chrono::duration<double, boost::pico> picosecond; // 10^-12 seconds
68typedef boost_ex::chrono::duration<double, boost::femto> femtosecond; // 10^-15 seconds
69typedef 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())
73template <class R1, class R2>
74class quantity
75{
76 double q_;
77public:
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
86template <>
87class quantity<boost::ratio<1>, boost::ratio<0> >
88{
89 double q_;
90public:
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
98template <>
99class quantity<boost::ratio<0>, boost::ratio<1> >
100{
101 double q_;
102public:
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
110template <>
111class quantity<boost::ratio<0>, boost::ratio<0> >
112{
113 double q_;
114public:
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
123typedef quantity<boost::ratio<0>, boost::ratio<0> > Scalar;
124typedef quantity<boost::ratio<1>, boost::ratio<0> > Time; // second
125typedef quantity<boost::ratio<0>, boost::ratio<1> > Distance; // meter
126typedef quantity<boost::ratio<-1>, boost::ratio<1> > Speed; // meter/second
127typedef quantity<boost::ratio<-2>, boost::ratio<1> > Acceleration; // meter/second^2
128
129template <class R1, class R2, class R3, class R4>
130quantity<typename boost::ratio_subtract<R1, R3>::type, typename boost::ratio_subtract<R2, R4>::type>
131operator/(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
139template <class R1, class R2, class R3, class R4>
140quantity<typename boost::ratio_add<R1, R3>::type, typename boost::ratio_add<R2, R4>::type>
141operator*(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
149template <class R1, class R2>
150quantity<R1, R2>
151operator+(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
159template <class R1, class R2>
160quantity<R1, R2>
161operator-(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
170Distance
171compute_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
185int 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

source code of boost/libs/ratio/example/si_physics.cpp