Chris@16: // ratio.hpp ---------------------------------------------------------------// Chris@16: Chris@16: // Copyright 2008 Howard Hinnant Chris@16: // Copyright 2008 Beman Dawes Chris@16: // Copyright 2009 Vicente J. Botet Escriba Chris@16: Chris@16: // Distributed under the Boost Software License, Version 1.0. Chris@16: // See http://www.boost.org/LICENSE_1_0.txt Chris@16: Chris@16: /* Chris@16: Chris@16: This code was derived by Beman Dawes from Howard Hinnant's time2_demo prototype. Chris@16: Many thanks to Howard for making his code available under the Boost license. Chris@16: The original code was modified to conform to Boost conventions and to section Chris@16: 20.4 Compile-time rational arithmetic [ratio], of the C++ committee working Chris@16: paper N2798. Chris@16: See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf. Chris@16: Chris@16: time2_demo contained this comment: Chris@16: Chris@16: Much thanks to Andrei Alexandrescu, Chris@16: Walter Brown, Chris@16: Peter Dimov, Chris@16: Jeff Garland, Chris@16: Terry Golubiewski, Chris@16: Daniel Krugler, Chris@16: Anthony Williams. Chris@16: */ Chris@16: Chris@16: // The way overflow is managed for ratio_less is taken from llvm/libcxx/include/ratio Chris@16: Chris@16: #ifndef BOOST_RATIO_DETAIL_RATIO_OPERATIONS_HPP Chris@16: #define BOOST_RATIO_DETAIL_RATIO_OPERATIONS_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: #include Chris@16: Chris@16: // Chris@16: // We simply cannot include this header on gcc without getting copious warnings of the kind: Chris@16: // Chris@16: // boost/integer.hpp:77:30: warning: use of C99 long long integer constant Chris@16: // Chris@16: // And yet there is no other reasonable implementation, so we declare this a system header Chris@16: // to suppress these warnings. Chris@16: // Chris@16: #if defined(__GNUC__) && (__GNUC__ >= 4) Chris@16: #pragma GCC system_header Chris@16: #endif Chris@16: Chris@16: namespace boost Chris@16: { Chris@16: Chris@16: //----------------------------------------------------------------------------// Chris@16: // helpers // Chris@16: //----------------------------------------------------------------------------// Chris@16: Chris@16: namespace ratio_detail Chris@16: { Chris@16: Chris@16: template ::value> Chris@16: class br_add; Chris@16: Chris@16: template Chris@16: class br_add Chris@16: { Chris@16: static const boost::intmax_t min = boost::integer_traits::const_min; Chris@16: static const boost::intmax_t max = boost::integer_traits::const_max; Chris@16: Chris@16: BOOST_RATIO_STATIC_ASSERT(X <= max - Y , BOOST_RATIO_OVERFLOW_IN_ADD, ()); Chris@16: public: Chris@16: static const boost::intmax_t value = X + Y; Chris@16: }; Chris@16: Chris@16: template Chris@16: class br_add Chris@16: { Chris@16: public: Chris@16: static const boost::intmax_t value = X; Chris@16: }; Chris@16: Chris@16: template Chris@16: class br_add Chris@16: { Chris@16: static const boost::intmax_t min = boost::integer_traits::const_min; Chris@16: static const boost::intmax_t max = boost::integer_traits::const_max; Chris@16: Chris@16: BOOST_RATIO_STATIC_ASSERT(min - Y <= X, BOOST_RATIO_OVERFLOW_IN_ADD, ()); Chris@16: public: Chris@16: static const boost::intmax_t value = X + Y; Chris@16: }; Chris@16: Chris@16: template ::value> Chris@16: class br_sub; Chris@16: Chris@16: template Chris@16: class br_sub Chris@16: { Chris@16: static const boost::intmax_t min = boost::integer_traits::const_min; Chris@16: static const boost::intmax_t max = boost::integer_traits::const_max; Chris@16: Chris@16: BOOST_RATIO_STATIC_ASSERT(min + Y <= X, BOOST_RATIO_OVERFLOW_IN_SUB, ()); Chris@16: public: Chris@16: static const boost::intmax_t value = X - Y; Chris@16: }; Chris@16: Chris@16: template Chris@16: class br_sub Chris@16: { Chris@16: public: Chris@16: static const boost::intmax_t value = X; Chris@16: }; Chris@16: Chris@16: template Chris@16: class br_sub Chris@16: { Chris@16: static const boost::intmax_t min = boost::integer_traits::const_min; Chris@16: static const boost::intmax_t max = boost::integer_traits::const_max; Chris@16: Chris@16: BOOST_RATIO_STATIC_ASSERT(X <= max + Y, BOOST_RATIO_OVERFLOW_IN_SUB, ()); Chris@16: public: Chris@16: static const boost::intmax_t value = X - Y; Chris@16: }; Chris@16: Chris@16: template Chris@16: class br_mul Chris@16: { Chris@16: static const boost::intmax_t nan = Chris@16: boost::intmax_t(BOOST_RATIO_UINTMAX_C(1) << (sizeof(boost::intmax_t) * CHAR_BIT - 1)); Chris@16: static const boost::intmax_t min = boost::integer_traits::const_min; Chris@16: static const boost::intmax_t max = boost::integer_traits::const_max; Chris@16: Chris@16: static const boost::intmax_t a_x = mpl::abs_c::value; Chris@16: static const boost::intmax_t a_y = mpl::abs_c::value; Chris@16: Chris@16: BOOST_RATIO_STATIC_ASSERT(X != nan, BOOST_RATIO_OVERFLOW_IN_MUL, ()); Chris@16: BOOST_RATIO_STATIC_ASSERT(Y != nan, BOOST_RATIO_OVERFLOW_IN_MUL, ()); Chris@16: BOOST_RATIO_STATIC_ASSERT(a_x <= max / a_y, BOOST_RATIO_OVERFLOW_IN_MUL, ()); Chris@16: public: Chris@16: static const boost::intmax_t value = X * Y; Chris@16: }; Chris@16: Chris@16: template Chris@16: class br_mul<0, Y> Chris@16: { Chris@16: public: Chris@16: static const boost::intmax_t value = 0; Chris@16: }; Chris@16: Chris@16: template Chris@16: class br_mul Chris@16: { Chris@16: public: Chris@16: static const boost::intmax_t value = 0; Chris@16: }; Chris@16: Chris@16: template <> Chris@16: class br_mul<0, 0> Chris@16: { Chris@16: public: Chris@16: static const boost::intmax_t value = 0; Chris@16: }; Chris@16: Chris@16: // Not actually used but left here in case needed in future maintenance Chris@16: template Chris@16: class br_div Chris@16: { Chris@16: static const boost::intmax_t nan = boost::intmax_t(BOOST_RATIO_UINTMAX_C(1) << (sizeof(boost::intmax_t) * CHAR_BIT - 1)); Chris@16: static const boost::intmax_t min = boost::integer_traits::const_min; Chris@16: static const boost::intmax_t max = boost::integer_traits::const_max; Chris@16: Chris@16: BOOST_RATIO_STATIC_ASSERT(X != nan, BOOST_RATIO_OVERFLOW_IN_DIV, ()); Chris@16: BOOST_RATIO_STATIC_ASSERT(Y != nan, BOOST_RATIO_OVERFLOW_IN_DIV, ()); Chris@16: BOOST_RATIO_STATIC_ASSERT(Y != 0, BOOST_RATIO_DIVIDE_BY_0, ()); Chris@16: public: Chris@16: static const boost::intmax_t value = X / Y; Chris@16: }; Chris@16: Chris@16: // ratio arithmetic Chris@16: template struct ratio_add; Chris@16: template struct ratio_subtract; Chris@16: template struct ratio_multiply; Chris@16: template struct ratio_divide; Chris@16: Chris@16: template Chris@16: struct ratio_add Chris@16: { Chris@16: //The nested typedef type shall be a synonym for ratio::type where T1 has the value R1::num * Chris@16: //R2::den + R2::num * R1::den and T2 has the value R1::den * R2::den. Chris@16: // As the preceding doesn't works because of overflow on boost::intmax_t we need something more elaborated. Chris@16: private: Chris@16: static const boost::intmax_t gcd_n1_n2 = mpl::gcd_c::value; Chris@16: static const boost::intmax_t gcd_d1_d2 = mpl::gcd_c::value; Chris@16: public: Chris@16: // No need to normalize as ratio_multiply is already normalized Chris@16: typedef typename ratio_multiply Chris@16: < Chris@16: ratio, Chris@16: ratio Chris@16: < Chris@16: boost::ratio_detail::br_add Chris@16: < Chris@16: boost::ratio_detail::br_mul::value, Chris@16: boost::ratio_detail::br_mul::value Chris@16: >::value, Chris@16: R2::den Chris@16: > Chris@16: >::type type; Chris@16: }; Chris@16: template Chris@16: struct ratio_add > Chris@16: { Chris@16: typedef R type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct ratio_subtract Chris@16: { Chris@16: //The nested typedef type shall be a synonym for ratio::type where T1 has the value Chris@16: // R1::num *R2::den - R2::num * R1::den and T2 has the value R1::den * R2::den. Chris@16: // As the preceding doesn't works because of overflow on boost::intmax_t we need something more elaborated. Chris@16: private: Chris@16: static const boost::intmax_t gcd_n1_n2 = mpl::gcd_c::value; Chris@16: static const boost::intmax_t gcd_d1_d2 = mpl::gcd_c::value; Chris@16: public: Chris@16: // No need to normalize as ratio_multiply is already normalized Chris@16: typedef typename ratio_multiply Chris@16: < Chris@16: ratio, Chris@16: ratio Chris@16: < Chris@16: boost::ratio_detail::br_sub Chris@16: < Chris@16: boost::ratio_detail::br_mul::value, Chris@16: boost::ratio_detail::br_mul::value Chris@16: >::value, Chris@16: R2::den Chris@16: > Chris@16: >::type type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct ratio_subtract > Chris@16: { Chris@16: typedef R type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct ratio_multiply Chris@16: { Chris@16: // The nested typedef type shall be a synonym for ratio::type. Chris@16: // As the preceding doesn't works because of overflow on boost::intmax_t we need something more elaborated. Chris@16: private: Chris@16: static const boost::intmax_t gcd_n1_d2 = mpl::gcd_c::value; Chris@16: static const boost::intmax_t gcd_d1_n2 = mpl::gcd_c::value; Chris@16: public: Chris@16: typedef typename ratio Chris@16: < Chris@16: boost::ratio_detail::br_mul::value, Chris@16: boost::ratio_detail::br_mul::value Chris@16: >::type type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct ratio_divide Chris@16: { Chris@16: // The nested typedef type shall be a synonym for ratio::type. Chris@16: // As the preceding doesn't works because of overflow on boost::intmax_t we need something more elaborated. Chris@16: private: Chris@16: static const boost::intmax_t gcd_n1_n2 = mpl::gcd_c::value; Chris@16: static const boost::intmax_t gcd_d1_d2 = mpl::gcd_c::value; Chris@16: public: Chris@16: typedef typename ratio Chris@16: < Chris@16: boost::ratio_detail::br_mul::value, Chris@16: boost::ratio_detail::br_mul::value Chris@16: >::type type; Chris@16: }; Chris@16: template Chris@16: struct is_evenly_divisible_by Chris@16: { Chris@16: private: Chris@16: static const boost::intmax_t gcd_n1_n2 = mpl::gcd_c::value; Chris@16: static const boost::intmax_t gcd_d1_d2 = mpl::gcd_c::value; Chris@16: public: Chris@16: typedef integral_constant type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct is_ratio : public boost::false_type Chris@16: {}; Chris@16: template Chris@16: struct is_ratio > : public boost::true_type Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct ratio_less1 Chris@16: { Chris@16: static const bool value = Q1 < Q2; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct ratio_less1 Chris@16: { Chris@16: static const bool value = false; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct ratio_less1 Chris@16: { Chris@16: static const bool value = true; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct ratio_less1 Chris@16: { Chris@16: static const bool value = false; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct ratio_less1 Chris@16: { Chris@16: static const bool value = ratio_less1, ratio Chris@16: >::value; Chris@16: }; Chris@16: Chris@16: template < Chris@16: class R1, Chris@16: class R2, Chris@16: boost::intmax_t S1 = mpl::sign_c::value, Chris@16: boost::intmax_t S2 = mpl::sign_c::value Chris@16: > Chris@16: struct ratio_less Chris@16: { Chris@16: static const bool value = S1 < S2; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct ratio_less Chris@16: { Chris@16: static const bool value = ratio_less1::value; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct ratio_less Chris@16: { Chris@16: static const bool value = ratio_less1, Chris@16: ratio<-R1::num, R1::den> >::value; Chris@16: }; Chris@16: Chris@16: Chris@16: } // namespace ratio_detail Chris@16: Chris@16: } // namespace boost Chris@16: Chris@16: #endif // BOOST_RATIO_HPP