Skip to content

Commit 7b2d061

Browse files
authored
Merge pull request #3103 from diffblue/bitwise-arbitrary-width
bitwise_or, _and, _xor can now do arbitrary widths
2 parents 2f36e51 + 7f506ef commit 7b2d061

File tree

1 file changed

+53
-18
lines changed

1 file changed

+53
-18
lines changed

src/util/mp_arith.cpp

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Author: Daniel Kroening, [email protected]
88

99
#include "mp_arith.h"
1010

11+
#include <algorithm>
1112
#include <cctype>
1213
#include <cstdlib>
1314
#include <limits>
@@ -219,34 +220,68 @@ unsigned integer2unsigned(const mp_integer &n)
219220
return (unsigned)ull;
220221
}
221222

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)
226231
{
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+
229248
return result;
230249
}
231250

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
235264
mp_integer bitwise_and(const mp_integer &a, const mp_integer &b)
236265
{
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; });
240273
}
241274

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
245276
mp_integer bitwise_xor(const mp_integer &a, const mp_integer &b)
246277
{
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; });
250285
}
251286

252287
/// arithmetic left shift bitwise operations only make sense on native objects,

0 commit comments

Comments
 (0)