// Boost.Units - A C++ library for zero-overhead dimensional analysis and // unit/quantity manipulation and conversion // // Copyright (C) 2003-2008 Matthias Christian Schabel // Copyright (C) 2008 Steven Watanabe // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_UNITS_STATIC_RATIONAL_HPP #define BOOST_UNITS_STATIC_RATIONAL_HPP #include #include #include #ifdef BOOST_BORLANDC #include #include #include #endif #include #include /// \file /// \brief Compile-time rational numbers and operators. namespace boost { namespace units { namespace detail { struct static_rational_tag {}; } typedef long integer_type; /// Compile time absolute value. template struct static_abs { BOOST_STATIC_CONSTANT(integer_type,value = Value < 0 ? -Value : Value); }; // Compile time rational number. /** This is an implementation of a compile time rational number, where @c static_rational represents a rational number with numerator @c N and denominator @c D. Because of the potential for ambiguity arising from multiple equivalent values of @c static_rational (e.g. @c static_rational<6,2>==static_rational<3>), static rationals should always be accessed through @c static_rational::type. Template specialization prevents instantiation of zero denominators (i.e. @c static_rational). The following compile-time arithmetic operators are provided for static_rational variables only (no operators are defined between long and static_rational): - @c mpl::negate - @c mpl::plus - @c mpl::minus - @c mpl::times - @c mpl::divides Neither @c static_power nor @c static_root are defined for @c static_rational. This is because template types may not be floating point values, while powers and roots of rational numbers can produce floating point values. */ #ifdef BOOST_BORLANDC template struct make_integral_c { typedef boost::mpl::integral_c type; }; template class static_rational { public: typedef static_rational this_type; typedef boost::mpl::integral_c N_type; typedef boost::mpl::integral_c D_type; typedef typename make_integral_c< (::boost::integer::static_gcd< ::boost::units::static_abs::value, ::boost::units::static_abs::value >::value)>::type gcd_type; typedef typename boost::mpl::eval_if< boost::mpl::less< D_type, boost::mpl::integral_c >, boost::mpl::negate, gcd_type >::type den_type; public: // for mpl arithmetic support typedef detail::static_rational_tag tag; BOOST_STATIC_CONSTANT(integer_type, Numerator = (::boost::mpl::divides::value)); BOOST_STATIC_CONSTANT(integer_type, Denominator = (::boost::mpl::divides::value)); /// INTERNAL ONLY typedef static_rational this_type; /// static_rational reduced by GCD typedef static_rational< (::boost::mpl::divides::value), (::boost::mpl::divides::value) > type; static BOOST_CONSTEXPR integer_type numerator() { return Numerator; } static BOOST_CONSTEXPR integer_type denominator() { return Denominator; } // INTERNAL ONLY BOOST_CONSTEXPR static_rational() { } //~static_rational() { } }; #else template class static_rational { private: BOOST_STATIC_CONSTEXPR integer_type nabs = static_abs::value, dabs = static_abs::value; /// greatest common divisor of N and D // need cast to signed because static_gcd returns unsigned long BOOST_STATIC_CONSTEXPR integer_type den = static_cast(boost::integer::static_gcd::value) * ((D < 0) ? -1 : 1); public: // for mpl arithmetic support typedef detail::static_rational_tag tag; BOOST_STATIC_CONSTEXPR integer_type Numerator = N/den, Denominator = D/den; /// INTERNAL ONLY typedef static_rational this_type; /// static_rational reduced by GCD typedef static_rational type; static BOOST_CONSTEXPR integer_type numerator() { return Numerator; } static BOOST_CONSTEXPR integer_type denominator() { return Denominator; } // INTERNAL ONLY BOOST_CONSTEXPR static_rational() { } //~static_rational() { } }; #endif } } #if BOOST_UNITS_HAS_BOOST_TYPEOF #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() BOOST_TYPEOF_REGISTER_TEMPLATE(boost::units::static_rational, (long)(long)) #endif namespace boost { namespace units { // prohibit zero denominator template class static_rational; /// get decimal value of @c static_rational template inline BOOST_CONSTEXPR typename divide_typeof_helper::type value(const static_rational&) { return T(N)/T(D); } } // namespace units #ifndef BOOST_UNITS_DOXYGEN namespace mpl { #ifdef BOOST_BORLANDC template<> struct plus_impl { template struct apply { typedef typename boost::units::static_rational< ::boost::mpl::plus< boost::mpl::times, boost::mpl::times >::value, ::boost::mpl::times::value >::type type; }; }; template<> struct minus_impl { template struct apply { typedef typename boost::units::static_rational< ::boost::mpl::minus< boost::mpl::times, boost::mpl::times >::value, ::boost::mpl::times::value >::type type; }; }; template<> struct times_impl { template struct apply { typedef typename boost::units::static_rational< ::boost::mpl::times::value, ::boost::mpl::times::value >::type type; }; }; template<> struct divides_impl { template struct apply { typedef typename boost::units::static_rational< ::boost::mpl::times::value, ::boost::mpl::times::value >::type type; }; }; template<> struct negate_impl { template struct apply { typedef typename boost::units::static_rational< ::boost::mpl::negate::value, ::boost::mpl::identity::type::Denominator >::type type; }; }; template<> struct less_impl { template struct apply { typedef mpl::bool_<((mpl::minus::type::Numerator) < 0)> type; }; }; #else template<> struct plus_impl { template struct apply { typedef typename boost::units::static_rational< T0::Numerator*T1::Denominator+T1::Numerator*T0::Denominator, T0::Denominator*T1::Denominator >::type type; }; }; template<> struct minus_impl { template struct apply { typedef typename boost::units::static_rational< T0::Numerator*T1::Denominator-T1::Numerator*T0::Denominator, T0::Denominator*T1::Denominator >::type type; }; }; template<> struct times_impl { template struct apply { typedef typename boost::units::static_rational< T0::Numerator*T1::Numerator, T0::Denominator*T1::Denominator >::type type; }; }; template<> struct divides_impl { template struct apply { typedef typename boost::units::static_rational< T0::Numerator*T1::Denominator, T0::Denominator*T1::Numerator >::type type; }; }; template<> struct negate_impl { template struct apply { typedef typename boost::units::static_rational<-T0::Numerator,T0::Denominator>::type type; }; }; template<> struct less_impl { template struct apply { typedef mpl::bool_<((mpl::minus::type::Numerator) < 0)> type; }; }; #endif } #endif } // namespace boost #endif // BOOST_UNITS_STATIC_RATIONAL_HPP