overflow_helpers.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. // ratio.hpp ---------------------------------------------------------------//
  2. // Copyright 2008 Howard Hinnant
  3. // Copyright 2008 Beman Dawes
  4. // Copyright 2009 Vicente J. Botet Escriba
  5. // Distributed under the Boost Software License, Version 1.0.
  6. // See http://www.boost.org/LICENSE_1_0.txt
  7. /*
  8. This code was derived by Beman Dawes from Howard Hinnant's time2_demo prototype.
  9. Many thanks to Howard for making his code available under the Boost license.
  10. The original code was modified to conform to Boost conventions and to section
  11. 20.4 Compile-time rational arithmetic [ratio], of the C++ committee working
  12. paper N2798.
  13. See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf.
  14. time2_demo contained this comment:
  15. Much thanks to Andrei Alexandrescu,
  16. Walter Brown,
  17. Peter Dimov,
  18. Jeff Garland,
  19. Terry Golubiewski,
  20. Daniel Krugler,
  21. Anthony Williams.
  22. */
  23. // The way overflow is managed for ratio_less is taken from llvm/libcxx/include/ratio
  24. #ifndef BOOST_RATIO_DETAIL_RATIO_OPERATIONS_HPP
  25. #define BOOST_RATIO_DETAIL_RATIO_OPERATIONS_HPP
  26. #include <boost/ratio/config.hpp>
  27. #include <boost/ratio/detail/mpl/abs.hpp>
  28. #include <boost/ratio/detail/mpl/sign.hpp>
  29. #include <cstdlib>
  30. #include <climits>
  31. #include <limits>
  32. #include <boost/cstdint.hpp>
  33. #include <boost/type_traits/integral_constant.hpp>
  34. #include <boost/core/enable_if.hpp>
  35. #include <boost/integer_traits.hpp>
  36. //
  37. // We simply cannot include this header on gcc without getting copious warnings of the kind:
  38. //
  39. // boost/integer.hpp:77:30: warning: use of C99 long long integer constant
  40. //
  41. // And yet there is no other reasonable implementation, so we declare this a system header
  42. // to suppress these warnings.
  43. //
  44. #if defined(__GNUC__) && (__GNUC__ >= 4)
  45. #pragma GCC system_header
  46. #endif
  47. namespace boost
  48. {
  49. //----------------------------------------------------------------------------//
  50. // helpers //
  51. //----------------------------------------------------------------------------//
  52. namespace ratio_detail
  53. {
  54. template <boost::intmax_t X, boost::intmax_t Y, boost::intmax_t = mpl::sign_c<boost::intmax_t, Y>::value>
  55. class br_add;
  56. template <boost::intmax_t X, boost::intmax_t Y>
  57. class br_add<X, Y, 1>
  58. {
  59. static const boost::intmax_t min = boost::integer_traits<boost::intmax_t>::const_min;
  60. static const boost::intmax_t max = boost::integer_traits<boost::intmax_t>::const_max;
  61. BOOST_RATIO_STATIC_ASSERT(X <= max - Y , BOOST_RATIO_OVERFLOW_IN_ADD, ());
  62. public:
  63. static const boost::intmax_t value = X + Y;
  64. };
  65. template <boost::intmax_t X, boost::intmax_t Y>
  66. class br_add<X, Y, 0>
  67. {
  68. public:
  69. static const boost::intmax_t value = X;
  70. };
  71. template <boost::intmax_t X, boost::intmax_t Y>
  72. class br_add<X, Y, -1>
  73. {
  74. static const boost::intmax_t min = boost::integer_traits<boost::intmax_t>::const_min;
  75. static const boost::intmax_t max = boost::integer_traits<boost::intmax_t>::const_max;
  76. BOOST_RATIO_STATIC_ASSERT(min - Y <= X, BOOST_RATIO_OVERFLOW_IN_ADD, ());
  77. public:
  78. static const boost::intmax_t value = X + Y;
  79. };
  80. template <boost::intmax_t X, boost::intmax_t Y, boost::intmax_t = mpl::sign_c<boost::intmax_t, Y>::value>
  81. class br_sub;
  82. template <boost::intmax_t X, boost::intmax_t Y>
  83. class br_sub<X, Y, 1>
  84. {
  85. static const boost::intmax_t min = boost::integer_traits<boost::intmax_t>::const_min;
  86. static const boost::intmax_t max = boost::integer_traits<boost::intmax_t>::const_max;
  87. BOOST_RATIO_STATIC_ASSERT(min + Y <= X, BOOST_RATIO_OVERFLOW_IN_SUB, ());
  88. public:
  89. static const boost::intmax_t value = X - Y;
  90. };
  91. template <boost::intmax_t X, boost::intmax_t Y>
  92. class br_sub<X, Y, 0>
  93. {
  94. public:
  95. static const boost::intmax_t value = X;
  96. };
  97. template <boost::intmax_t X, boost::intmax_t Y>
  98. class br_sub<X, Y, -1>
  99. {
  100. static const boost::intmax_t min = boost::integer_traits<boost::intmax_t>::const_min;
  101. static const boost::intmax_t max = boost::integer_traits<boost::intmax_t>::const_max;
  102. BOOST_RATIO_STATIC_ASSERT(X <= max + Y, BOOST_RATIO_OVERFLOW_IN_SUB, ());
  103. public:
  104. static const boost::intmax_t value = X - Y;
  105. };
  106. template <boost::intmax_t X, boost::intmax_t Y>
  107. class br_mul
  108. {
  109. static const boost::intmax_t nan =
  110. boost::intmax_t(BOOST_RATIO_UINTMAX_C(1) << (sizeof(boost::intmax_t) * CHAR_BIT - 1));
  111. static const boost::intmax_t min = boost::integer_traits<boost::intmax_t>::const_min;
  112. static const boost::intmax_t max = boost::integer_traits<boost::intmax_t>::const_max;
  113. static const boost::intmax_t a_x = mpl::abs_c<boost::intmax_t, X>::value;
  114. static const boost::intmax_t a_y = mpl::abs_c<boost::intmax_t, Y>::value;
  115. BOOST_RATIO_STATIC_ASSERT(X != nan, BOOST_RATIO_OVERFLOW_IN_MUL, ());
  116. BOOST_RATIO_STATIC_ASSERT(Y != nan, BOOST_RATIO_OVERFLOW_IN_MUL, ());
  117. BOOST_RATIO_STATIC_ASSERT(a_x <= max / a_y, BOOST_RATIO_OVERFLOW_IN_MUL, ());
  118. public:
  119. static const boost::intmax_t value = X * Y;
  120. };
  121. template <boost::intmax_t Y>
  122. class br_mul<0, Y>
  123. {
  124. public:
  125. static const boost::intmax_t value = 0;
  126. };
  127. template <boost::intmax_t X>
  128. class br_mul<X, 0>
  129. {
  130. public:
  131. static const boost::intmax_t value = 0;
  132. };
  133. template <>
  134. class br_mul<0, 0>
  135. {
  136. public:
  137. static const boost::intmax_t value = 0;
  138. };
  139. // Not actually used but left here in case needed in future maintenance
  140. template <boost::intmax_t X, boost::intmax_t Y>
  141. class br_div
  142. {
  143. static const boost::intmax_t nan = boost::intmax_t(BOOST_RATIO_UINTMAX_C(1) << (sizeof(boost::intmax_t) * CHAR_BIT - 1));
  144. static const boost::intmax_t min = boost::integer_traits<boost::intmax_t>::const_min;
  145. static const boost::intmax_t max = boost::integer_traits<boost::intmax_t>::const_max;
  146. BOOST_RATIO_STATIC_ASSERT(X != nan, BOOST_RATIO_OVERFLOW_IN_DIV, ());
  147. BOOST_RATIO_STATIC_ASSERT(Y != nan, BOOST_RATIO_OVERFLOW_IN_DIV, ());
  148. BOOST_RATIO_STATIC_ASSERT(Y != 0, BOOST_RATIO_DIVIDE_BY_0, ());
  149. public:
  150. static const boost::intmax_t value = X / Y;
  151. };
  152. // ratio arithmetic
  153. template <class R1, class R2> struct ratio_add;
  154. template <class R1, class R2> struct ratio_subtract;
  155. template <class R1, class R2> struct ratio_multiply;
  156. template <class R1, class R2> struct ratio_divide;
  157. template <class R1, class R2>
  158. struct ratio_add
  159. {
  160. //The nested typedef type shall be a synonym for ratio<T1, T2>::type where T1 has the value R1::num *
  161. //R2::den + R2::num * R1::den and T2 has the value R1::den * R2::den.
  162. // As the preceding doesn't works because of overflow on boost::intmax_t we need something more elaborated.
  163. private:
  164. static const boost::intmax_t gcd_n1_n2 = mpl::gcd_c<boost::intmax_t, R1::num, R2::num>::value;
  165. static const boost::intmax_t gcd_d1_d2 = mpl::gcd_c<boost::intmax_t, R1::den, R2::den>::value;
  166. public:
  167. // No need to normalize as ratio_multiply is already normalized
  168. typedef typename ratio_multiply
  169. <
  170. ratio<gcd_n1_n2, R1::den / gcd_d1_d2>,
  171. ratio
  172. <
  173. boost::ratio_detail::br_add
  174. <
  175. boost::ratio_detail::br_mul<R1::num / gcd_n1_n2, R2::den / gcd_d1_d2>::value,
  176. boost::ratio_detail::br_mul<R2::num / gcd_n1_n2, R1::den / gcd_d1_d2>::value
  177. >::value,
  178. R2::den
  179. >
  180. >::type type;
  181. };
  182. template <class R, boost::intmax_t D>
  183. struct ratio_add<R, ratio<0,D> >
  184. {
  185. typedef R type;
  186. };
  187. template <class R1, class R2>
  188. struct ratio_subtract
  189. {
  190. //The nested typedef type shall be a synonym for ratio<T1, T2>::type where T1 has the value
  191. // R1::num *R2::den - R2::num * R1::den and T2 has the value R1::den * R2::den.
  192. // As the preceding doesn't works because of overflow on boost::intmax_t we need something more elaborated.
  193. private:
  194. static const boost::intmax_t gcd_n1_n2 = mpl::gcd_c<boost::intmax_t, R1::num, R2::num>::value;
  195. static const boost::intmax_t gcd_d1_d2 = mpl::gcd_c<boost::intmax_t, R1::den, R2::den>::value;
  196. public:
  197. // No need to normalize as ratio_multiply is already normalized
  198. typedef typename ratio_multiply
  199. <
  200. ratio<gcd_n1_n2, R1::den / gcd_d1_d2>,
  201. ratio
  202. <
  203. boost::ratio_detail::br_sub
  204. <
  205. boost::ratio_detail::br_mul<R1::num / gcd_n1_n2, R2::den / gcd_d1_d2>::value,
  206. boost::ratio_detail::br_mul<R2::num / gcd_n1_n2, R1::den / gcd_d1_d2>::value
  207. >::value,
  208. R2::den
  209. >
  210. >::type type;
  211. };
  212. template <class R, boost::intmax_t D>
  213. struct ratio_subtract<R, ratio<0,D> >
  214. {
  215. typedef R type;
  216. };
  217. template <class R1, class R2>
  218. struct ratio_multiply
  219. {
  220. // The nested typedef type shall be a synonym for ratio<R1::num * R2::den - R2::num * R1::den, R1::den * R2::den>::type.
  221. // As the preceding doesn't works because of overflow on boost::intmax_t we need something more elaborated.
  222. private:
  223. static const boost::intmax_t gcd_n1_d2 = mpl::gcd_c<boost::intmax_t, R1::num, R2::den>::value;
  224. static const boost::intmax_t gcd_d1_n2 = mpl::gcd_c<boost::intmax_t, R1::den, R2::num>::value;
  225. public:
  226. typedef typename ratio
  227. <
  228. boost::ratio_detail::br_mul<R1::num / gcd_n1_d2, R2::num / gcd_d1_n2>::value,
  229. boost::ratio_detail::br_mul<R2::den / gcd_n1_d2, R1::den / gcd_d1_n2>::value
  230. >::type type;
  231. };
  232. template <class R1, class R2>
  233. struct ratio_divide
  234. {
  235. // The nested typedef type shall be a synonym for ratio<R1::num * R2::den, R2::num * R1::den>::type.
  236. // As the preceding doesn't works because of overflow on boost::intmax_t we need something more elaborated.
  237. private:
  238. static const boost::intmax_t gcd_n1_n2 = mpl::gcd_c<boost::intmax_t, R1::num, R2::num>::value;
  239. static const boost::intmax_t gcd_d1_d2 = mpl::gcd_c<boost::intmax_t, R1::den, R2::den>::value;
  240. public:
  241. typedef typename ratio
  242. <
  243. boost::ratio_detail::br_mul<R1::num / gcd_n1_n2, R2::den / gcd_d1_d2>::value,
  244. boost::ratio_detail::br_mul<R2::num / gcd_n1_n2, R1::den / gcd_d1_d2>::value
  245. >::type type;
  246. };
  247. template <class R1, class R2>
  248. struct is_evenly_divisible_by
  249. {
  250. private:
  251. static const boost::intmax_t gcd_n1_n2 = mpl::gcd_c<boost::intmax_t, R1::num, R2::num>::value;
  252. static const boost::intmax_t gcd_d1_d2 = mpl::gcd_c<boost::intmax_t, R1::den, R2::den>::value;
  253. public:
  254. typedef integral_constant<bool,
  255. ((R2::num / gcd_n1_n2 ==1) && (R1::den / gcd_d1_d2)==1)
  256. > type;
  257. };
  258. template <class T>
  259. struct is_ratio : public boost::false_type
  260. {};
  261. template <boost::intmax_t N, boost::intmax_t D>
  262. struct is_ratio<ratio<N, D> > : public boost::true_type
  263. {};
  264. template <class R1, class R2,
  265. boost::intmax_t Q1 = R1::num / R1::den, boost::intmax_t M1 = R1::num % R1::den,
  266. boost::intmax_t Q2 = R2::num / R2::den, boost::intmax_t M2 = R2::num % R2::den>
  267. struct ratio_less1
  268. {
  269. static const bool value = Q1 < Q2;
  270. };
  271. template <class R1, class R2, boost::intmax_t Q>
  272. struct ratio_less1<R1, R2, Q, 0, Q, 0>
  273. {
  274. static const bool value = false;
  275. };
  276. template <class R1, class R2, boost::intmax_t Q, boost::intmax_t M2>
  277. struct ratio_less1<R1, R2, Q, 0, Q, M2>
  278. {
  279. static const bool value = true;
  280. };
  281. template <class R1, class R2, boost::intmax_t Q, boost::intmax_t M1>
  282. struct ratio_less1<R1, R2, Q, M1, Q, 0>
  283. {
  284. static const bool value = false;
  285. };
  286. template <class R1, class R2, boost::intmax_t Q, boost::intmax_t M1, boost::intmax_t M2>
  287. struct ratio_less1<R1, R2, Q, M1, Q, M2>
  288. {
  289. static const bool value = ratio_less1<ratio<R2::den, M2>, ratio<R1::den, M1>
  290. >::value;
  291. };
  292. template <
  293. class R1,
  294. class R2,
  295. boost::intmax_t S1 = mpl::sign_c<boost::intmax_t, R1::num>::value,
  296. boost::intmax_t S2 = mpl::sign_c<boost::intmax_t, R2::num>::value
  297. >
  298. struct ratio_less
  299. {
  300. static const bool value = S1 < S2;
  301. };
  302. template <class R1, class R2>
  303. struct ratio_less<R1, R2, 1LL, 1LL>
  304. {
  305. static const bool value = ratio_less1<R1, R2>::value;
  306. };
  307. template <class R1, class R2>
  308. struct ratio_less<R1, R2, -1LL, -1LL>
  309. {
  310. static const bool value = ratio_less1<ratio<-R2::num, R2::den>,
  311. ratio<-R1::num, R1::den> >::value;
  312. };
  313. } // namespace ratio_detail
  314. } // namespace boost
  315. #endif // BOOST_RATIO_HPP