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 // Comparison operators for cpp_int_backend:
|
Chris@16
|
7 //
|
Chris@16
|
8 #ifndef BOOST_MP_CPP_INT_MISC_HPP
|
Chris@16
|
9 #define BOOST_MP_CPP_INT_MISC_HPP
|
Chris@16
|
10
|
Chris@16
|
11 #include <boost/multiprecision/detail/bitscan.hpp> // lsb etc
|
Chris@101
|
12 #include <boost/integer/common_factor_rt.hpp> // gcd/lcm
|
Chris@16
|
13
|
Chris@16
|
14 #ifdef BOOST_MSVC
|
Chris@16
|
15 #pragma warning(push)
|
Chris@16
|
16 #pragma warning(disable:4702)
|
Chris@16
|
17 #endif
|
Chris@16
|
18
|
Chris@16
|
19 namespace boost{ namespace multiprecision{ namespace backends{
|
Chris@16
|
20
|
Chris@16
|
21 template <class R, class CppInt>
|
Chris@16
|
22 void check_in_range(const CppInt& val, const mpl::int_<checked>&)
|
Chris@16
|
23 {
|
Chris@16
|
24 typedef typename boost::multiprecision::detail::canonical<R, CppInt>::type cast_type;
|
Chris@16
|
25 if(val.sign())
|
Chris@16
|
26 {
|
Chris@16
|
27 if(val.compare(static_cast<cast_type>((std::numeric_limits<R>::min)())) < 0)
|
Chris@16
|
28 BOOST_THROW_EXCEPTION(std::overflow_error("Could not convert to the target type - -value is out of range."));
|
Chris@16
|
29 }
|
Chris@16
|
30 else
|
Chris@16
|
31 {
|
Chris@16
|
32 if(val.compare(static_cast<cast_type>((std::numeric_limits<R>::max)())) > 0)
|
Chris@16
|
33 BOOST_THROW_EXCEPTION(std::overflow_error("Could not convert to the target type - -value is out of range."));
|
Chris@16
|
34 }
|
Chris@16
|
35 }
|
Chris@16
|
36 template <class R, class CppInt>
|
Chris@16
|
37 inline void check_in_range(const CppInt& /*val*/, const mpl::int_<unchecked>&) BOOST_NOEXCEPT {}
|
Chris@16
|
38
|
Chris@16
|
39 inline void check_is_negative(const mpl::true_&) BOOST_NOEXCEPT {}
|
Chris@16
|
40 inline void check_is_negative(const mpl::false_&)
|
Chris@16
|
41 {
|
Chris@16
|
42 BOOST_THROW_EXCEPTION(std::range_error("Attempt to assign a negative value to an unsigned type."));
|
Chris@16
|
43 }
|
Chris@16
|
44
|
Chris@16
|
45 template <class Integer>
|
Chris@16
|
46 inline Integer negate_integer(Integer i, const mpl::true_&) BOOST_NOEXCEPT
|
Chris@16
|
47 {
|
Chris@16
|
48 return -i;
|
Chris@16
|
49 }
|
Chris@16
|
50 template <class Integer>
|
Chris@16
|
51 inline Integer negate_integer(Integer i, const mpl::false_&) BOOST_NOEXCEPT
|
Chris@16
|
52 {
|
Chris@16
|
53 return ~(i-1);
|
Chris@16
|
54 }
|
Chris@16
|
55
|
Chris@16
|
56 template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
57 inline typename enable_if_c<is_integral<R>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, void>::type
|
Chris@16
|
58 eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& backend) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
Chris@16
|
59 {
|
Chris@16
|
60 typedef mpl::int_<Checked1> checked_type;
|
Chris@16
|
61 check_in_range<R>(backend, checked_type());
|
Chris@16
|
62
|
Chris@16
|
63 *result = static_cast<R>(backend.limbs()[0]);
|
Chris@16
|
64 unsigned shift = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
Chris@16
|
65 for(unsigned i = 1; (i < backend.size()) && (shift < static_cast<unsigned>(std::numeric_limits<R>::digits)); ++i)
|
Chris@16
|
66 {
|
Chris@16
|
67 *result += static_cast<R>(backend.limbs()[i]) << shift;
|
Chris@16
|
68 shift += cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
Chris@16
|
69 }
|
Chris@16
|
70 if(backend.sign())
|
Chris@16
|
71 {
|
Chris@16
|
72 check_is_negative(boost::is_signed<R>());
|
Chris@16
|
73 *result = negate_integer(*result, boost::is_signed<R>());
|
Chris@16
|
74 }
|
Chris@16
|
75 }
|
Chris@16
|
76
|
Chris@16
|
77 template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
78 inline typename enable_if_c<is_floating_point<R>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, void>::type
|
Chris@16
|
79 eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& backend) BOOST_NOEXCEPT_IF(is_arithmetic<R>::value)
|
Chris@16
|
80 {
|
Chris@16
|
81 typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::const_limb_pointer p = backend.limbs();
|
Chris@16
|
82 unsigned shift = cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
Chris@16
|
83 *result = static_cast<R>(*p);
|
Chris@16
|
84 for(unsigned i = 1; i < backend.size(); ++i)
|
Chris@16
|
85 {
|
Chris@16
|
86 *result += static_cast<R>(std::ldexp(static_cast<long double>(p[i]), shift));
|
Chris@16
|
87 shift += cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
Chris@16
|
88 }
|
Chris@16
|
89 if(backend.sign())
|
Chris@16
|
90 *result = -*result;
|
Chris@16
|
91 }
|
Chris@16
|
92
|
Chris@16
|
93 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
94 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, bool>::type
|
Chris@16
|
95 eval_is_zero(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_NOEXCEPT
|
Chris@16
|
96 {
|
Chris@16
|
97 return (val.size() == 1) && (val.limbs()[0] == 0);
|
Chris@16
|
98 }
|
Chris@16
|
99 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
100 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, int>::type
|
Chris@16
|
101 eval_get_sign(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_NOEXCEPT
|
Chris@16
|
102 {
|
Chris@16
|
103 return eval_is_zero(val) ? 0 : val.sign() ? -1 : 1;
|
Chris@16
|
104 }
|
Chris@16
|
105 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
106 BOOST_MP_FORCEINLINE typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
Chris@16
|
107 eval_abs(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
Chris@16
|
108 {
|
Chris@16
|
109 result = val;
|
Chris@16
|
110 result.sign(false);
|
Chris@16
|
111 }
|
Chris@16
|
112
|
Chris@16
|
113 //
|
Chris@16
|
114 // Get the location of the least-significant-bit:
|
Chris@16
|
115 //
|
Chris@16
|
116 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
117 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
|
Chris@16
|
118 eval_lsb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
|
Chris@16
|
119 {
|
Chris@16
|
120 using default_ops::eval_get_sign;
|
Chris@16
|
121 if(eval_get_sign(a) == 0)
|
Chris@16
|
122 {
|
Chris@16
|
123 BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
|
Chris@16
|
124 }
|
Chris@16
|
125 if(a.sign())
|
Chris@16
|
126 {
|
Chris@16
|
127 BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
|
Chris@16
|
128 }
|
Chris@16
|
129
|
Chris@16
|
130 //
|
Chris@16
|
131 // Find the index of the least significant limb that is non-zero:
|
Chris@16
|
132 //
|
Chris@16
|
133 unsigned index = 0;
|
Chris@16
|
134 while(!a.limbs()[index] && (index < a.size()))
|
Chris@16
|
135 ++index;
|
Chris@16
|
136 //
|
Chris@16
|
137 // Find the index of the least significant bit within that limb:
|
Chris@16
|
138 //
|
Chris@16
|
139 unsigned result = boost::multiprecision::detail::find_lsb(a.limbs()[index]);
|
Chris@16
|
140
|
Chris@16
|
141 return result + index * cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
Chris@16
|
142 }
|
Chris@16
|
143
|
Chris@16
|
144 //
|
Chris@16
|
145 // Get the location of the most-significant-bit:
|
Chris@16
|
146 //
|
Chris@16
|
147 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
148 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
|
Chris@16
|
149 eval_msb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
|
Chris@16
|
150 {
|
Chris@16
|
151 using default_ops::eval_get_sign;
|
Chris@16
|
152 if(eval_get_sign(a) == 0)
|
Chris@16
|
153 {
|
Chris@16
|
154 BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
|
Chris@16
|
155 }
|
Chris@16
|
156 if(a.sign())
|
Chris@16
|
157 {
|
Chris@16
|
158 BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
|
Chris@16
|
159 }
|
Chris@16
|
160
|
Chris@16
|
161 //
|
Chris@16
|
162 // Find the index of the most significant bit that is non-zero:
|
Chris@16
|
163 //
|
Chris@16
|
164 return (a.size() - 1) * cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits + boost::multiprecision::detail::find_msb(a.limbs()[a.size() - 1]);
|
Chris@16
|
165 }
|
Chris@16
|
166
|
Chris@16
|
167 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
168 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, bool>::type
|
Chris@16
|
169 eval_bit_test(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index) BOOST_NOEXCEPT
|
Chris@16
|
170 {
|
Chris@16
|
171 unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
Chris@16
|
172 unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
Chris@16
|
173 limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
|
Chris@16
|
174 if(offset >= val.size())
|
Chris@16
|
175 return false;
|
Chris@16
|
176 return val.limbs()[offset] & mask ? true : false;
|
Chris@16
|
177 }
|
Chris@16
|
178
|
Chris@16
|
179 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
180 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
Chris@16
|
181 eval_bit_set(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index)
|
Chris@16
|
182 {
|
Chris@16
|
183 unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
Chris@16
|
184 unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
Chris@16
|
185 limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
|
Chris@16
|
186 if(offset >= val.size())
|
Chris@16
|
187 {
|
Chris@16
|
188 unsigned os = val.size();
|
Chris@16
|
189 val.resize(offset + 1, offset + 1);
|
Chris@16
|
190 if(offset >= val.size())
|
Chris@16
|
191 return; // fixed precision overflow
|
Chris@16
|
192 for(unsigned i = os; i <= offset; ++i)
|
Chris@16
|
193 val.limbs()[i] = 0;
|
Chris@16
|
194 }
|
Chris@16
|
195 val.limbs()[offset] |= mask;
|
Chris@16
|
196 }
|
Chris@16
|
197
|
Chris@16
|
198 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
199 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
Chris@16
|
200 eval_bit_unset(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index) BOOST_NOEXCEPT
|
Chris@16
|
201 {
|
Chris@16
|
202 unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
Chris@16
|
203 unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
Chris@16
|
204 limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
|
Chris@16
|
205 if(offset >= val.size())
|
Chris@16
|
206 return;
|
Chris@16
|
207 val.limbs()[offset] &= ~mask;
|
Chris@16
|
208 val.normalize();
|
Chris@16
|
209 }
|
Chris@16
|
210
|
Chris@16
|
211 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
212 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
Chris@16
|
213 eval_bit_flip(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val, unsigned index)
|
Chris@16
|
214 {
|
Chris@16
|
215 unsigned offset = index / cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
Chris@16
|
216 unsigned shift = index % cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::limb_bits;
|
Chris@16
|
217 limb_type mask = shift ? limb_type(1u) << shift : limb_type(1u);
|
Chris@16
|
218 if(offset >= val.size())
|
Chris@16
|
219 {
|
Chris@16
|
220 unsigned os = val.size();
|
Chris@16
|
221 val.resize(offset + 1, offset + 1);
|
Chris@16
|
222 if(offset >= val.size())
|
Chris@16
|
223 return; // fixed precision overflow
|
Chris@16
|
224 for(unsigned i = os; i <= offset; ++i)
|
Chris@16
|
225 val.limbs()[i] = 0;
|
Chris@16
|
226 }
|
Chris@16
|
227 val.limbs()[offset] ^= mask;
|
Chris@16
|
228 val.normalize();
|
Chris@16
|
229 }
|
Chris@16
|
230
|
Chris@16
|
231 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
232 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
Chris@16
|
233 eval_qr(
|
Chris@16
|
234 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
|
Chris@16
|
235 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& y,
|
Chris@16
|
236 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
|
Chris@16
|
237 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
Chris@16
|
238 {
|
Chris@16
|
239 divide_unsigned_helper(&q, x, y, r);
|
Chris@16
|
240 q.sign(x.sign() != y.sign());
|
Chris@16
|
241 r.sign(x.sign());
|
Chris@16
|
242 }
|
Chris@16
|
243
|
Chris@101
|
244 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@101
|
245 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
Chris@101
|
246 eval_qr(
|
Chris@101
|
247 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
|
Chris@101
|
248 limb_type y,
|
Chris@101
|
249 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
|
Chris@101
|
250 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
Chris@101
|
251 {
|
Chris@101
|
252 divide_unsigned_helper(&q, x, y, r);
|
Chris@101
|
253 q.sign(x.sign());
|
Chris@101
|
254 r.sign(x.sign());
|
Chris@101
|
255 }
|
Chris@101
|
256
|
Chris@101
|
257 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class U>
|
Chris@101
|
258 inline typename enable_if_c<is_integral<U>::value>::type eval_qr(
|
Chris@101
|
259 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x,
|
Chris@101
|
260 U y,
|
Chris@101
|
261 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& q,
|
Chris@101
|
262 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& r) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
Chris@101
|
263 {
|
Chris@101
|
264 using default_ops::eval_qr;
|
Chris@101
|
265 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> t(y);
|
Chris@101
|
266 eval_qr(x, t, q, r);
|
Chris@101
|
267 }
|
Chris@101
|
268
|
Chris@16
|
269 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
|
Chris@16
|
270 inline typename enable_if_c<is_unsigned<Integer>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, Integer>::type
|
Chris@16
|
271 eval_integer_modulus(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x, Integer val)
|
Chris@16
|
272 {
|
Chris@16
|
273 if((sizeof(Integer) <= sizeof(limb_type)) || (val <= (std::numeric_limits<limb_type>::max)()))
|
Chris@16
|
274 {
|
Chris@16
|
275 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> d;
|
Chris@16
|
276 divide_unsigned_helper(static_cast<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>*>(0), x, static_cast<limb_type>(val), d);
|
Chris@16
|
277 return d.limbs()[0];
|
Chris@16
|
278 }
|
Chris@16
|
279 else
|
Chris@16
|
280 {
|
Chris@16
|
281 return default_ops::eval_integer_modulus(x, val);
|
Chris@16
|
282 }
|
Chris@16
|
283 }
|
Chris@16
|
284
|
Chris@16
|
285 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
|
Chris@16
|
286 BOOST_MP_FORCEINLINE typename enable_if_c<is_signed<Integer>::value && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, Integer>::type
|
Chris@16
|
287 eval_integer_modulus(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& x, Integer val)
|
Chris@16
|
288 {
|
Chris@101
|
289 return eval_integer_modulus(x, boost::multiprecision::detail::unsigned_abs(val));
|
Chris@16
|
290 }
|
Chris@16
|
291
|
Chris@16
|
292 inline limb_type integer_gcd_reduce(limb_type u, limb_type v)
|
Chris@16
|
293 {
|
Chris@16
|
294 do
|
Chris@16
|
295 {
|
Chris@16
|
296 if(u > v)
|
Chris@16
|
297 std::swap(u, v);
|
Chris@16
|
298 if(u == v)
|
Chris@16
|
299 break;
|
Chris@16
|
300 v -= u;
|
Chris@16
|
301 v >>= boost::multiprecision::detail::find_lsb(v);
|
Chris@16
|
302 } while(true);
|
Chris@16
|
303 return u;
|
Chris@16
|
304 }
|
Chris@16
|
305
|
Chris@16
|
306 inline double_limb_type integer_gcd_reduce(double_limb_type u, double_limb_type v)
|
Chris@16
|
307 {
|
Chris@16
|
308 do
|
Chris@16
|
309 {
|
Chris@16
|
310 if(u > v)
|
Chris@16
|
311 std::swap(u, v);
|
Chris@16
|
312 if(u == v)
|
Chris@16
|
313 break;
|
Chris@16
|
314 if(v <= ~static_cast<limb_type>(0))
|
Chris@16
|
315 {
|
Chris@16
|
316 u = integer_gcd_reduce(static_cast<limb_type>(v), static_cast<limb_type>(u));
|
Chris@16
|
317 break;
|
Chris@16
|
318 }
|
Chris@16
|
319 v -= u;
|
Chris@16
|
320 while((static_cast<unsigned>(v) & 1u) == 0)
|
Chris@16
|
321 v >>= 1;
|
Chris@16
|
322 } while(true);
|
Chris@16
|
323 return u;
|
Chris@16
|
324 }
|
Chris@16
|
325
|
Chris@16
|
326 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
327 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
Chris@16
|
328 eval_gcd(
|
Chris@16
|
329 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
Chris@16
|
330 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
|
Chris@16
|
331 limb_type v)
|
Chris@16
|
332 {
|
Chris@16
|
333 using default_ops::eval_lsb;
|
Chris@16
|
334 using default_ops::eval_is_zero;
|
Chris@16
|
335 using default_ops::eval_get_sign;
|
Chris@16
|
336
|
Chris@16
|
337 int shift;
|
Chris@16
|
338
|
Chris@16
|
339 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> u(a);
|
Chris@16
|
340
|
Chris@16
|
341 int s = eval_get_sign(u);
|
Chris@16
|
342
|
Chris@16
|
343 /* GCD(0,x) := x */
|
Chris@16
|
344 if(s < 0)
|
Chris@16
|
345 {
|
Chris@16
|
346 u.negate();
|
Chris@16
|
347 }
|
Chris@16
|
348 else if(s == 0)
|
Chris@16
|
349 {
|
Chris@16
|
350 result = v;
|
Chris@16
|
351 return;
|
Chris@16
|
352 }
|
Chris@16
|
353 if(v == 0)
|
Chris@16
|
354 {
|
Chris@16
|
355 result = u;
|
Chris@16
|
356 return;
|
Chris@16
|
357 }
|
Chris@16
|
358
|
Chris@16
|
359 /* Let shift := lg K, where K is the greatest power of 2
|
Chris@16
|
360 dividing both u and v. */
|
Chris@16
|
361
|
Chris@16
|
362 unsigned us = eval_lsb(u);
|
Chris@16
|
363 unsigned vs = boost::multiprecision::detail::find_lsb(v);
|
Chris@16
|
364 shift = (std::min)(us, vs);
|
Chris@16
|
365 eval_right_shift(u, us);
|
Chris@16
|
366 if(vs)
|
Chris@16
|
367 v >>= vs;
|
Chris@16
|
368
|
Chris@16
|
369 do
|
Chris@16
|
370 {
|
Chris@16
|
371 /* Now u and v are both odd, so diff(u, v) is even.
|
Chris@16
|
372 Let u = min(u, v), v = diff(u, v)/2. */
|
Chris@16
|
373 if(u.size() <= 2)
|
Chris@16
|
374 {
|
Chris@16
|
375 if(u.size() == 1)
|
Chris@16
|
376 v = integer_gcd_reduce(*u.limbs(), v);
|
Chris@16
|
377 else
|
Chris@16
|
378 {
|
Chris@16
|
379 double_limb_type i;
|
Chris@16
|
380 i = u.limbs()[0] | (static_cast<double_limb_type>(u.limbs()[1]) << sizeof(limb_type) * CHAR_BIT);
|
Chris@16
|
381 v = static_cast<limb_type>(integer_gcd_reduce(i, static_cast<double_limb_type>(v)));
|
Chris@16
|
382 }
|
Chris@16
|
383 break;
|
Chris@16
|
384 }
|
Chris@16
|
385 eval_subtract(u, v);
|
Chris@16
|
386 us = eval_lsb(u);
|
Chris@16
|
387 eval_right_shift(u, us);
|
Chris@16
|
388 }
|
Chris@16
|
389 while(true);
|
Chris@16
|
390
|
Chris@16
|
391 result = v;
|
Chris@16
|
392 eval_left_shift(result, shift);
|
Chris@16
|
393 }
|
Chris@16
|
394 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
|
Chris@16
|
395 inline typename enable_if_c<is_unsigned<Integer>::value && (sizeof(Integer) <= sizeof(limb_type)) && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
Chris@16
|
396 eval_gcd(
|
Chris@16
|
397 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
Chris@16
|
398 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
|
Chris@16
|
399 const Integer& v)
|
Chris@16
|
400 {
|
Chris@16
|
401 eval_gcd(result, a, static_cast<limb_type>(v));
|
Chris@16
|
402 }
|
Chris@16
|
403 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1, class Integer>
|
Chris@16
|
404 inline typename enable_if_c<is_signed<Integer>::value && (sizeof(Integer) <= sizeof(limb_type)) && !is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
Chris@16
|
405 eval_gcd(
|
Chris@16
|
406 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
Chris@16
|
407 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
|
Chris@16
|
408 const Integer& v)
|
Chris@16
|
409 {
|
Chris@16
|
410 eval_gcd(result, a, static_cast<limb_type>(v < 0 ? -v : v));
|
Chris@16
|
411 }
|
Chris@16
|
412
|
Chris@16
|
413 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
414 inline typename enable_if_c<!is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
Chris@16
|
415 eval_gcd(
|
Chris@16
|
416 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result,
|
Chris@16
|
417 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a,
|
Chris@16
|
418 const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b)
|
Chris@16
|
419 {
|
Chris@16
|
420 using default_ops::eval_lsb;
|
Chris@16
|
421 using default_ops::eval_is_zero;
|
Chris@16
|
422 using default_ops::eval_get_sign;
|
Chris@16
|
423
|
Chris@16
|
424 if(a.size() == 1)
|
Chris@16
|
425 {
|
Chris@16
|
426 eval_gcd(result, b, *a.limbs());
|
Chris@16
|
427 return;
|
Chris@16
|
428 }
|
Chris@16
|
429 if(b.size() == 1)
|
Chris@16
|
430 {
|
Chris@16
|
431 eval_gcd(result, a, *b.limbs());
|
Chris@16
|
432 return;
|
Chris@16
|
433 }
|
Chris@16
|
434
|
Chris@16
|
435 int shift;
|
Chris@16
|
436
|
Chris@16
|
437 cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> u(a), v(b);
|
Chris@16
|
438
|
Chris@16
|
439 int s = eval_get_sign(u);
|
Chris@16
|
440
|
Chris@16
|
441 /* GCD(0,x) := x */
|
Chris@16
|
442 if(s < 0)
|
Chris@16
|
443 {
|
Chris@16
|
444 u.negate();
|
Chris@16
|
445 }
|
Chris@16
|
446 else if(s == 0)
|
Chris@16
|
447 {
|
Chris@16
|
448 result = v;
|
Chris@16
|
449 return;
|
Chris@16
|
450 }
|
Chris@16
|
451 s = eval_get_sign(v);
|
Chris@16
|
452 if(s < 0)
|
Chris@16
|
453 {
|
Chris@16
|
454 v.negate();
|
Chris@16
|
455 }
|
Chris@16
|
456 else if(s == 0)
|
Chris@16
|
457 {
|
Chris@16
|
458 result = u;
|
Chris@16
|
459 return;
|
Chris@16
|
460 }
|
Chris@16
|
461
|
Chris@16
|
462 /* Let shift := lg K, where K is the greatest power of 2
|
Chris@16
|
463 dividing both u and v. */
|
Chris@16
|
464
|
Chris@16
|
465 unsigned us = eval_lsb(u);
|
Chris@16
|
466 unsigned vs = eval_lsb(v);
|
Chris@16
|
467 shift = (std::min)(us, vs);
|
Chris@16
|
468 eval_right_shift(u, us);
|
Chris@16
|
469 eval_right_shift(v, vs);
|
Chris@16
|
470
|
Chris@16
|
471 do
|
Chris@16
|
472 {
|
Chris@16
|
473 /* Now u and v are both odd, so diff(u, v) is even.
|
Chris@16
|
474 Let u = min(u, v), v = diff(u, v)/2. */
|
Chris@16
|
475 s = u.compare(v);
|
Chris@16
|
476 if(s > 0)
|
Chris@16
|
477 u.swap(v);
|
Chris@16
|
478 if(s == 0)
|
Chris@16
|
479 break;
|
Chris@16
|
480 if(v.size() <= 2)
|
Chris@16
|
481 {
|
Chris@16
|
482 if(v.size() == 1)
|
Chris@16
|
483 u = integer_gcd_reduce(*v.limbs(), *u.limbs());
|
Chris@16
|
484 else
|
Chris@16
|
485 {
|
Chris@16
|
486 double_limb_type i, j;
|
Chris@16
|
487 i = v.limbs()[0] | (static_cast<double_limb_type>(v.limbs()[1]) << sizeof(limb_type) * CHAR_BIT);
|
Chris@16
|
488 j = (u.size() == 1) ? *u.limbs() : u.limbs()[0] | (static_cast<double_limb_type>(u.limbs()[1]) << sizeof(limb_type) * CHAR_BIT);
|
Chris@16
|
489 u = integer_gcd_reduce(i, j);
|
Chris@16
|
490 }
|
Chris@16
|
491 break;
|
Chris@16
|
492 }
|
Chris@16
|
493 eval_subtract(v, u);
|
Chris@16
|
494 vs = eval_lsb(v);
|
Chris@16
|
495 eval_right_shift(v, vs);
|
Chris@16
|
496 }
|
Chris@16
|
497 while(true);
|
Chris@16
|
498
|
Chris@16
|
499 result = u;
|
Chris@16
|
500 eval_left_shift(result, shift);
|
Chris@16
|
501 }
|
Chris@16
|
502 //
|
Chris@16
|
503 // Now again for trivial backends:
|
Chris@16
|
504 //
|
Chris@16
|
505 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
506 BOOST_MP_FORCEINLINE typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value>::type
|
Chris@16
|
507 eval_gcd(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b) BOOST_NOEXCEPT
|
Chris@16
|
508 {
|
Chris@101
|
509 *result.limbs() = boost::integer::gcd(*a.limbs(), *b.limbs());
|
Chris@16
|
510 }
|
Chris@16
|
511 // This one is only enabled for unchecked cpp_int's, for checked int's we need the checking in the default version:
|
Chris@16
|
512 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
513 BOOST_MP_FORCEINLINE typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value && (Checked1 == unchecked)>::type
|
Chris@16
|
514 eval_lcm(cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& b) BOOST_NOEXCEPT_IF((is_non_throwing_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value))
|
Chris@16
|
515 {
|
Chris@101
|
516 *result.limbs() = boost::integer::lcm(*a.limbs(), *b.limbs());
|
Chris@16
|
517 result.normalize(); // result may overflow the specified number of bits
|
Chris@16
|
518 }
|
Chris@16
|
519
|
Chris@16
|
520 inline void conversion_overflow(const mpl::int_<checked>&)
|
Chris@16
|
521 {
|
Chris@16
|
522 BOOST_THROW_EXCEPTION(std::overflow_error("Overflow in conversion to narrower type"));
|
Chris@16
|
523 }
|
Chris@16
|
524 inline void conversion_overflow(const mpl::int_<unchecked>&){}
|
Chris@16
|
525
|
Chris@16
|
526 template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
527 inline typename enable_if_c<
|
Chris@16
|
528 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
Chris@16
|
529 && is_signed_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
Chris@16
|
530 >::type
|
Chris@16
|
531 eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val)
|
Chris@16
|
532 {
|
Chris@16
|
533 typedef typename common_type<R, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type>::type common_type;
|
Chris@16
|
534 if(std::numeric_limits<R>::is_specialized && (static_cast<common_type>(*val.limbs()) > static_cast<common_type>((std::numeric_limits<R>::max)())))
|
Chris@16
|
535 {
|
Chris@16
|
536 conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
Chris@16
|
537 *result = (std::numeric_limits<R>::max)();
|
Chris@16
|
538 }
|
Chris@16
|
539 else
|
Chris@16
|
540 *result = static_cast<R>(*val.limbs());
|
Chris@16
|
541 if(val.isneg())
|
Chris@16
|
542 {
|
Chris@16
|
543 check_is_negative(mpl::bool_<boost::is_signed<R>::value || boost::is_floating_point<R>::value>());
|
Chris@16
|
544 *result = negate_integer(*result, mpl::bool_<boost::is_signed<R>::value || boost::is_floating_point<R>::value>());
|
Chris@16
|
545 }
|
Chris@16
|
546 }
|
Chris@16
|
547
|
Chris@16
|
548 template <class R, unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
549 inline typename enable_if_c<
|
Chris@16
|
550 is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
Chris@16
|
551 && is_unsigned_number<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value
|
Chris@16
|
552 >::type
|
Chris@16
|
553 eval_convert_to(R* result, const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& val)
|
Chris@16
|
554 {
|
Chris@16
|
555 typedef typename common_type<R, typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::local_limb_type>::type common_type;
|
Chris@16
|
556 if(std::numeric_limits<R>::is_specialized && (static_cast<common_type>(*val.limbs()) > static_cast<common_type>((std::numeric_limits<R>::max)())))
|
Chris@16
|
557 {
|
Chris@16
|
558 conversion_overflow(typename cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>::checked_type());
|
Chris@16
|
559 *result = (std::numeric_limits<R>::max)();
|
Chris@16
|
560 }
|
Chris@16
|
561 else
|
Chris@16
|
562 *result = static_cast<R>(*val.limbs());
|
Chris@16
|
563 }
|
Chris@16
|
564
|
Chris@16
|
565 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
566 inline typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
|
Chris@16
|
567 eval_lsb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
|
Chris@16
|
568 {
|
Chris@16
|
569 using default_ops::eval_get_sign;
|
Chris@16
|
570 if(eval_get_sign(a) == 0)
|
Chris@16
|
571 {
|
Chris@16
|
572 BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
|
Chris@16
|
573 }
|
Chris@16
|
574 if(a.sign())
|
Chris@16
|
575 {
|
Chris@16
|
576 BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
|
Chris@16
|
577 }
|
Chris@16
|
578 //
|
Chris@16
|
579 // Find the index of the least significant bit within that limb:
|
Chris@16
|
580 //
|
Chris@16
|
581 return boost::multiprecision::detail::find_lsb(*a.limbs());
|
Chris@16
|
582 }
|
Chris@16
|
583
|
Chris@16
|
584 template <unsigned MinBits1, unsigned MaxBits1, cpp_integer_type SignType1, cpp_int_check_type Checked1, class Allocator1>
|
Chris@16
|
585 inline typename enable_if_c<is_trivial_cpp_int<cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1> >::value, unsigned>::type
|
Chris@16
|
586 eval_msb(const cpp_int_backend<MinBits1, MaxBits1, SignType1, Checked1, Allocator1>& a)
|
Chris@16
|
587 {
|
Chris@16
|
588 using default_ops::eval_get_sign;
|
Chris@16
|
589 if(eval_get_sign(a) == 0)
|
Chris@16
|
590 {
|
Chris@16
|
591 BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
|
Chris@16
|
592 }
|
Chris@16
|
593 if(a.sign())
|
Chris@16
|
594 {
|
Chris@16
|
595 BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
|
Chris@16
|
596 }
|
Chris@16
|
597 //
|
Chris@16
|
598 // Find the index of the least significant bit within that limb:
|
Chris@16
|
599 //
|
Chris@16
|
600 return boost::multiprecision::detail::find_msb(*a.limbs());
|
Chris@16
|
601 }
|
Chris@16
|
602
|
Chris@16
|
603 #ifdef BOOST_MSVC
|
Chris@16
|
604 #pragma warning(pop)
|
Chris@16
|
605 #endif
|
Chris@16
|
606
|
Chris@16
|
607 }}} // namespaces
|
Chris@16
|
608
|
Chris@16
|
609 #endif
|