1 ///////////////////////////////////////////////////////////////
2 // Copyright 2012 John Maddock. Distributed under the Boost
3 // Software License, Version 1.0. (See accompanying file
4 // LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
6 #ifndef BOOST_MP_INTEGER_HPP
7 #define BOOST_MP_INTEGER_HPP
9 #include <boost/multiprecision/cpp_int.hpp>
10 #include <boost/multiprecision/detail/bitscan.hpp>
13 namespace multiprecision {
15 template <class Integer, class I2>
16 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_integral<Integer>::value && is_integral<I2>::value, Integer&>::type
17 multiply(Integer& result, const I2& a, const I2& b)
19 return result = static_cast<Integer>(a) * static_cast<Integer>(b);
21 template <class Integer, class I2>
22 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_integral<Integer>::value && is_integral<I2>::value, Integer&>::type
23 add(Integer& result, const I2& a, const I2& b)
25 return result = static_cast<Integer>(a) + static_cast<Integer>(b);
27 template <class Integer, class I2>
28 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_integral<Integer>::value && is_integral<I2>::value, Integer&>::type
29 subtract(Integer& result, const I2& a, const I2& b)
31 return result = static_cast<Integer>(a) - static_cast<Integer>(b);
34 template <class Integer>
35 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_integral<Integer>::value>::type divide_qr(const Integer& x, const Integer& y, Integer& q, Integer& r)
41 template <class I1, class I2>
42 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_integral<I1>::value && is_integral<I2>::value, I2>::type integer_modulus(const I1& x, I2 val)
44 return static_cast<I2>(x % val);
49 // Figure out the kind of integer that has twice as many bits as some builtin
50 // integer type I. Use a native type if we can (including types which may not
51 // be recognised by boost::int_t because they're larger than boost::long_long_type),
52 // otherwise synthesize a cpp_int to do the job.
57 static const unsigned int_t_digits =
58 2 * sizeof(I) <= sizeof(boost::long_long_type) ? std::numeric_limits<I>::digits * 2 : 1;
60 typedef typename mpl::if_c<
61 2 * sizeof(I) <= sizeof(boost::long_long_type),
64 typename boost::int_t<int_t_digits>::least,
65 typename boost::uint_t<int_t_digits>::least>::type,
67 2 * sizeof(I) <= sizeof(double_limb_type),
70 signed_double_limb_type,
71 double_limb_type>::type,
72 number<cpp_int_backend<sizeof(I) * CHAR_BIT * 2, sizeof(I) * CHAR_BIT * 2, (is_signed<I>::value ? signed_magnitude : unsigned_magnitude), unchecked, void> > >::type>::type type;
77 template <class I1, class I2, class I3>
78 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_integral<I1>::value && is_unsigned<I2>::value && is_integral<I3>::value, I1>::type
79 powm(const I1& a, I2 b, I3 c)
81 typedef typename detail::double_integer<I1>::type double_type;
84 double_type result(0);
90 multiply(result, x, y);
91 x = integer_modulus(result, c);
93 multiply(result, y, y);
94 y = integer_modulus(result, c);
100 template <class I1, class I2, class I3>
101 inline BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_integral<I1>::value && is_signed<I2>::value && is_integral<I3>::value, I1>::type
102 powm(const I1& a, I2 b, I3 c)
106 BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
108 return powm(a, static_cast<typename make_unsigned<I2>::type>(b), c);
111 template <class Integer>
112 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_integral<Integer>::value, unsigned>::type lsb(const Integer& val)
118 BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
122 BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
125 return detail::find_lsb(val);
128 template <class Integer>
129 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_integral<Integer>::value, unsigned>::type msb(Integer val)
135 BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
139 BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
142 return detail::find_msb(val);
145 template <class Integer>
146 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_integral<Integer>::value, bool>::type bit_test(const Integer& val, unsigned index)
149 if (index >= sizeof(Integer) * CHAR_BIT)
153 return val & mask ? true : false;
156 template <class Integer>
157 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_integral<Integer>::value, Integer&>::type bit_set(Integer& val, unsigned index)
160 if (index >= sizeof(Integer) * CHAR_BIT)
168 template <class Integer>
169 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_integral<Integer>::value, Integer&>::type bit_unset(Integer& val, unsigned index)
172 if (index >= sizeof(Integer) * CHAR_BIT)
180 template <class Integer>
181 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_integral<Integer>::value, Integer&>::type bit_flip(Integer& val, unsigned index)
184 if (index >= sizeof(Integer) * CHAR_BIT)
192 template <class Integer>
193 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_integral<Integer>::value, Integer>::type sqrt(const Integer& x, Integer& r)
196 // This is slow bit-by-bit integer square root, see for example
197 // http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29
198 // There are better methods such as http://hal.inria.fr/docs/00/07/28/54/PDF/RR-3805.pdf
199 // and http://hal.inria.fr/docs/00/07/21/13/PDF/RR-4475.pdf which should be implemented
237 template <class Integer>
238 BOOST_MP_CXX14_CONSTEXPR typename enable_if_c<is_integral<Integer>::value, Integer>::type sqrt(const Integer& x)
244 }} // namespace boost::multiprecision