|
8 | 8 |
|
9 | 9 | #include "mp_arith.h"
|
10 | 10 |
|
| 11 | +#include <algorithm> |
11 | 12 | #include <cctype>
|
12 | 13 | #include <cstdlib>
|
13 | 14 | #include <limits>
|
@@ -219,34 +220,68 @@ unsigned integer2unsigned(const mp_integer &n)
|
219 | 220 | return (unsigned)ull;
|
220 | 221 | }
|
221 | 222 |
|
222 |
| -/// bitwise or bitwise operations only make sense on native objects, hence the |
223 |
| -/// largest object size should be the largest available c++ integer size |
224 |
| -/// (currently long long) |
225 |
| -mp_integer bitwise_or(const mp_integer &a, const mp_integer &b) |
| 223 | +/// bitwise binary operation over two integers, given as a functor |
| 224 | +/// \param a: the first integer |
| 225 | +/// \param b: the second integer |
| 226 | +/// \param f: the function over two bits |
| 227 | +mp_integer bitwise( |
| 228 | + const mp_integer &a, |
| 229 | + const mp_integer &b, |
| 230 | + std::function<bool(bool, bool)> f) |
226 | 231 | {
|
227 |
| - PRECONDITION(a.is_ulong() && b.is_ulong()); |
228 |
| - ullong_t result=a.to_ulong()|b.to_ulong(); |
| 232 | + const auto digits = std::max(a.digits(2), b.digits(2)); |
| 233 | + |
| 234 | + mp_integer result = 0; |
| 235 | + mp_integer tmp_a = a, tmp_b = b; |
| 236 | + |
| 237 | + for(std::size_t i = 0; i < digits; i++) |
| 238 | + { |
| 239 | + const bool bit_a = tmp_a.is_odd(); |
| 240 | + const bool bit_b = tmp_b.is_odd(); |
| 241 | + const bool bit_result = f(bit_a, bit_b); |
| 242 | + if(bit_result) |
| 243 | + result += power(2, i); |
| 244 | + tmp_a /= 2; |
| 245 | + tmp_b /= 2; |
| 246 | + } |
| 247 | + |
229 | 248 | return result;
|
230 | 249 | }
|
231 | 250 |
|
232 |
| -/// bitwise and bitwise operations only make sense on native objects, hence the |
233 |
| -/// largest object size should be the largest available c++ integer size |
234 |
| -/// (currently long long) |
| 251 | +/// bitwise 'or' of two nonnegative integers |
| 252 | +mp_integer bitwise_or(const mp_integer &a, const mp_integer &b) |
| 253 | +{ |
| 254 | + PRECONDITION(!a.is_negative() && !b.is_negative()); |
| 255 | + |
| 256 | + // fast path for small numbers |
| 257 | + if(a.is_ulong() && b.is_ulong()) |
| 258 | + return a.to_ulong() | b.to_ulong(); |
| 259 | + |
| 260 | + return bitwise(a, b, [](bool a, bool b) { return a || b; }); |
| 261 | +} |
| 262 | + |
| 263 | +/// bitwise 'and' of two nonnegative integers |
235 | 264 | mp_integer bitwise_and(const mp_integer &a, const mp_integer &b)
|
236 | 265 | {
|
237 |
| - PRECONDITION(a.is_ulong() && b.is_ulong()); |
238 |
| - ullong_t result=a.to_ulong()&b.to_ulong(); |
239 |
| - return result; |
| 266 | + PRECONDITION(!a.is_negative() && !b.is_negative()); |
| 267 | + |
| 268 | + // fast path for small numbers |
| 269 | + if(a.is_ulong() && b.is_ulong()) |
| 270 | + return a.to_ulong() & b.to_ulong(); |
| 271 | + |
| 272 | + return bitwise(a, b, [](bool a, bool b) { return a && b; }); |
240 | 273 | }
|
241 | 274 |
|
242 |
| -/// bitwise xor bitwise operations only make sense on native objects, hence the |
243 |
| -/// largest object size should be the largest available c++ integer size |
244 |
| -/// (currently long long) |
| 275 | +/// bitwise 'xor' of two nonnegative integers |
245 | 276 | mp_integer bitwise_xor(const mp_integer &a, const mp_integer &b)
|
246 | 277 | {
|
247 |
| - PRECONDITION(a.is_ulong() && b.is_ulong()); |
248 |
| - ullong_t result=a.to_ulong()^b.to_ulong(); |
249 |
| - return result; |
| 278 | + PRECONDITION(!a.is_negative() && !b.is_negative()); |
| 279 | + |
| 280 | + // fast path for small numbers |
| 281 | + if(a.is_ulong() && b.is_ulong()) |
| 282 | + return a.to_ulong() ^ b.to_ulong(); |
| 283 | + |
| 284 | + return bitwise(a, b, [](bool a, bool b) { return a ^ b; }); |
250 | 285 | }
|
251 | 286 |
|
252 | 287 | /// arithmetic left shift bitwise operations only make sense on native objects,
|
|
0 commit comments