// ratio_test.cpp ----------------------------------------------------------// // Copyright 2008 Howard Hinnant // Copyright 2008 Beman Dawes // Distributed under the Boost Software License, Version 1.0. // See http://www.boost.org/LICENSE_1_0.txt #include #include #include "duration.hpp" namespace User1 { // Example type-safe "physics" code interoperating with chrono::duration types // and taking advantage of the std::ratio infrastructure and design philosophy. // length - mimics chrono::duration except restricts representation to double. // Uses boost::ratio facilities for length units conversions. template class length { public: typedef Ratio ratio; private: double len_; public: length() : len_(1) {} length(const double& len) : len_(len) {} // conversions template length(const length& d) : len_(d.count() * boost::ratio_divide::type::den / boost::ratio_divide::type::num) {} // observer double count() const {return len_;} // arithmetic length& operator+=(const length& d) {len_ += d.count(); return *this;} length& operator-=(const length& d) {len_ -= d.count(); return *this;} length operator+() const {return *this;} length operator-() const {return length(-len_);} length& operator*=(double rhs) {len_ *= rhs; return *this;} length& operator/=(double rhs) {len_ /= rhs; return *this;} }; // Sparse sampling of length units typedef length > meter; // set meter as "unity" typedef length centimeter; // 1/100 meter typedef length kilometer; // 1000 meters typedef length > inch; // 254/10000 meters // length takes ratio instead of two integral types so that definitions can be made like so: typedef length, inch::ratio>::type> foot; // 12 inchs typedef length, foot::ratio>::type> mile; // 5280 feet // Need a floating point definition of seconds typedef boost_ex::chrono::duration seconds; // unity // Demo of (scientific) support for sub-nanosecond resolutions typedef boost_ex::chrono::duration picosecond; // 10^-12 seconds typedef boost_ex::chrono::duration femtosecond; // 10^-15 seconds typedef boost_ex::chrono::duration attosecond; // 10^-18 seconds // A very brief proof-of-concept for SIUnits-like library // Hard-wired to floating point seconds and meters, but accepts other units (shown in testUser1()) template class quantity { double q_; public: typedef R1 time_dim; typedef R2 distance_dim; quantity() : q_(1) {} double get() const {return q_;} void set(double q) {q_ = q;} }; template <> class quantity, boost::ratio<0> > { double q_; public: quantity() : q_(1) {} quantity(seconds d) : q_(d.count()) {} // note: only User1::seconds needed here double get() const {return q_;} void set(double q) {q_ = q;} }; template <> class quantity, boost::ratio<1> > { double q_; public: quantity() : q_(1) {} quantity(meter d) : q_(d.count()) {} // note: only User1::meter needed here double get() const {return q_;} void set(double q) {q_ = q;} }; template <> class quantity, boost::ratio<0> > { double q_; public: quantity() : q_(1) {} quantity(double d) : q_(d) {} double get() const {return q_;} void set(double q) {q_ = q;} }; // Example SI-Units typedef quantity, boost::ratio<0> > Scalar; typedef quantity, boost::ratio<0> > Time; // second typedef quantity, boost::ratio<1> > Distance; // meter typedef quantity, boost::ratio<1> > Speed; // meter/second typedef quantity, boost::ratio<1> > Acceleration; // meter/second^2 template quantity::type, typename boost::ratio_subtract::type> operator/(const quantity& x, const quantity& y) { typedef quantity::type, typename boost::ratio_subtract::type> R; R r; r.set(x.get() / y.get()); return r; } template quantity::type, typename boost::ratio_add::type> operator*(const quantity& x, const quantity& y) { typedef quantity::type, typename boost::ratio_add::type> R; R r; r.set(x.get() * y.get()); return r; } template quantity operator+(const quantity& x, const quantity& y) { typedef quantity R; R r; r.set(x.get() + y.get()); return r; } template quantity operator-(const quantity& x, const quantity& y) { typedef quantity R; R r; r.set(x.get() - y.get()); return r; } // Example type-safe physics function Distance compute_distance(Speed v0, Time t, Acceleration a) { return v0 * t + Scalar(.5) * a * t * t; // if a units mistake is made here it won't compile } } // User1 // Exercise example type-safe physics function and show interoperation // of custom time durations (User1::seconds) and standard time durations (std::hours). // Though input can be arbitrary (but type-safe) units, output is always in SI-units // (a limitation of the simplified Units lib demoed here). int main() { //~ typedef boost::ratio<8, BOOST_INTMAX_C(0x7FFFFFFFD)> R1; //~ typedef boost::ratio<3, BOOST_INTMAX_C(0x7FFFFFFFD)> R2; typedef User1::quantity, boost::ratio<1> >::type, boost::ratio_subtract, boost::ratio<0> >::type > RR; //~ typedef boost::ratio_subtract::type RS; //~ std::cout << RS::num << '/' << RS::den << '\n'; std::cout << "*************\n"; std::cout << "* testUser1 *\n"; std::cout << "*************\n"; User1::Distance d(( User1::mile(110) )); boost_ex::chrono::hours h((2)); User1::Time t(( h )); //~ boost_ex::chrono::seconds sss=boost_ex::chrono::duration_cast(h); //~ User1::seconds sss((120)); //~ User1::Time t(( sss )); //typedef User1::quantity::type, // boost::ratio_subtract::type > R; RR r=d / t; //r.set(d.get() / t.get()); User1::Speed rc= r; (void)rc; User1::Speed s = d / t; std::cout << "Speed = " << s.get() << " meters/sec\n"; User1::Acceleration a = User1::Distance( User1::foot(32.2) ) / User1::Time() / User1::Time(); std::cout << "Acceleration = " << a.get() << " meters/sec^2\n"; User1::Distance df = compute_distance(s, User1::Time( User1::seconds(0.5) ), a); std::cout << "Distance = " << df.get() << " meters\n"; std::cout << "There are " << User1::mile::ratio::den << '/' << User1::mile::ratio::num << " miles/meter"; User1::meter mt = 1; User1::mile mi = mt; std::cout << " which is approximately " << mi.count() << '\n'; std::cout << "There are " << User1::mile::ratio::num << '/' << User1::mile::ratio::den << " meters/mile"; mi = 1; mt = mi; std::cout << " which is approximately " << mt.count() << '\n'; User1::attosecond as(1); User1::seconds sec = as; std::cout << "1 attosecond is " << sec.count() << " seconds\n"; std::cout << "sec = as; // compiles\n"; sec = User1::seconds(1); as = sec; std::cout << "1 second is " << as.count() << " attoseconds\n"; std::cout << "as = sec; // compiles\n"; std::cout << "\n"; return 0; }