static_rational.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. // Boost.Units - A C++ library for zero-overhead dimensional analysis and
  2. // unit/quantity manipulation and conversion
  3. //
  4. // Copyright (C) 2003-2008 Matthias Christian Schabel
  5. // Copyright (C) 2008 Steven Watanabe
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See
  8. // accompanying file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. #ifndef BOOST_UNITS_STATIC_RATIONAL_HPP
  11. #define BOOST_UNITS_STATIC_RATIONAL_HPP
  12. #include <boost/integer/common_factor_ct.hpp>
  13. #include <boost/mpl/less.hpp>
  14. #include <boost/mpl/arithmetic.hpp>
  15. #ifdef BOOST_BORLANDC
  16. #include <boost/mpl/eval_if.hpp>
  17. #include <boost/mpl/integral_c.hpp>
  18. #include <boost/mpl/identity.hpp>
  19. #endif
  20. #include <boost/units/config.hpp>
  21. #include <boost/units/operators.hpp>
  22. /// \file
  23. /// \brief Compile-time rational numbers and operators.
  24. namespace boost {
  25. namespace units {
  26. namespace detail {
  27. struct static_rational_tag {};
  28. }
  29. typedef long integer_type;
  30. /// Compile time absolute value.
  31. template<integer_type Value>
  32. struct static_abs
  33. {
  34. BOOST_STATIC_CONSTANT(integer_type,value = Value < 0 ? -Value : Value);
  35. };
  36. // Compile time rational number.
  37. /**
  38. This is an implementation of a compile time rational number, where @c static_rational<N,D> represents
  39. a rational number with numerator @c N and denominator @c D. Because of the potential for ambiguity arising
  40. from multiple equivalent values of @c static_rational (e.g. @c static_rational<6,2>==static_rational<3>),
  41. static rationals should always be accessed through @c static_rational<N,D>::type. Template specialization
  42. prevents instantiation of zero denominators (i.e. @c static_rational<N,0>). The following compile-time
  43. arithmetic operators are provided for static_rational variables only (no operators are defined between
  44. long and static_rational):
  45. - @c mpl::negate
  46. - @c mpl::plus
  47. - @c mpl::minus
  48. - @c mpl::times
  49. - @c mpl::divides
  50. Neither @c static_power nor @c static_root are defined for @c static_rational. This is because template types
  51. may not be floating point values, while powers and roots of rational numbers can produce floating point
  52. values.
  53. */
  54. #ifdef BOOST_BORLANDC
  55. template<integer_type X>
  56. struct make_integral_c {
  57. typedef boost::mpl::integral_c<integer_type, X> type;
  58. };
  59. template<integer_type N,integer_type D = 1>
  60. class static_rational
  61. {
  62. public:
  63. typedef static_rational this_type;
  64. typedef boost::mpl::integral_c<integer_type, N> N_type;
  65. typedef boost::mpl::integral_c<integer_type, D> D_type;
  66. typedef typename make_integral_c<
  67. (::boost::integer::static_gcd<
  68. ::boost::units::static_abs<N>::value,
  69. ::boost::units::static_abs<D>::value
  70. >::value)>::type gcd_type;
  71. typedef typename boost::mpl::eval_if<
  72. boost::mpl::less<
  73. D_type,
  74. boost::mpl::integral_c<integer_type, 0>
  75. >,
  76. boost::mpl::negate<gcd_type>,
  77. gcd_type
  78. >::type den_type;
  79. public:
  80. // for mpl arithmetic support
  81. typedef detail::static_rational_tag tag;
  82. BOOST_STATIC_CONSTANT(integer_type, Numerator =
  83. (::boost::mpl::divides<N_type, den_type>::value));
  84. BOOST_STATIC_CONSTANT(integer_type, Denominator =
  85. (::boost::mpl::divides<D_type, den_type>::value));
  86. /// INTERNAL ONLY
  87. typedef static_rational<N,D> this_type;
  88. /// static_rational<N,D> reduced by GCD
  89. typedef static_rational<
  90. (::boost::mpl::divides<N_type, den_type>::value),
  91. (::boost::mpl::divides<D_type, den_type>::value)
  92. > type;
  93. static BOOST_CONSTEXPR integer_type numerator() { return Numerator; }
  94. static BOOST_CONSTEXPR integer_type denominator() { return Denominator; }
  95. // INTERNAL ONLY
  96. BOOST_CONSTEXPR static_rational() { }
  97. //~static_rational() { }
  98. };
  99. #else
  100. template<integer_type N,integer_type D = 1>
  101. class static_rational
  102. {
  103. private:
  104. BOOST_STATIC_CONSTEXPR integer_type nabs = static_abs<N>::value,
  105. dabs = static_abs<D>::value;
  106. /// greatest common divisor of N and D
  107. // need cast to signed because static_gcd returns unsigned long
  108. BOOST_STATIC_CONSTEXPR integer_type den =
  109. static_cast<integer_type>(boost::integer::static_gcd<nabs,dabs>::value) * ((D < 0) ? -1 : 1);
  110. public:
  111. // for mpl arithmetic support
  112. typedef detail::static_rational_tag tag;
  113. BOOST_STATIC_CONSTEXPR integer_type Numerator = N/den,
  114. Denominator = D/den;
  115. /// INTERNAL ONLY
  116. typedef static_rational<N,D> this_type;
  117. /// static_rational<N,D> reduced by GCD
  118. typedef static_rational<Numerator,Denominator> type;
  119. static BOOST_CONSTEXPR integer_type numerator() { return Numerator; }
  120. static BOOST_CONSTEXPR integer_type denominator() { return Denominator; }
  121. // INTERNAL ONLY
  122. BOOST_CONSTEXPR static_rational() { }
  123. //~static_rational() { }
  124. };
  125. #endif
  126. }
  127. }
  128. #if BOOST_UNITS_HAS_BOOST_TYPEOF
  129. #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
  130. BOOST_TYPEOF_REGISTER_TEMPLATE(boost::units::static_rational, (long)(long))
  131. #endif
  132. namespace boost {
  133. namespace units {
  134. // prohibit zero denominator
  135. template<integer_type N> class static_rational<N,0>;
  136. /// get decimal value of @c static_rational
  137. template<class T,integer_type N,integer_type D>
  138. inline BOOST_CONSTEXPR typename divide_typeof_helper<T,T>::type
  139. value(const static_rational<N,D>&)
  140. {
  141. return T(N)/T(D);
  142. }
  143. } // namespace units
  144. #ifndef BOOST_UNITS_DOXYGEN
  145. namespace mpl {
  146. #ifdef BOOST_BORLANDC
  147. template<>
  148. struct plus_impl<boost::units::detail::static_rational_tag, boost::units::detail::static_rational_tag>
  149. {
  150. template<class T0, class T1>
  151. struct apply {
  152. typedef typename boost::units::static_rational<
  153. ::boost::mpl::plus<
  154. boost::mpl::times<typename T0::N_type, typename T1::D_type>,
  155. boost::mpl::times<typename T1::N_type, typename T0::D_type>
  156. >::value,
  157. ::boost::mpl::times<typename T0::D_type, typename T1::D_type>::value
  158. >::type type;
  159. };
  160. };
  161. template<>
  162. struct minus_impl<boost::units::detail::static_rational_tag, boost::units::detail::static_rational_tag>
  163. {
  164. template<class T0, class T1>
  165. struct apply {
  166. typedef typename boost::units::static_rational<
  167. ::boost::mpl::minus<
  168. boost::mpl::times<typename T0::N_type, typename T1::D_type>,
  169. boost::mpl::times<typename T1::N_type, typename T0::D_type>
  170. >::value,
  171. ::boost::mpl::times<typename T0::D_type, typename T1::D_type>::value
  172. >::type type;
  173. };
  174. };
  175. template<>
  176. struct times_impl<boost::units::detail::static_rational_tag, boost::units::detail::static_rational_tag>
  177. {
  178. template<class T0, class T1>
  179. struct apply {
  180. typedef typename boost::units::static_rational<
  181. ::boost::mpl::times<typename T0::N_type, typename T1::N_type>::value,
  182. ::boost::mpl::times<typename T0::D_type, typename T1::D_type>::value
  183. >::type type;
  184. };
  185. };
  186. template<>
  187. struct divides_impl<boost::units::detail::static_rational_tag, boost::units::detail::static_rational_tag>
  188. {
  189. template<class T0, class T1>
  190. struct apply {
  191. typedef typename boost::units::static_rational<
  192. ::boost::mpl::times<typename T0::N_type, typename T1::D_type>::value,
  193. ::boost::mpl::times<typename T0::D_type, typename T1::N_type>::value
  194. >::type type;
  195. };
  196. };
  197. template<>
  198. struct negate_impl<boost::units::detail::static_rational_tag>
  199. {
  200. template<class T0>
  201. struct apply {
  202. typedef typename boost::units::static_rational<
  203. ::boost::mpl::negate<typename T0::N_type>::value,
  204. ::boost::mpl::identity<T0>::type::Denominator
  205. >::type type;
  206. };
  207. };
  208. template<>
  209. struct less_impl<boost::units::detail::static_rational_tag, boost::units::detail::static_rational_tag>
  210. {
  211. template<class T0, class T1>
  212. struct apply
  213. {
  214. typedef mpl::bool_<((mpl::minus<T0, T1>::type::Numerator) < 0)> type;
  215. };
  216. };
  217. #else
  218. template<>
  219. struct plus_impl<boost::units::detail::static_rational_tag, boost::units::detail::static_rational_tag>
  220. {
  221. template<class T0, class T1>
  222. struct apply {
  223. typedef typename boost::units::static_rational<
  224. T0::Numerator*T1::Denominator+T1::Numerator*T0::Denominator,
  225. T0::Denominator*T1::Denominator
  226. >::type type;
  227. };
  228. };
  229. template<>
  230. struct minus_impl<boost::units::detail::static_rational_tag, boost::units::detail::static_rational_tag>
  231. {
  232. template<class T0, class T1>
  233. struct apply {
  234. typedef typename boost::units::static_rational<
  235. T0::Numerator*T1::Denominator-T1::Numerator*T0::Denominator,
  236. T0::Denominator*T1::Denominator
  237. >::type type;
  238. };
  239. };
  240. template<>
  241. struct times_impl<boost::units::detail::static_rational_tag, boost::units::detail::static_rational_tag>
  242. {
  243. template<class T0, class T1>
  244. struct apply {
  245. typedef typename boost::units::static_rational<
  246. T0::Numerator*T1::Numerator,
  247. T0::Denominator*T1::Denominator
  248. >::type type;
  249. };
  250. };
  251. template<>
  252. struct divides_impl<boost::units::detail::static_rational_tag, boost::units::detail::static_rational_tag>
  253. {
  254. template<class T0, class T1>
  255. struct apply {
  256. typedef typename boost::units::static_rational<
  257. T0::Numerator*T1::Denominator,
  258. T0::Denominator*T1::Numerator
  259. >::type type;
  260. };
  261. };
  262. template<>
  263. struct negate_impl<boost::units::detail::static_rational_tag>
  264. {
  265. template<class T0>
  266. struct apply {
  267. typedef typename boost::units::static_rational<-T0::Numerator,T0::Denominator>::type type;
  268. };
  269. };
  270. template<>
  271. struct less_impl<boost::units::detail::static_rational_tag, boost::units::detail::static_rational_tag>
  272. {
  273. template<class T0, class T1>
  274. struct apply
  275. {
  276. typedef mpl::bool_<((mpl::minus<T0, T1>::type::Numerator) < 0)> type;
  277. };
  278. };
  279. #endif
  280. }
  281. #endif
  282. } // namespace boost
  283. #endif // BOOST_UNITS_STATIC_RATIONAL_HPP