common_factor_rt.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. // (C) Copyright Jeremy William Murphy 2016.
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_INTEGER_COMMON_FACTOR_RT_HPP
  6. #define BOOST_INTEGER_COMMON_FACTOR_RT_HPP
  7. #include <boost/assert.hpp>
  8. #include <boost/core/enable_if.hpp>
  9. #include <boost/config.hpp> // for BOOST_NESTED_TEMPLATE, etc.
  10. #include <boost/limits.hpp> // for std::numeric_limits
  11. #include <climits> // for CHAR_MIN
  12. #include <boost/detail/workaround.hpp>
  13. #include <iterator>
  14. #include <algorithm>
  15. #include <limits>
  16. #ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
  17. #include <type_traits>
  18. #endif
  19. #ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
  20. #include <functional>
  21. #endif
  22. #if ((defined(BOOST_MSVC) && (BOOST_MSVC >= 1600)) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64))
  23. #include <intrin.h>
  24. #endif
  25. #ifdef BOOST_MSVC
  26. #pragma warning(push)
  27. #pragma warning(disable:4127 4244) // Conditional expression is constant
  28. #endif
  29. #if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) && !defined(BOOST_NO_CXX11_NOEXCEPT)
  30. #define BOOST_GCD_NOEXCEPT(T) noexcept(std::is_arithmetic<T>::value)
  31. #else
  32. #define BOOST_GCD_NOEXCEPT(T)
  33. #endif
  34. namespace boost {
  35. template <class I>
  36. class rational;
  37. namespace integer {
  38. namespace gcd_detail{
  39. //
  40. // some helper functions which really should be constexpr already, but sadly aren't:
  41. //
  42. #ifndef BOOST_NO_CXX14_CONSTEXPR
  43. template <class T>
  44. inline constexpr T constexpr_min(T const& a, T const& b) BOOST_GCD_NOEXCEPT(T)
  45. {
  46. return a < b ? a : b;
  47. }
  48. template <class T>
  49. inline constexpr auto constexpr_swap(T&a, T& b) BOOST_GCD_NOEXCEPT(T) -> decltype(a.swap(b))
  50. {
  51. return a.swap(b);
  52. }
  53. template <class T, class U>
  54. inline constexpr void constexpr_swap(T&a, U& b...) BOOST_GCD_NOEXCEPT(T)
  55. {
  56. T t(static_cast<T&&>(a));
  57. a = static_cast<T&&>(b);
  58. b = static_cast<T&&>(t);
  59. }
  60. #else
  61. template <class T>
  62. inline T constexpr_min(T const& a, T const& b) BOOST_GCD_NOEXCEPT(T)
  63. {
  64. return a < b ? a : b;
  65. }
  66. template <class T>
  67. inline void constexpr_swap(T&a, T& b) BOOST_GCD_NOEXCEPT(T)
  68. {
  69. using std::swap;
  70. swap(a, b);
  71. }
  72. #endif
  73. template <class T, bool a =
  74. #ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
  75. std::is_unsigned<T>::value ||
  76. #endif
  77. (std::numeric_limits<T>::is_specialized && !std::numeric_limits<T>::is_signed)>
  78. struct gcd_traits_abs_defaults
  79. {
  80. inline static BOOST_CXX14_CONSTEXPR const T& abs(const T& val) BOOST_GCD_NOEXCEPT(T) { return val; }
  81. };
  82. template <class T>
  83. struct gcd_traits_abs_defaults<T, false>
  84. {
  85. inline static T BOOST_CXX14_CONSTEXPR abs(const T& val) BOOST_GCD_NOEXCEPT(T)
  86. {
  87. // This sucks, but std::abs is not constexpr :(
  88. return val < T(0) ? -val : val;
  89. }
  90. };
  91. enum method_type
  92. {
  93. method_euclid = 0,
  94. method_binary = 1,
  95. method_mixed = 2
  96. };
  97. struct any_convert
  98. {
  99. template <class T>
  100. any_convert(const T&);
  101. };
  102. struct unlikely_size
  103. {
  104. char buf[9973];
  105. };
  106. unlikely_size operator <<= (any_convert, any_convert);
  107. unlikely_size operator >>= (any_convert, any_convert);
  108. template <class T>
  109. struct gcd_traits_defaults : public gcd_traits_abs_defaults<T>
  110. {
  111. BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned make_odd(T& val) BOOST_GCD_NOEXCEPT(T)
  112. {
  113. unsigned r = 0;
  114. while(0 == (val & 1u))
  115. {
  116. #ifdef _MSC_VER // VC++ can't handle operator >>= in constexpr code for some reason
  117. val = val >> 1;
  118. #else
  119. val >>= 1;
  120. #endif
  121. ++r;
  122. }
  123. return r;
  124. }
  125. inline static BOOST_CXX14_CONSTEXPR bool less(const T& a, const T& b) BOOST_GCD_NOEXCEPT(T)
  126. {
  127. return a < b;
  128. }
  129. static T& get_value();
  130. #ifndef BOOST_NO_SFINAE
  131. static const bool has_operator_left_shift_equal = sizeof(get_value() <<= 2) != sizeof(unlikely_size);
  132. static const bool has_operator_right_shift_equal = sizeof(get_value() >>= 2) != sizeof(unlikely_size);
  133. #else
  134. static const bool has_operator_left_shift_equal = true;
  135. static const bool has_operator_right_shift_equal = true;
  136. #endif
  137. static const method_type method = std::numeric_limits<T>::is_specialized && std::numeric_limits<T>::is_integer && has_operator_left_shift_equal && has_operator_right_shift_equal ? method_mixed : method_euclid;
  138. };
  139. //
  140. // Default gcd_traits just inherits from defaults:
  141. //
  142. template <class T>
  143. struct gcd_traits : public gcd_traits_defaults<T> {};
  144. //
  145. // Some platforms have fast bitscan operations, that allow us to implement
  146. // make_odd much more efficiently, unfortunately we can't use these if we want
  147. // the functions to be constexpr as the compiler intrinsics aren't constexpr.
  148. //
  149. #if defined(BOOST_NO_CXX14_CONSTEXPR) && ((defined(BOOST_MSVC) && (BOOST_MSVC >= 1600)) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64))
  150. #pragma intrinsic(_BitScanForward,)
  151. template <>
  152. struct gcd_traits<unsigned long> : public gcd_traits_defaults<unsigned long>
  153. {
  154. BOOST_FORCEINLINE static unsigned find_lsb(unsigned long val) BOOST_NOEXCEPT
  155. {
  156. unsigned long result;
  157. _BitScanForward(&result, val);
  158. return result;
  159. }
  160. BOOST_FORCEINLINE static unsigned make_odd(unsigned long& val) BOOST_NOEXCEPT
  161. {
  162. unsigned result = find_lsb(val);
  163. val >>= result;
  164. return result;
  165. }
  166. };
  167. #ifdef _M_X64
  168. #pragma intrinsic(_BitScanForward64)
  169. template <>
  170. struct gcd_traits<unsigned __int64> : public gcd_traits_defaults<unsigned __int64>
  171. {
  172. BOOST_FORCEINLINE static unsigned find_lsb(unsigned __int64 mask) BOOST_NOEXCEPT
  173. {
  174. unsigned long result;
  175. _BitScanForward64(&result, mask);
  176. return result;
  177. }
  178. BOOST_FORCEINLINE static unsigned make_odd(unsigned __int64& val) BOOST_NOEXCEPT
  179. {
  180. unsigned result = find_lsb(val);
  181. val >>= result;
  182. return result;
  183. }
  184. };
  185. #endif
  186. //
  187. // Other integer type are trivial adaptations of the above,
  188. // this works for signed types too, as by the time these functions
  189. // are called, all values are > 0.
  190. //
  191. template <> struct gcd_traits<long> : public gcd_traits_defaults<long>
  192. { BOOST_FORCEINLINE static unsigned make_odd(long& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; } };
  193. template <> struct gcd_traits<unsigned int> : public gcd_traits_defaults<unsigned int>
  194. { BOOST_FORCEINLINE static unsigned make_odd(unsigned int& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; } };
  195. template <> struct gcd_traits<int> : public gcd_traits_defaults<int>
  196. { BOOST_FORCEINLINE static unsigned make_odd(int& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; } };
  197. template <> struct gcd_traits<unsigned short> : public gcd_traits_defaults<unsigned short>
  198. { BOOST_FORCEINLINE static unsigned make_odd(unsigned short& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; } };
  199. template <> struct gcd_traits<short> : public gcd_traits_defaults<short>
  200. { BOOST_FORCEINLINE static unsigned make_odd(short& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; } };
  201. template <> struct gcd_traits<unsigned char> : public gcd_traits_defaults<unsigned char>
  202. { BOOST_FORCEINLINE static unsigned make_odd(unsigned char& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; } };
  203. template <> struct gcd_traits<signed char> : public gcd_traits_defaults<signed char>
  204. { BOOST_FORCEINLINE static unsigned make_odd(signed char& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; } };
  205. template <> struct gcd_traits<char> : public gcd_traits_defaults<char>
  206. { BOOST_FORCEINLINE static unsigned make_odd(char& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; } };
  207. #ifndef BOOST_NO_INTRINSIC_WCHAR_T
  208. template <> struct gcd_traits<wchar_t> : public gcd_traits_defaults<wchar_t>
  209. { BOOST_FORCEINLINE static unsigned make_odd(wchar_t& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; } };
  210. #endif
  211. #ifdef _M_X64
  212. template <> struct gcd_traits<__int64> : public gcd_traits_defaults<__int64>
  213. { BOOST_FORCEINLINE static unsigned make_odd(__int64& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits<unsigned __int64>::find_lsb(val); val >>= result; return result; } };
  214. #endif
  215. #elif defined(BOOST_GCC) || defined(__clang__) || (defined(BOOST_INTEL) && defined(__GNUC__))
  216. template <>
  217. struct gcd_traits<unsigned> : public gcd_traits_defaults<unsigned>
  218. {
  219. BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned find_lsb(unsigned mask)BOOST_NOEXCEPT
  220. {
  221. return __builtin_ctz(mask);
  222. }
  223. BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned make_odd(unsigned& val)BOOST_NOEXCEPT
  224. {
  225. unsigned result = find_lsb(val);
  226. val >>= result;
  227. return result;
  228. }
  229. };
  230. template <>
  231. struct gcd_traits<unsigned long> : public gcd_traits_defaults<unsigned long>
  232. {
  233. BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned find_lsb(unsigned long mask)BOOST_NOEXCEPT
  234. {
  235. return __builtin_ctzl(mask);
  236. }
  237. BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned make_odd(unsigned long& val)BOOST_NOEXCEPT
  238. {
  239. unsigned result = find_lsb(val);
  240. val >>= result;
  241. return result;
  242. }
  243. };
  244. template <>
  245. struct gcd_traits<boost::ulong_long_type> : public gcd_traits_defaults<boost::ulong_long_type>
  246. {
  247. BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned find_lsb(boost::ulong_long_type mask)BOOST_NOEXCEPT
  248. {
  249. return __builtin_ctzll(mask);
  250. }
  251. BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned make_odd(boost::ulong_long_type& val)BOOST_NOEXCEPT
  252. {
  253. unsigned result = find_lsb(val);
  254. val >>= result;
  255. return result;
  256. }
  257. };
  258. //
  259. // Other integer type are trivial adaptations of the above,
  260. // this works for signed types too, as by the time these functions
  261. // are called, all values are > 0.
  262. //
  263. template <> struct gcd_traits<boost::long_long_type> : public gcd_traits_defaults<boost::long_long_type>
  264. {
  265. BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned make_odd(boost::long_long_type& val)BOOST_NOEXCEPT { unsigned result = gcd_traits<boost::ulong_long_type>::find_lsb(val); val >>= result; return result; }
  266. };
  267. template <> struct gcd_traits<long> : public gcd_traits_defaults<long>
  268. {
  269. BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned make_odd(long& val)BOOST_NOEXCEPT { unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; }
  270. };
  271. template <> struct gcd_traits<int> : public gcd_traits_defaults<int>
  272. {
  273. BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned make_odd(int& val)BOOST_NOEXCEPT { unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; }
  274. };
  275. template <> struct gcd_traits<unsigned short> : public gcd_traits_defaults<unsigned short>
  276. {
  277. BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned make_odd(unsigned short& val)BOOST_NOEXCEPT { unsigned result = gcd_traits<unsigned>::find_lsb(val); val >>= result; return result; }
  278. };
  279. template <> struct gcd_traits<short> : public gcd_traits_defaults<short>
  280. {
  281. BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned make_odd(short& val)BOOST_NOEXCEPT { unsigned result = gcd_traits<unsigned>::find_lsb(val); val >>= result; return result; }
  282. };
  283. template <> struct gcd_traits<unsigned char> : public gcd_traits_defaults<unsigned char>
  284. {
  285. BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned make_odd(unsigned char& val)BOOST_NOEXCEPT { unsigned result = gcd_traits<unsigned>::find_lsb(val); val >>= result; return result; }
  286. };
  287. template <> struct gcd_traits<signed char> : public gcd_traits_defaults<signed char>
  288. {
  289. BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned make_odd(signed char& val)BOOST_NOEXCEPT { unsigned result = gcd_traits<unsigned>::find_lsb(val); val >>= result; return result; }
  290. };
  291. template <> struct gcd_traits<char> : public gcd_traits_defaults<char>
  292. {
  293. BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned make_odd(char& val)BOOST_NOEXCEPT { unsigned result = gcd_traits<unsigned>::find_lsb(val); val >>= result; return result; }
  294. };
  295. #ifndef BOOST_NO_INTRINSIC_WCHAR_T
  296. template <> struct gcd_traits<wchar_t> : public gcd_traits_defaults<wchar_t>
  297. {
  298. BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned make_odd(wchar_t& val)BOOST_NOEXCEPT { unsigned result = gcd_traits<unsigned>::find_lsb(val); val >>= result; return result; }
  299. };
  300. #endif
  301. #endif
  302. //
  303. // The Mixed Binary Euclid Algorithm
  304. // Sidi Mohamed Sedjelmaci
  305. // Electronic Notes in Discrete Mathematics 35 (2009) 169-176
  306. //
  307. template <class T>
  308. BOOST_CXX14_CONSTEXPR T mixed_binary_gcd(T u, T v) BOOST_GCD_NOEXCEPT(T)
  309. {
  310. if(gcd_traits<T>::less(u, v))
  311. constexpr_swap(u, v);
  312. unsigned shifts = 0;
  313. if(u == T(0))
  314. return v;
  315. if(v == T(0))
  316. return u;
  317. shifts = constexpr_min(gcd_traits<T>::make_odd(u), gcd_traits<T>::make_odd(v));
  318. while(gcd_traits<T>::less(1, v))
  319. {
  320. u %= v;
  321. v -= u;
  322. if(u == T(0))
  323. return v << shifts;
  324. if(v == T(0))
  325. return u << shifts;
  326. gcd_traits<T>::make_odd(u);
  327. gcd_traits<T>::make_odd(v);
  328. if(gcd_traits<T>::less(u, v))
  329. constexpr_swap(u, v);
  330. }
  331. return (v == 1 ? v : u) << shifts;
  332. }
  333. /** Stein gcd (aka 'binary gcd')
  334. *
  335. * From Mathematics to Generic Programming, Alexander Stepanov, Daniel Rose
  336. */
  337. template <typename SteinDomain>
  338. BOOST_CXX14_CONSTEXPR SteinDomain Stein_gcd(SteinDomain m, SteinDomain n) BOOST_GCD_NOEXCEPT(SteinDomain)
  339. {
  340. BOOST_ASSERT(m >= 0);
  341. BOOST_ASSERT(n >= 0);
  342. if (m == SteinDomain(0))
  343. return n;
  344. if (n == SteinDomain(0))
  345. return m;
  346. // m > 0 && n > 0
  347. unsigned d_m = gcd_traits<SteinDomain>::make_odd(m);
  348. unsigned d_n = gcd_traits<SteinDomain>::make_odd(n);
  349. // odd(m) && odd(n)
  350. while (m != n)
  351. {
  352. if (n > m)
  353. constexpr_swap(n, m);
  354. m -= n;
  355. gcd_traits<SteinDomain>::make_odd(m);
  356. }
  357. // m == n
  358. m <<= constexpr_min(d_m, d_n);
  359. return m;
  360. }
  361. /** Euclidean algorithm
  362. *
  363. * From Mathematics to Generic Programming, Alexander Stepanov, Daniel Rose
  364. *
  365. */
  366. template <typename EuclideanDomain>
  367. inline BOOST_CXX14_CONSTEXPR EuclideanDomain Euclid_gcd(EuclideanDomain a, EuclideanDomain b) BOOST_GCD_NOEXCEPT(EuclideanDomain)
  368. {
  369. while (b != EuclideanDomain(0))
  370. {
  371. a %= b;
  372. constexpr_swap(a, b);
  373. }
  374. return a;
  375. }
  376. template <typename T>
  377. inline BOOST_CXX14_CONSTEXPR BOOST_DEDUCED_TYPENAME enable_if_c<gcd_traits<T>::method == method_mixed, T>::type
  378. optimal_gcd_select(T const &a, T const &b) BOOST_GCD_NOEXCEPT(T)
  379. {
  380. return gcd_detail::mixed_binary_gcd(a, b);
  381. }
  382. template <typename T>
  383. inline BOOST_CXX14_CONSTEXPR BOOST_DEDUCED_TYPENAME enable_if_c<gcd_traits<T>::method == method_binary, T>::type
  384. optimal_gcd_select(T const &a, T const &b) BOOST_GCD_NOEXCEPT(T)
  385. {
  386. return gcd_detail::Stein_gcd(a, b);
  387. }
  388. template <typename T>
  389. inline BOOST_CXX14_CONSTEXPR BOOST_DEDUCED_TYPENAME enable_if_c<gcd_traits<T>::method == method_euclid, T>::type
  390. optimal_gcd_select(T const &a, T const &b) BOOST_GCD_NOEXCEPT(T)
  391. {
  392. return gcd_detail::Euclid_gcd(a, b);
  393. }
  394. template <class T>
  395. inline BOOST_CXX14_CONSTEXPR T lcm_imp(const T& a, const T& b) BOOST_GCD_NOEXCEPT(T)
  396. {
  397. T temp = boost::integer::gcd_detail::optimal_gcd_select(a, b);
  398. #if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40500)
  399. return (temp != T(0)) ? T(a / temp * b) : T(0);
  400. #else
  401. return temp != T(0) ? T(a / temp * b) : T(0);
  402. #endif
  403. }
  404. } // namespace detail
  405. template <typename Integer>
  406. inline BOOST_CXX14_CONSTEXPR Integer gcd(Integer const &a, Integer const &b) BOOST_GCD_NOEXCEPT(Integer)
  407. {
  408. if(a == (std::numeric_limits<Integer>::min)())
  409. return a == static_cast<Integer>(0) ? gcd_detail::gcd_traits<Integer>::abs(b) : boost::integer::gcd(static_cast<Integer>(a % b), b);
  410. else if (b == (std::numeric_limits<Integer>::min)())
  411. return b == static_cast<Integer>(0) ? gcd_detail::gcd_traits<Integer>::abs(a) : boost::integer::gcd(a, static_cast<Integer>(b % a));
  412. return gcd_detail::optimal_gcd_select(static_cast<Integer>(gcd_detail::gcd_traits<Integer>::abs(a)), static_cast<Integer>(gcd_detail::gcd_traits<Integer>::abs(b)));
  413. }
  414. template <typename Integer>
  415. inline BOOST_CXX14_CONSTEXPR Integer lcm(Integer const &a, Integer const &b) BOOST_GCD_NOEXCEPT(Integer)
  416. {
  417. return gcd_detail::lcm_imp(static_cast<Integer>(gcd_detail::gcd_traits<Integer>::abs(a)), static_cast<Integer>(gcd_detail::gcd_traits<Integer>::abs(b)));
  418. }
  419. #ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
  420. //
  421. // This looks slightly odd, but the variadic forms must have 3 or more arguments, and the variadic argument pack may be empty.
  422. // This matters not at all for most compilers, but Oracle C++ selects the wrong overload in the 2-arg case unless we do this.
  423. //
  424. template <typename Integer, typename... Args>
  425. inline BOOST_CXX14_CONSTEXPR Integer gcd(Integer const &a, Integer const &b, const Integer& c, Args const&... args) BOOST_GCD_NOEXCEPT(Integer)
  426. {
  427. Integer t = gcd(b, c, args...);
  428. return t == 1 ? 1 : gcd(a, t);
  429. }
  430. template <typename Integer, typename... Args>
  431. inline BOOST_CXX14_CONSTEXPR Integer lcm(Integer const &a, Integer const &b, Integer const& c, Args const&... args) BOOST_GCD_NOEXCEPT(Integer)
  432. {
  433. return lcm(a, lcm(b, c, args...));
  434. }
  435. #endif
  436. //
  437. // Special handling for rationals:
  438. //
  439. template <typename Integer>
  440. inline typename boost::enable_if_c<std::numeric_limits<Integer>::is_specialized, boost::rational<Integer> >::type gcd(boost::rational<Integer> const &a, boost::rational<Integer> const &b)
  441. {
  442. return boost::rational<Integer>(static_cast<Integer>(gcd(a.numerator(), b.numerator())), static_cast<Integer>(lcm(a.denominator(), b.denominator())));
  443. }
  444. template <typename Integer>
  445. inline typename boost::enable_if_c<std::numeric_limits<Integer>::is_specialized, boost::rational<Integer> >::type lcm(boost::rational<Integer> const &a, boost::rational<Integer> const &b)
  446. {
  447. return boost::rational<Integer>(static_cast<Integer>(lcm(a.numerator(), b.numerator())), static_cast<Integer>(gcd(a.denominator(), b.denominator())));
  448. }
  449. /**
  450. * Knuth, The Art of Computer Programming: Volume 2, Third edition, 1998
  451. * Chapter 4.5.2, Algorithm C: Greatest common divisor of n integers.
  452. *
  453. * Knuth counts down from n to zero but we naturally go from first to last.
  454. * We also return the termination position because it might be useful to know.
  455. *
  456. * Partly by quirk, partly by design, this algorithm is defined for n = 1,
  457. * because the gcd of {x} is x. It is not defined for n = 0.
  458. *
  459. * @tparam I Input iterator.
  460. * @return The gcd of the range and the iterator position at termination.
  461. */
  462. template <typename I>
  463. std::pair<typename std::iterator_traits<I>::value_type, I>
  464. gcd_range(I first, I last) BOOST_GCD_NOEXCEPT(I)
  465. {
  466. BOOST_ASSERT(first != last);
  467. typedef typename std::iterator_traits<I>::value_type T;
  468. T d = *first;
  469. ++first;
  470. while (d != T(1) && first != last)
  471. {
  472. d = gcd(d, *first);
  473. ++first;
  474. }
  475. return std::make_pair(d, first);
  476. }
  477. template <typename I>
  478. std::pair<typename std::iterator_traits<I>::value_type, I>
  479. lcm_range(I first, I last) BOOST_GCD_NOEXCEPT(I)
  480. {
  481. BOOST_ASSERT(first != last);
  482. typedef typename std::iterator_traits<I>::value_type T;
  483. T d = *first;
  484. ++first;
  485. while (d != T(0) && first != last)
  486. {
  487. d = lcm(d, *first);
  488. ++first;
  489. }
  490. return std::make_pair(d, first);
  491. }
  492. template < typename IntegerType >
  493. class gcd_evaluator
  494. #ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
  495. : public std::binary_function<IntegerType, IntegerType, IntegerType>
  496. #endif
  497. {
  498. public:
  499. #ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
  500. typedef IntegerType first_argument_type;
  501. typedef IntegerType second_argument_type;
  502. typedef IntegerType result_type;
  503. #endif
  504. IntegerType operator()(IntegerType const &a, IntegerType const &b) const
  505. {
  506. return boost::integer::gcd(a, b);
  507. }
  508. };
  509. template < typename IntegerType >
  510. class lcm_evaluator
  511. #ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
  512. : public std::binary_function<IntegerType, IntegerType, IntegerType>
  513. #endif
  514. {
  515. public:
  516. #ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
  517. typedef IntegerType first_argument_type;
  518. typedef IntegerType second_argument_type;
  519. typedef IntegerType result_type;
  520. #endif
  521. IntegerType operator()(IntegerType const &a, IntegerType const &b)const
  522. {
  523. return boost::integer::lcm(a, b);
  524. }
  525. };
  526. } // namespace integer
  527. } // namespace boost
  528. #ifdef BOOST_MSVC
  529. #pragma warning(pop)
  530. #endif
  531. #endif // BOOST_INTEGER_COMMON_FACTOR_RT_HPP