Chris@16
|
1 ///////////////////////////////////////////////////////////////
|
Chris@16
|
2 // Copyright 2012 John Maddock. Distributed under the Boost
|
Chris@16
|
3 // Software License, Version 1.0. (See accompanying file
|
Chris@16
|
4 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
|
Chris@16
|
5
|
Chris@16
|
6 #ifndef BOOST_MP_INTEGER_HPP
|
Chris@16
|
7 #define BOOST_MP_INTEGER_HPP
|
Chris@16
|
8
|
Chris@16
|
9 #include <boost/multiprecision/cpp_int.hpp>
|
Chris@16
|
10 #include <boost/multiprecision/detail/bitscan.hpp>
|
Chris@16
|
11
|
Chris@16
|
12 namespace boost{
|
Chris@16
|
13 namespace multiprecision{
|
Chris@16
|
14
|
Chris@16
|
15 template <class Integer, class I2>
|
Chris@16
|
16 typename enable_if_c<is_integral<Integer>::value && is_integral<I2>::value, Integer&>::type
|
Chris@16
|
17 multiply(Integer& result, const I2& a, const I2& b)
|
Chris@16
|
18 {
|
Chris@16
|
19 return result = static_cast<Integer>(a) * static_cast<Integer>(b);
|
Chris@16
|
20 }
|
Chris@16
|
21 template <class Integer, class I2>
|
Chris@16
|
22 typename enable_if_c<is_integral<Integer>::value && is_integral<I2>::value, Integer&>::type
|
Chris@16
|
23 add(Integer& result, const I2& a, const I2& b)
|
Chris@16
|
24 {
|
Chris@16
|
25 return result = static_cast<Integer>(a) + static_cast<Integer>(b);
|
Chris@16
|
26 }
|
Chris@16
|
27 template <class Integer, class I2>
|
Chris@16
|
28 typename enable_if_c<is_integral<Integer>::value && is_integral<I2>::value, Integer&>::type
|
Chris@16
|
29 subtract(Integer& result, const I2& a, const I2& b)
|
Chris@16
|
30 {
|
Chris@16
|
31 return result = static_cast<Integer>(a) - static_cast<Integer>(b);
|
Chris@16
|
32 }
|
Chris@16
|
33
|
Chris@16
|
34 template <class Integer>
|
Chris@16
|
35 typename enable_if_c<is_integral<Integer>::value>::type divide_qr(const Integer& x, const Integer& y, Integer& q, Integer& r)
|
Chris@16
|
36 {
|
Chris@16
|
37 q = x / y;
|
Chris@16
|
38 r = x % y;
|
Chris@16
|
39 }
|
Chris@16
|
40
|
Chris@16
|
41 template <class I1, class I2>
|
Chris@16
|
42 typename enable_if_c<is_integral<I1>::value && is_integral<I2>::value, I2>::type integer_modulus(const I1& x, I2 val)
|
Chris@16
|
43 {
|
Chris@16
|
44 return static_cast<I2>(x % val);
|
Chris@16
|
45 }
|
Chris@16
|
46
|
Chris@16
|
47 namespace detail{
|
Chris@16
|
48 //
|
Chris@16
|
49 // Figure out the kind of integer that has twice as many bits as some builtin
|
Chris@16
|
50 // integer type I. Use a native type if we can (including types which may not
|
Chris@16
|
51 // be recognised by boost::int_t because they're larger than long long),
|
Chris@16
|
52 // otherwise synthesize a cpp_int to do the job.
|
Chris@16
|
53 //
|
Chris@16
|
54 template <class I>
|
Chris@16
|
55 struct double_integer
|
Chris@16
|
56 {
|
Chris@16
|
57 static const unsigned int_t_digits =
|
Chris@16
|
58 2 * sizeof(I) <= sizeof(long long) ? std::numeric_limits<I>::digits * 2 : 1;
|
Chris@16
|
59
|
Chris@16
|
60 typedef typename mpl::if_c<
|
Chris@16
|
61 2 * sizeof(I) <= sizeof(long long),
|
Chris@16
|
62 typename mpl::if_c<
|
Chris@16
|
63 is_signed<I>::value,
|
Chris@16
|
64 typename boost::int_t<int_t_digits>::least,
|
Chris@16
|
65 typename boost::uint_t<int_t_digits>::least
|
Chris@16
|
66 >::type,
|
Chris@16
|
67 typename mpl::if_c<
|
Chris@16
|
68 2 * sizeof(I) <= sizeof(double_limb_type),
|
Chris@16
|
69 typename mpl::if_c<
|
Chris@16
|
70 is_signed<I>::value,
|
Chris@16
|
71 signed_double_limb_type,
|
Chris@16
|
72 double_limb_type
|
Chris@16
|
73 >::type,
|
Chris@16
|
74 number<cpp_int_backend<sizeof(I)*CHAR_BIT*2, sizeof(I)*CHAR_BIT*2, (is_signed<I>::value ? signed_magnitude : unsigned_magnitude), unchecked, void> >
|
Chris@16
|
75 >::type
|
Chris@16
|
76 >::type type;
|
Chris@16
|
77 };
|
Chris@16
|
78
|
Chris@16
|
79 }
|
Chris@16
|
80
|
Chris@16
|
81 template <class I1, class I2, class I3>
|
Chris@101
|
82 typename enable_if_c<is_integral<I1>::value && is_unsigned<I2>::value && is_integral<I3>::value, I1>::type
|
Chris@16
|
83 powm(const I1& a, I2 b, I3 c)
|
Chris@16
|
84 {
|
Chris@16
|
85 typedef typename detail::double_integer<I1>::type double_type;
|
Chris@16
|
86
|
Chris@16
|
87 I1 x(1), y(a);
|
Chris@16
|
88 double_type result;
|
Chris@16
|
89
|
Chris@16
|
90 while(b > 0)
|
Chris@16
|
91 {
|
Chris@16
|
92 if(b & 1)
|
Chris@16
|
93 {
|
Chris@16
|
94 multiply(result, x, y);
|
Chris@16
|
95 x = integer_modulus(result, c);
|
Chris@16
|
96 }
|
Chris@16
|
97 multiply(result, y, y);
|
Chris@16
|
98 y = integer_modulus(result, c);
|
Chris@16
|
99 b >>= 1;
|
Chris@16
|
100 }
|
Chris@16
|
101 return x % c;
|
Chris@16
|
102 }
|
Chris@16
|
103
|
Chris@101
|
104 template <class I1, class I2, class I3>
|
Chris@101
|
105 inline typename enable_if_c<is_integral<I1>::value && is_signed<I2>::value && is_integral<I3>::value, I1>::type
|
Chris@101
|
106 powm(const I1& a, I2 b, I3 c)
|
Chris@101
|
107 {
|
Chris@101
|
108 if(b < 0)
|
Chris@101
|
109 {
|
Chris@101
|
110 BOOST_THROW_EXCEPTION(std::runtime_error("powm requires a positive exponent."));
|
Chris@101
|
111 }
|
Chris@101
|
112 return powm(a, static_cast<typename make_unsigned<I2>::type>(b), c);
|
Chris@101
|
113 }
|
Chris@101
|
114
|
Chris@16
|
115 template <class Integer>
|
Chris@16
|
116 typename enable_if_c<is_integral<Integer>::value, unsigned>::type lsb(const Integer& val)
|
Chris@16
|
117 {
|
Chris@16
|
118 if(val <= 0)
|
Chris@16
|
119 {
|
Chris@16
|
120 if(val == 0)
|
Chris@16
|
121 {
|
Chris@16
|
122 BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
|
Chris@16
|
123 }
|
Chris@16
|
124 else
|
Chris@16
|
125 {
|
Chris@16
|
126 BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
|
Chris@16
|
127 }
|
Chris@16
|
128 }
|
Chris@16
|
129 return detail::find_lsb(val);
|
Chris@16
|
130 }
|
Chris@16
|
131
|
Chris@16
|
132 template <class Integer>
|
Chris@16
|
133 typename enable_if_c<is_integral<Integer>::value, unsigned>::type msb(Integer val)
|
Chris@16
|
134 {
|
Chris@16
|
135 if(val <= 0)
|
Chris@16
|
136 {
|
Chris@16
|
137 if(val == 0)
|
Chris@16
|
138 {
|
Chris@16
|
139 BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
|
Chris@16
|
140 }
|
Chris@16
|
141 else
|
Chris@16
|
142 {
|
Chris@16
|
143 BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
|
Chris@16
|
144 }
|
Chris@16
|
145 }
|
Chris@16
|
146 return detail::find_msb(val);
|
Chris@16
|
147 }
|
Chris@16
|
148
|
Chris@16
|
149 template <class Integer>
|
Chris@16
|
150 typename enable_if_c<is_integral<Integer>::value, bool>::type bit_test(const Integer& val, unsigned index)
|
Chris@16
|
151 {
|
Chris@16
|
152 Integer mask = 1;
|
Chris@16
|
153 if(index >= sizeof(Integer) * CHAR_BIT)
|
Chris@16
|
154 return 0;
|
Chris@16
|
155 if(index)
|
Chris@16
|
156 mask <<= index;
|
Chris@16
|
157 return val & mask ? true : false;
|
Chris@16
|
158 }
|
Chris@16
|
159
|
Chris@16
|
160 template <class Integer>
|
Chris@16
|
161 typename enable_if_c<is_integral<Integer>::value, Integer&>::type bit_set(Integer& val, unsigned index)
|
Chris@16
|
162 {
|
Chris@16
|
163 Integer mask = 1;
|
Chris@16
|
164 if(index >= sizeof(Integer) * CHAR_BIT)
|
Chris@16
|
165 return val;
|
Chris@16
|
166 if(index)
|
Chris@16
|
167 mask <<= index;
|
Chris@16
|
168 val |= mask;
|
Chris@16
|
169 return val;
|
Chris@16
|
170 }
|
Chris@16
|
171
|
Chris@16
|
172 template <class Integer>
|
Chris@16
|
173 typename enable_if_c<is_integral<Integer>::value, Integer&>::type bit_unset(Integer& val, unsigned index)
|
Chris@16
|
174 {
|
Chris@16
|
175 Integer mask = 1;
|
Chris@16
|
176 if(index >= sizeof(Integer) * CHAR_BIT)
|
Chris@16
|
177 return val;
|
Chris@16
|
178 if(index)
|
Chris@16
|
179 mask <<= index;
|
Chris@16
|
180 val &= ~mask;
|
Chris@16
|
181 return val;
|
Chris@16
|
182 }
|
Chris@16
|
183
|
Chris@16
|
184 template <class Integer>
|
Chris@16
|
185 typename enable_if_c<is_integral<Integer>::value, Integer&>::type bit_flip(Integer& val, unsigned index)
|
Chris@16
|
186 {
|
Chris@16
|
187 Integer mask = 1;
|
Chris@16
|
188 if(index >= sizeof(Integer) * CHAR_BIT)
|
Chris@16
|
189 return val;
|
Chris@16
|
190 if(index)
|
Chris@16
|
191 mask <<= index;
|
Chris@16
|
192 val ^= mask;
|
Chris@16
|
193 return val;
|
Chris@16
|
194 }
|
Chris@16
|
195
|
Chris@16
|
196 template <class Integer>
|
Chris@16
|
197 typename enable_if_c<is_integral<Integer>::value, Integer>::type sqrt(const Integer& x, Integer& r)
|
Chris@16
|
198 {
|
Chris@16
|
199 //
|
Chris@16
|
200 // This is slow bit-by-bit integer square root, see for example
|
Chris@16
|
201 // http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29
|
Chris@16
|
202 // There are better methods such as http://hal.inria.fr/docs/00/07/28/54/PDF/RR-3805.pdf
|
Chris@16
|
203 // and http://hal.inria.fr/docs/00/07/21/13/PDF/RR-4475.pdf which should be implemented
|
Chris@16
|
204 // at some point.
|
Chris@16
|
205 //
|
Chris@16
|
206 Integer s = 0;
|
Chris@16
|
207 if(x == 0)
|
Chris@16
|
208 {
|
Chris@16
|
209 r = 0;
|
Chris@16
|
210 return s;
|
Chris@16
|
211 }
|
Chris@16
|
212 int g = msb(x);
|
Chris@16
|
213 if(g == 0)
|
Chris@16
|
214 {
|
Chris@16
|
215 r = 1;
|
Chris@16
|
216 return s;
|
Chris@16
|
217 }
|
Chris@16
|
218
|
Chris@101
|
219 Integer t = 0;
|
Chris@16
|
220 r = x;
|
Chris@16
|
221 g /= 2;
|
Chris@16
|
222 bit_set(s, g);
|
Chris@16
|
223 bit_set(t, 2 * g);
|
Chris@16
|
224 r = x - t;
|
Chris@16
|
225 --g;
|
Chris@16
|
226 do
|
Chris@16
|
227 {
|
Chris@16
|
228 t = s;
|
Chris@16
|
229 t <<= g + 1;
|
Chris@16
|
230 bit_set(t, 2 * g);
|
Chris@16
|
231 if(t <= r)
|
Chris@16
|
232 {
|
Chris@16
|
233 bit_set(s, g);
|
Chris@16
|
234 r -= t;
|
Chris@16
|
235 }
|
Chris@16
|
236 --g;
|
Chris@16
|
237 }
|
Chris@16
|
238 while(g >= 0);
|
Chris@16
|
239 return s;
|
Chris@16
|
240 }
|
Chris@16
|
241
|
Chris@16
|
242 template <class Integer>
|
Chris@16
|
243 typename enable_if_c<is_integral<Integer>::value, Integer>::type sqrt(const Integer& x)
|
Chris@16
|
244 {
|
Chris@16
|
245 Integer r;
|
Chris@16
|
246 return sqrt(x, r);
|
Chris@16
|
247 }
|
Chris@16
|
248
|
Chris@16
|
249 }} // namespaces
|
Chris@16
|
250
|
Chris@16
|
251 #endif
|