mirror of
https://github.com/Z3Prover/z3
synced 2026-02-10 02:50:55 +00:00
optimize has_sign_bit and mod2k to not compute powers of two
this is very useful for bitvectors of large bitwidths
This commit is contained in:
parent
74cbd6de32
commit
09370d7782
6 changed files with 97 additions and 34 deletions
100
src/util/mpz.cpp
100
src/util/mpz.cpp
|
|
@ -633,6 +633,79 @@ void mpz_manager<SYNCH>::mod(mpz const & a, mpz const & b, mpz & c) {
|
|||
STRACE(mpz, tout << to_string(c) << "\n";);
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
mpz mpz_manager<SYNCH>::mod2k(mpz const & a, unsigned k) {
|
||||
if (is_zero(a))
|
||||
return 0;
|
||||
|
||||
mpz result;
|
||||
|
||||
if (is_small(a) && k < 64) {
|
||||
uint64_t mask = ((1ULL << k) - 1);
|
||||
uint64_t uval = static_cast<uint64_t>(i64(a));
|
||||
set_i64(result, static_cast<int64_t>(uval & mask));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (is_nonneg(a) && bitsize(a) <= k) {
|
||||
return dup(a);
|
||||
}
|
||||
|
||||
#ifndef _MP_GMP
|
||||
sign_cell ca(*this, a);
|
||||
unsigned digit_size = sizeof(digit_t) * 8;
|
||||
unsigned digit_count = k / digit_size;
|
||||
unsigned rem_bits = k % digit_size;
|
||||
unsigned total_digits = digit_count + (rem_bits > 0);
|
||||
digit_t mask = (1ULL << rem_bits) - 1;
|
||||
bool is_zero = true;
|
||||
|
||||
allocate_if_needed(result, total_digits);
|
||||
|
||||
// compute |a| mod 2^k-
|
||||
for (unsigned i = 0, e = std::min(digit_count, ca.cell()->m_size); i < e; ++i) {
|
||||
is_zero &= (digits(result)[i] = ca.cell()->m_digits[i]) == 0;
|
||||
}
|
||||
for (unsigned i = ca.cell()->m_size; i < total_digits; ++i) {
|
||||
digits(result)[i] = 0;
|
||||
}
|
||||
|
||||
if (rem_bits > 0 && digit_count < ca.cell()->m_size) {
|
||||
is_zero &= (digits(result)[digit_count] = ca.cell()->m_digits[digit_count] & mask) == 0;
|
||||
}
|
||||
result.m_ptr->m_size = total_digits;
|
||||
|
||||
if (ca.sign() < 0 && !is_zero) {
|
||||
// Negative case: if non-zero, result = 2^k - (|a| mod 2^k)
|
||||
// which boils down to computing ~result + 1
|
||||
for (unsigned i = 0; i < total_digits; ++i) {
|
||||
digits(result)[i] = ~digits(result)[i];
|
||||
}
|
||||
|
||||
// Increment result
|
||||
digit_t carry = 1;
|
||||
for (unsigned i = 0; i < total_digits && carry; ++i) {
|
||||
digit_t sum = digits(result)[i] + carry;
|
||||
carry = sum < digits(result)[i];
|
||||
digits(result)[i] = sum;
|
||||
}
|
||||
|
||||
// Clamp to k bits
|
||||
if (rem_bits != 0) {
|
||||
digits(result)[digit_count] &= mask;
|
||||
}
|
||||
}
|
||||
normalize(result);
|
||||
#else
|
||||
ensure_mpz_t a1(a);
|
||||
mk_big(result);
|
||||
MPZ_BEGIN_CRITICAL();
|
||||
mpz_tdiv_r_2exp(*result.m_ptr, a1(), k);
|
||||
MPZ_END_CRITICAL();
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
void mpz_manager<SYNCH>::neg(mpz & a) {
|
||||
STRACE(mpz, tout << "[mpz] 0 - " << to_string(a) << " == ";);
|
||||
|
|
@ -1140,13 +1213,9 @@ unsigned mpz_manager<SYNCH>::size_info(mpz const & a) {
|
|||
|
||||
template<bool SYNCH>
|
||||
struct mpz_manager<SYNCH>::sz_lt {
|
||||
mpz_manager<SYNCH> & m;
|
||||
mpz const * m_as;
|
||||
|
||||
sz_lt(mpz_manager<SYNCH> & _m, mpz const * as):m(_m), m_as(as) {}
|
||||
|
||||
mpz const * m_as;
|
||||
bool operator()(unsigned p1, unsigned p2) {
|
||||
return m.size_info(m_as[p1]) < m.size_info(m_as[p2]);
|
||||
return size_info(m_as[p1]) < size_info(m_as[p2]);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1180,8 +1249,7 @@ void mpz_manager<SYNCH>::gcd(unsigned sz, mpz const * as, mpz & g) {
|
|||
sbuffer<unsigned, 1024> p;
|
||||
for (i = 0; i < sz; ++i)
|
||||
p.push_back(i);
|
||||
sz_lt lt(*this, as);
|
||||
std::sort(p.begin(), p.end(), lt);
|
||||
std::sort(p.begin(), p.end(), sz_lt{as});
|
||||
TRACE(mpz_gcd, for (unsigned i = 0; i < sz; ++i) tout << p[i] << ":" << size_info(as[p[i]]) << " "; tout << "\n";);
|
||||
gcd(as[p[0]], as[p[1]], g);
|
||||
for (i = 2; i < sz; ++i) {
|
||||
|
|
@ -1695,15 +1763,11 @@ void mpz_manager<SYNCH>::display(std::ostream & out, mpz const & a) const {
|
|||
else {
|
||||
#ifndef _MP_GMP
|
||||
if (a.m_val < 0)
|
||||
out << "-";
|
||||
if (sizeof(digit_t) == 4) {
|
||||
sbuffer<char, 1024> buffer(11*size(a), 0);
|
||||
out << m_mpn_manager.to_string(digits(a), size(a), buffer.begin(), buffer.size());
|
||||
}
|
||||
else {
|
||||
sbuffer<char, 1024> buffer(21*size(a), 0);
|
||||
out << m_mpn_manager.to_string(digits(a), size(a), buffer.begin(), buffer.size());
|
||||
}
|
||||
out << '-';
|
||||
|
||||
auto sz = sizeof(digit_t) == 4 ? 11 : 21;
|
||||
sbuffer<char, 1024> buffer(sz * size(a), 0);
|
||||
out << m_mpn_manager.to_string(digits(a), size(a), buffer.begin(), buffer.size());
|
||||
#else
|
||||
// GMP version
|
||||
size_t sz = mpz_sizeinbase(*a.m_ptr, 10) + 2;
|
||||
|
|
@ -1835,7 +1899,7 @@ template<bool SYNCH>
|
|||
std::string mpz_manager<SYNCH>::to_string(mpz const & a) const {
|
||||
std::ostringstream buffer;
|
||||
display(buffer, a);
|
||||
return buffer.str();
|
||||
return std::move(buffer).str();
|
||||
}
|
||||
|
||||
template<bool SYNCH>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue