mirror of
https://github.com/Z3Prover/z3
synced 2025-04-07 18:05:21 +00:00
867 lines
24 KiB
C++
867 lines
24 KiB
C++
/*++
|
|
Copyright (c) 2012 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
mpfx.h
|
|
|
|
Abstract:
|
|
|
|
Multi precision fixed point numbers.
|
|
|
|
Author:
|
|
|
|
Leonardo de Moura (leonardo) 2012-09-19
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include<sstream>
|
|
#include<iomanip>
|
|
#include"mpfx.h"
|
|
#include"mpn.h"
|
|
#include"mpz.h"
|
|
#include"mpq.h"
|
|
#include"bit_util.h"
|
|
#include"trace.h"
|
|
|
|
mpfx_manager::mpfx_manager(unsigned int_sz, unsigned frac_sz, unsigned initial_capacity) {
|
|
SASSERT(initial_capacity > 0);
|
|
SASSERT(int_sz > 0);
|
|
SASSERT(frac_sz > 0);
|
|
m_int_part_sz = int_sz;
|
|
m_frac_part_sz = frac_sz;
|
|
m_total_sz = m_int_part_sz + m_frac_part_sz;
|
|
m_words.resize(initial_capacity * m_total_sz, 0);
|
|
m_capacity = initial_capacity;
|
|
m_to_plus_inf = false;
|
|
m_buffer0.resize(2*m_total_sz, 0);
|
|
m_buffer1.resize(2*m_total_sz, 0);
|
|
m_buffer2.resize(2*m_total_sz, 0);
|
|
unsigned zero_sig_idx = m_id_gen.mk();
|
|
SASSERT(zero_sig_idx == 0);
|
|
set(m_one, 1);
|
|
}
|
|
|
|
mpfx_manager::~mpfx_manager() {
|
|
del(m_one);
|
|
}
|
|
|
|
void mpfx_manager::expand() {
|
|
m_capacity = 2*m_capacity;
|
|
m_words.resize(m_capacity * m_total_sz, 0);
|
|
}
|
|
|
|
void mpfx_manager::allocate(mpfx & n) {
|
|
SASSERT(n.m_sig_idx == 0);
|
|
unsigned sig_idx = m_id_gen.mk();
|
|
ensure_capacity(sig_idx);
|
|
n.m_sig_idx = sig_idx;
|
|
SASSERT(::is_zero(m_total_sz, words(n)));
|
|
}
|
|
|
|
unsigned mpfx_manager::sz(unsigned * ws) const {
|
|
SASSERT(!::is_zero(m_total_sz, ws));
|
|
unsigned r = m_total_sz;
|
|
while (true) {
|
|
SASSERT(r > 0);
|
|
--r;
|
|
if (ws[r] != 0)
|
|
return r + 1;
|
|
}
|
|
}
|
|
|
|
void mpfx_manager::del(mpfx & n) {
|
|
unsigned sig_idx = n.m_sig_idx;
|
|
if (sig_idx != 0) {
|
|
m_id_gen.recycle(sig_idx);
|
|
unsigned * w = words(n);
|
|
for (unsigned i = 0; i < m_total_sz; i++)
|
|
w[i] = 0;
|
|
}
|
|
}
|
|
|
|
void mpfx_manager::reset(mpfx & n) {
|
|
del(n);
|
|
n.m_sign = false;
|
|
n.m_sig_idx = 0;
|
|
SASSERT(check(n));
|
|
}
|
|
|
|
bool mpfx_manager::is_int(mpfx const & n) const {
|
|
unsigned * w = words(n);
|
|
for (unsigned i = 0; i < m_frac_part_sz; i++)
|
|
if (w[i] != 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool mpfx_manager::is_abs_one(mpfx const & n) const {
|
|
unsigned * w = words(n);
|
|
return is_int(n) && w[m_frac_part_sz] == 1 && ::is_zero(m_int_part_sz - 1, w + m_frac_part_sz + 1);
|
|
}
|
|
|
|
bool mpfx_manager::is_int64(mpfx const & a) const {
|
|
if (!is_int(a))
|
|
return false;
|
|
if (is_zero(a) || m_int_part_sz <= 1)
|
|
return true;
|
|
unsigned * w = words(a);
|
|
w += m_frac_part_sz;
|
|
if (w[1] < 0x80000000u || (w[1] == 0x80000000u && is_neg(a))) {
|
|
for (unsigned i = 2; i < m_int_part_sz; i++)
|
|
if (w[i] != 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool mpfx_manager::is_uint64(mpfx const & a) const {
|
|
if (!is_int(a) || is_neg(a))
|
|
return false;
|
|
if (is_zero(a) || m_int_part_sz <= 2)
|
|
return true;
|
|
unsigned * w = words(a);
|
|
for (unsigned i = m_frac_part_sz + 2; i < m_total_sz; i++)
|
|
if (w[i] != 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
void mpfx_manager::set(mpfx & n, int v) {
|
|
if (v == 0) {
|
|
reset(n);
|
|
}
|
|
else {
|
|
if (v < 0) {
|
|
set(n, static_cast<unsigned>(-v));
|
|
n.m_sign = 1;
|
|
}
|
|
else {
|
|
set(n, static_cast<unsigned>(v));
|
|
}
|
|
}
|
|
SASSERT(get_int64(n) == v);
|
|
SASSERT(check(n));
|
|
}
|
|
|
|
void mpfx_manager::set(mpfx & n, unsigned v) {
|
|
if (v == 0) {
|
|
reset(n);
|
|
}
|
|
else {
|
|
allocate_if_needed(n);
|
|
n.m_sign = 0;
|
|
unsigned * w = words(n);
|
|
for (unsigned i = 0; i < m_total_sz; i++)
|
|
w[i] = 0;
|
|
w[m_frac_part_sz] = v;
|
|
}
|
|
SASSERT(is_int(n));
|
|
SASSERT(get_uint64(n) == v);
|
|
SASSERT(check(n));
|
|
}
|
|
|
|
void mpfx_manager::set(mpfx & n, int64 v) {
|
|
if (m_int_part_sz == 1) {
|
|
if (v < -static_cast<int64>(static_cast<uint64>(UINT_MAX)) ||
|
|
v > static_cast<int64>(static_cast<uint64>(UINT_MAX)))
|
|
throw overflow_exception();
|
|
}
|
|
if (v == 0) {
|
|
reset(n);
|
|
}
|
|
else {
|
|
if (v < 0) {
|
|
set(n, static_cast<uint64>(-v));
|
|
n.m_sign = 1;
|
|
}
|
|
else {
|
|
set(n, static_cast<uint64>(v));
|
|
}
|
|
}
|
|
SASSERT(is_int(n));
|
|
SASSERT(get_int64(n) == v);
|
|
SASSERT(check(n));
|
|
}
|
|
|
|
void mpfx_manager::set(mpfx & n, uint64 v) {
|
|
if (m_int_part_sz == 1) {
|
|
if (v > static_cast<uint64>(UINT_MAX))
|
|
throw overflow_exception();
|
|
}
|
|
|
|
if (v == 0) {
|
|
reset(n);
|
|
}
|
|
else {
|
|
allocate_if_needed(n);
|
|
n.m_sign = 0;
|
|
unsigned * _v = reinterpret_cast<unsigned*>(&v);
|
|
unsigned * w = words(n);
|
|
for (unsigned i = 0; i < m_total_sz; i++)
|
|
w[i] = 0;
|
|
w[m_frac_part_sz] = _v[0];
|
|
if (m_int_part_sz == 1) {
|
|
SASSERT(_v[1] == 0);
|
|
}
|
|
else {
|
|
w[m_frac_part_sz+1] = _v[1];
|
|
}
|
|
}
|
|
SASSERT(is_int(n));
|
|
SASSERT(get_uint64(n) == v);
|
|
SASSERT(check(n));
|
|
}
|
|
|
|
void mpfx_manager::set(mpfx & n, int num, unsigned den) {
|
|
scoped_mpfx a(*this), b(*this);
|
|
set(a, num);
|
|
set(b, den);
|
|
div(a, b, n);
|
|
SASSERT(check(n));
|
|
}
|
|
|
|
void mpfx_manager::set(mpfx & n, int64 num, uint64 den) {
|
|
scoped_mpfx a(*this), b(*this);
|
|
set(a, num);
|
|
set(b, den);
|
|
div(a, b, n);
|
|
SASSERT(check(n));
|
|
}
|
|
|
|
void mpfx_manager::set(mpfx & n, mpfx const & v) {
|
|
if (is_zero(v)) {
|
|
reset(n);
|
|
return;
|
|
}
|
|
allocate_if_needed(n);
|
|
n.m_sign = v.m_sign;
|
|
unsigned * w1 = words(n);
|
|
unsigned * w2 = words(v);
|
|
for (unsigned i = 0; i < m_total_sz; i++)
|
|
w1[i] = w2[i];
|
|
SASSERT(check(n));
|
|
}
|
|
|
|
template<bool SYNCH>
|
|
void mpfx_manager::set_core(mpfx & n, mpz_manager<SYNCH> & m, mpz const & v) {
|
|
if (m.is_zero(v)) {
|
|
reset(n);
|
|
}
|
|
else {
|
|
m_tmp_digits.reset();
|
|
allocate_if_needed(n);
|
|
n.m_sign = m.decompose(v, m_tmp_digits);
|
|
unsigned sz = m_tmp_digits.size();
|
|
if (sz > m_int_part_sz)
|
|
throw overflow_exception();
|
|
unsigned * w = words(n);
|
|
for (unsigned i = 0; i < m_frac_part_sz; i++)
|
|
w[i] = 0;
|
|
::copy(sz, m_tmp_digits.c_ptr(), m_int_part_sz, w + m_frac_part_sz);
|
|
}
|
|
SASSERT(check(n));
|
|
}
|
|
|
|
void mpfx_manager::set(mpfx & n, unsynch_mpz_manager & m, mpz const & v) {
|
|
set_core(n, m, v);
|
|
}
|
|
|
|
void mpfx_manager::set(mpfx & n, synch_mpz_manager & m, mpz const & v) {
|
|
set_core(n, m, v);
|
|
}
|
|
|
|
template<bool SYNCH>
|
|
void mpfx_manager::set_core(mpfx & n, mpq_manager<SYNCH> & m, mpq const & v) {
|
|
if (m.is_int(v)) {
|
|
set_core(n, m, v.numerator());
|
|
}
|
|
else {
|
|
allocate_if_needed(n);
|
|
_scoped_numeral<mpz_manager<SYNCH> > tmp(m);
|
|
n.m_sign = is_neg(n);
|
|
m.mul2k(v.numerator(), 8 * sizeof(unsigned) * m_frac_part_sz, tmp);
|
|
m.abs(tmp);
|
|
if ((n.m_sign == 1) != m_to_plus_inf && !m.divides(v.denominator(), tmp)) {
|
|
m.div(tmp, v.denominator(), tmp);
|
|
m.inc(tmp);
|
|
}
|
|
else {
|
|
m.div(tmp, v.denominator(), tmp);
|
|
}
|
|
m_tmp_digits.reset();
|
|
m.decompose(tmp, m_tmp_digits);
|
|
unsigned sz = m_tmp_digits.size();
|
|
if (sz > m_total_sz)
|
|
throw overflow_exception();
|
|
unsigned * w = words(n);
|
|
::copy(sz, m_tmp_digits.c_ptr(), m_total_sz, w);
|
|
}
|
|
SASSERT(check(n));
|
|
}
|
|
|
|
void mpfx_manager::set(mpfx & n, unsynch_mpq_manager & m, mpq const & v) {
|
|
set_core(n, m, v);
|
|
}
|
|
|
|
void mpfx_manager::set(mpfx & n, synch_mpq_manager & m, mpq const & v) {
|
|
set_core(n, m, v);
|
|
}
|
|
|
|
bool mpfx_manager::eq(mpfx const & a, mpfx const & b) const {
|
|
if (is_zero(a) && is_zero(b))
|
|
return true;
|
|
if (is_zero(a) || is_zero(b))
|
|
return false;
|
|
if (a.m_sign != b.m_sign)
|
|
return false;
|
|
unsigned * w1 = words(a);
|
|
unsigned * w2 = words(b);
|
|
for (unsigned i = 0; i < m_total_sz; i++)
|
|
if (w1[i] != w2[i])
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool mpfx_manager::lt(mpfx const & a, mpfx const & b) const {
|
|
STRACE("mpfx_trace", tout << "[mpfx] ("; display(tout, a); tout << " < "; display(tout, b); tout << ") == ";);
|
|
bool r;
|
|
if (is_zero(a)) {
|
|
r = !is_zero(b) && !is_neg(b);
|
|
}
|
|
else if (is_zero(b)) {
|
|
r = is_neg(a);
|
|
}
|
|
else {
|
|
SASSERT(!is_zero(a));
|
|
SASSERT(!is_zero(b));
|
|
if (is_neg(a)) {
|
|
r = is_pos(b) || ::lt(m_total_sz, words(b), words(a));
|
|
}
|
|
else {
|
|
SASSERT(is_pos(a));
|
|
r = is_pos(b) && ::lt(m_total_sz, words(a), words(b));
|
|
}
|
|
}
|
|
STRACE("mpfx_trace", tout << "(" << r << " == 1)\n";);
|
|
return r;
|
|
}
|
|
|
|
void mpfx_manager::add_sub(bool is_sub, mpfx const & a, mpfx const & b, mpfx & c) {
|
|
if (is_zero(a)) {
|
|
set(c, b);
|
|
if (is_sub)
|
|
neg(c);
|
|
return;
|
|
}
|
|
|
|
if (is_zero(b)) {
|
|
set(c, a);
|
|
return;
|
|
}
|
|
|
|
TRACE("mpfx", tout << (is_sub ? "sub" : "add") << "("; display(tout, a); tout << ", "; display(tout, b); tout << ")\n";);
|
|
|
|
allocate_if_needed(c);
|
|
|
|
bool sgn_a = a.m_sign;
|
|
bool sgn_b = b.m_sign;
|
|
unsigned * w_a = words(a);
|
|
unsigned * w_b = words(b);
|
|
|
|
if (is_sub)
|
|
sgn_b = !sgn_b;
|
|
|
|
// Compute c
|
|
unsigned * w_c = words(c);
|
|
if (sgn_a == sgn_b) {
|
|
c.m_sign = sgn_a;
|
|
if (!::add(m_total_sz, w_a, w_b, w_c))
|
|
throw overflow_exception();
|
|
}
|
|
else {
|
|
unsigned borrow;
|
|
SASSERT(sgn_a != sgn_b);
|
|
if (::lt(m_total_sz, w_a, w_b)) {
|
|
c.m_sign = sgn_b;
|
|
sub_diff(w_b, m_total_sz, w_a, m_total_sz, w_c, &borrow, 0);
|
|
SASSERT(!::is_zero(m_total_sz, w_c));
|
|
}
|
|
else {
|
|
c.m_sign = sgn_a;
|
|
sub_diff(w_a, m_total_sz, w_b, m_total_sz, w_c, &borrow, 0);
|
|
if (::is_zero(m_total_sz, w_c))
|
|
reset(c);
|
|
}
|
|
SASSERT(borrow == 0);
|
|
}
|
|
TRACE("mpfx", tout << "result: "; display(tout, c); tout << "\n";);
|
|
SASSERT(check(c));
|
|
}
|
|
|
|
void mpfx_manager::add(mpfx const & a, mpfx const & b, mpfx & c) {
|
|
STRACE("mpfx_trace", tout << "[mpfx] "; display(tout, a); tout << " + "; display(tout, b); tout << " == ";);
|
|
add_sub(false, a, b, c);
|
|
STRACE("mpfx_trace", display(tout, c); tout << "\n";);
|
|
}
|
|
|
|
void mpfx_manager::sub(mpfx const & a, mpfx const & b, mpfx & c) {
|
|
STRACE("mpfx_trace", tout << "[mpfx] "; display(tout, a); tout << " - "; display(tout, b); tout << " == ";);
|
|
add_sub(true, a, b, c);
|
|
STRACE("mpfx_trace", display(tout, c); tout << "\n";);
|
|
}
|
|
|
|
void mpfx_manager::mul(mpfx const & a, mpfx const & b, mpfx & c) {
|
|
STRACE("mpfx_trace", tout << "[mpfx] ("; display(tout, a); tout << ") * ("; display(tout, b); tout << ") " << (m_to_plus_inf ? "<=" : ">=") << " ";);
|
|
if (is_zero(a) || is_zero(b)) {
|
|
reset(c);
|
|
}
|
|
else {
|
|
allocate_if_needed(c);
|
|
c.m_sign = a.m_sign ^ b.m_sign;
|
|
unsigned * r = m_buffer0.c_ptr();
|
|
multiply(words(a), m_total_sz, words(b), m_total_sz, r, 0);
|
|
// round result
|
|
unsigned * _r = r + m_frac_part_sz;
|
|
if ((c.m_sign == 1) != m_to_plus_inf && !::is_zero(m_frac_part_sz, r)) {
|
|
if (!::inc(m_total_sz, _r))
|
|
throw overflow_exception();
|
|
}
|
|
// check for overflows
|
|
if (!::is_zero(m_int_part_sz, _r + m_total_sz))
|
|
throw overflow_exception();
|
|
// copy result to c
|
|
unsigned * w_c = words(c);
|
|
for (unsigned i = 0; i < m_total_sz; i++)
|
|
w_c[i] = _r[i];
|
|
}
|
|
STRACE("mpfx_trace", display(tout, c); tout << "\n";);
|
|
SASSERT(check(c));
|
|
}
|
|
|
|
void mpfx_manager::div(mpfx const & a, mpfx const & b, mpfx & c) {
|
|
if (is_zero(b))
|
|
throw div0_exception();
|
|
STRACE("mpfx_trace", tout << "[mpfx] ("; display(tout, a); tout << ") / ("; display(tout, b); tout << ") " << (m_to_plus_inf ? "<=" : ">=") << " ";);
|
|
if (is_zero(a)) {
|
|
reset(c);
|
|
}
|
|
else {
|
|
allocate_if_needed(c);
|
|
c.m_sign = a.m_sign ^ b.m_sign;
|
|
unsigned * w_a = words(a);
|
|
unsigned * w_a_shft = m_buffer0.c_ptr();
|
|
unsigned a_shft_sz = sz(w_a) + m_frac_part_sz;
|
|
// copy a to buffer 0, and shift by m_frac_part_sz
|
|
for (unsigned i = 0; i < m_frac_part_sz; i++)
|
|
w_a_shft[i] = 0;
|
|
for (unsigned i = 0; i < m_total_sz; i++)
|
|
w_a_shft[i+m_frac_part_sz] = w_a[i];
|
|
unsigned * w_b = words(b);
|
|
unsigned b_sz = sz(w_b);
|
|
unsigned * w_q = m_buffer1.c_ptr();
|
|
if (b_sz > a_shft_sz) {
|
|
if ((c.m_sign == 1) != m_to_plus_inf)
|
|
set_epsilon(c);
|
|
else
|
|
reset(c);
|
|
}
|
|
else {
|
|
unsigned q_sz = a_shft_sz - b_sz + 1;
|
|
unsigned * w_r = m_buffer2.c_ptr();
|
|
unsigned r_sz = b_sz;
|
|
divide(w_a_shft, a_shft_sz,
|
|
w_b, b_sz,
|
|
reciprocal_1_NULL,
|
|
w_q,
|
|
w_r,
|
|
0);
|
|
for (unsigned i = m_total_sz; i < q_sz; i++)
|
|
if (w_q[i] != 0)
|
|
throw overflow_exception();
|
|
if (((c.m_sign == 1) != m_to_plus_inf) && !::is_zero(r_sz, w_r)) {
|
|
// round the result
|
|
if (!::inc(m_total_sz, w_q))
|
|
throw overflow_exception();
|
|
}
|
|
unsigned * w_c = words(c);
|
|
bool zero_q = true;
|
|
if (m_total_sz >= q_sz) {
|
|
unsigned i;
|
|
for (i = 0; i < q_sz; i++) {
|
|
if (w_q[i] != 0)
|
|
zero_q = false;
|
|
w_c[i] = w_q[i];
|
|
}
|
|
for (; i < m_total_sz; i++)
|
|
w_c[i] = 0;
|
|
}
|
|
else {
|
|
for (unsigned i = 0; i < m_total_sz; i++) {
|
|
if (w_q[i] != 0)
|
|
zero_q = false;
|
|
w_c[i] = w_q[i];
|
|
}
|
|
}
|
|
if (zero_q) {
|
|
if ((c.m_sign == 1) != m_to_plus_inf)
|
|
set_epsilon(c);
|
|
else
|
|
reset(c);
|
|
}
|
|
}
|
|
}
|
|
STRACE("mpfx_trace", display(tout, c); tout << "\n";);
|
|
SASSERT(check(c));
|
|
}
|
|
|
|
void mpfx_manager::div2k(mpfx & a, unsigned k) {
|
|
STRACE("mpfx_trace", tout << "[mpfx] ("; display(tout, a); tout << ") / (2^" << k << ") " << (m_to_plus_inf ? "<=" : ">=") << " ";);
|
|
if (!is_zero(a) && k > 0) {
|
|
unsigned * w = words(a);
|
|
bool _inc = ((a.m_sign == 1) != m_to_plus_inf) && has_one_at_first_k_bits(m_total_sz, w, k);
|
|
shr(m_total_sz, w, k, m_total_sz, w);
|
|
if (_inc) {
|
|
VERIFY(::inc(m_total_sz, w));
|
|
SASSERT(!::is_zero(m_total_sz, w));
|
|
}
|
|
else if (::is_zero(m_total_sz, w)) {
|
|
reset(a);
|
|
}
|
|
}
|
|
STRACE("mpfx_trace", display(tout, a); tout << "\n";);
|
|
SASSERT(check(a));
|
|
}
|
|
|
|
void mpfx_manager::set_epsilon(mpfx & n) {
|
|
unsigned * w = words(n);
|
|
w[0] = 1;
|
|
for (unsigned i = 1; i < m_total_sz; i++)
|
|
w[i] = 0;
|
|
}
|
|
|
|
void mpfx_manager::set_minus_epsilon(mpfx & n) {
|
|
set_epsilon(n);
|
|
n.m_sign = true;
|
|
SASSERT(check(n));
|
|
}
|
|
|
|
void mpfx_manager::set_plus_epsilon(mpfx & n) {
|
|
set_epsilon(n);
|
|
n.m_sign = 0;
|
|
SASSERT(check(n));
|
|
}
|
|
|
|
void mpfx_manager::floor(mpfx & n) {
|
|
STRACE("mpfx_trace", tout << "[mpfx] Floor["; display(tout, n); tout << "] == ";);
|
|
unsigned * w = words(n);
|
|
if (is_neg(n)) {
|
|
bool is_int = true;
|
|
for (unsigned i = 0; i < m_frac_part_sz; i++) {
|
|
if (w[i] != 0) {
|
|
is_int = false;
|
|
w[i] = 0;
|
|
}
|
|
}
|
|
if (!is_int && !::inc(m_int_part_sz, w + m_frac_part_sz))
|
|
throw overflow_exception();
|
|
}
|
|
else {
|
|
for (unsigned i = 0; i < m_frac_part_sz; i++)
|
|
w[i] = 0;
|
|
}
|
|
if (::is_zero(m_int_part_sz, w + m_frac_part_sz))
|
|
reset(n);
|
|
SASSERT(check(n));
|
|
STRACE("mpfx_trace", display(tout, n); tout << "\n";);
|
|
}
|
|
|
|
void mpfx_manager::ceil(mpfx & n) {
|
|
STRACE("mpfx_trace", tout << "[mpfx] Ceiling["; display(tout, n); tout << "] == ";);
|
|
unsigned * w = words(n);
|
|
if (is_pos(n)) {
|
|
bool is_int = true;
|
|
for (unsigned i = 0; i < m_frac_part_sz; i++) {
|
|
if (w[i] != 0) {
|
|
is_int = false;
|
|
w[i] = 0;
|
|
}
|
|
}
|
|
if (!is_int && !::inc(m_int_part_sz, w + m_frac_part_sz))
|
|
throw overflow_exception();
|
|
}
|
|
else {
|
|
for (unsigned i = 0; i < m_frac_part_sz; i++)
|
|
w[i] = 0;
|
|
}
|
|
if (::is_zero(m_int_part_sz, w + m_frac_part_sz))
|
|
reset(n);
|
|
SASSERT(check(n));
|
|
STRACE("mpfx_trace", display(tout, n); tout << "\n";);
|
|
}
|
|
|
|
void mpfx_manager::power(mpfx const & a, unsigned p, mpfx & b) {
|
|
#ifdef _TRACE
|
|
scoped_mpfx _a(*this); _a = a;
|
|
unsigned _p = p;
|
|
#endif
|
|
#define SMALL_POWER 8
|
|
SASSERT(check(a));
|
|
if (is_zero(a)) {
|
|
SASSERT(p != 0);
|
|
reset(b);
|
|
}
|
|
else if (p == 0) {
|
|
set(b, 1);
|
|
}
|
|
else if (p == 1) {
|
|
set(b, a);
|
|
}
|
|
else if (p == 2) {
|
|
mul(a, a, b);
|
|
}
|
|
else if (p <= SMALL_POWER && &a != &b) {
|
|
SASSERT(p > 2);
|
|
--p;
|
|
set(b, a);
|
|
while (p > 0) {
|
|
--p;
|
|
mul(a, b, b);
|
|
}
|
|
}
|
|
else {
|
|
unsigned mask = 1;
|
|
scoped_mpfx pw(*this);
|
|
set(pw, a);
|
|
set(b, 1);
|
|
while (mask <= p) {
|
|
if (mask & p)
|
|
mul(b, pw, b);
|
|
mul(pw, pw, pw);
|
|
mask = mask << 1;
|
|
}
|
|
}
|
|
STRACE("mpfx_trace", tout << "[mpfx] ("; display(tout, _a); tout << ") ^ " << _p << (m_to_plus_inf ? "<=" : ">="); display(tout, b); tout << "\n";);
|
|
TRACE("mpfx_power", display_raw(tout, b); tout << "\n";);
|
|
SASSERT(check(b));
|
|
}
|
|
|
|
|
|
bool mpfx_manager::is_power_of_two(mpfx const & a, unsigned & k) const {
|
|
if (!is_int(a) || is_zero(a))
|
|
return false;
|
|
unsigned * w = words(a);
|
|
unsigned i = m_total_sz;
|
|
while (true) {
|
|
SASSERT (i > m_frac_part_sz);
|
|
--i;
|
|
if (w[i] != 0) {
|
|
if (!::is_power_of_two(w[i]))
|
|
return false;
|
|
k = (i - m_frac_part_sz) * 8 * sizeof(unsigned) + log2(w[i]);
|
|
while (i > m_frac_part_sz) {
|
|
--i;
|
|
if (w[i] != 0)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool mpfx_manager::is_power_of_two(mpfx const & a) const {
|
|
unsigned k;
|
|
return is_power_of_two(a, k);
|
|
}
|
|
|
|
int64 mpfx_manager::get_int64(mpfx const & n) const {
|
|
SASSERT(is_int64(n));
|
|
unsigned * w = words(n);
|
|
w += m_frac_part_sz;
|
|
uint64 r = *reinterpret_cast<uint64*>(w);
|
|
if (r == 0x8000000000000000ull) {
|
|
SASSERT(is_neg(n));
|
|
return INT64_MIN;
|
|
}
|
|
else {
|
|
return is_neg(n) ? -static_cast<int64>(r) : r;
|
|
}
|
|
}
|
|
|
|
uint64 mpfx_manager::get_uint64(mpfx const & n) const {
|
|
SASSERT(is_uint64(n));
|
|
unsigned * w = words(n);
|
|
w += m_frac_part_sz;
|
|
return *reinterpret_cast<uint64*>(w);
|
|
}
|
|
|
|
template<bool SYNCH>
|
|
void mpfx_manager::to_mpz_core(mpfx const & n, mpz_manager<SYNCH> & m, mpz & t) {
|
|
SASSERT(is_int(n));
|
|
unsigned * w = words(n);
|
|
m.set(t, m_int_part_sz, w+m_frac_part_sz);
|
|
if (is_neg(n))
|
|
m.neg(t);
|
|
}
|
|
|
|
void mpfx_manager::to_mpz(mpfx const & n, unsynch_mpz_manager & m, mpz & t) {
|
|
to_mpz_core(n, m, t);
|
|
}
|
|
|
|
void mpfx_manager::to_mpz(mpfx const & n, synch_mpz_manager & m, mpz & t) {
|
|
to_mpz_core(n, m, t);
|
|
}
|
|
|
|
template<bool SYNCH>
|
|
void mpfx_manager::to_mpq_core(mpfx const & n, mpq_manager<SYNCH> & m, mpq & t) {
|
|
_scoped_numeral<mpz_manager<SYNCH> > a(m), b(m);
|
|
|
|
unsigned * w = words(n);
|
|
m.set(a, m_total_sz, w);
|
|
|
|
m.set(b, 1);
|
|
m.mul2k(b, sizeof(unsigned)*8*m_frac_part_sz);
|
|
|
|
m.rat_div(a, b, t);
|
|
|
|
if (is_neg(n))
|
|
m.neg(t);
|
|
}
|
|
|
|
void mpfx_manager::to_mpq(mpfx const & n, unsynch_mpq_manager & m, mpq & t) {
|
|
to_mpq_core(n, m, t);
|
|
}
|
|
|
|
void mpfx_manager::to_mpq(mpfx const & n, synch_mpq_manager & m, mpq & t) {
|
|
to_mpq_core(n, m, t);
|
|
}
|
|
|
|
void mpfx_manager::display_raw(std::ostream & out, mpfx const & n) const {
|
|
if (is_neg(n))
|
|
out << "-";
|
|
unsigned * w = words(n);
|
|
unsigned i = m_total_sz;
|
|
while(i > 0) {
|
|
if (i == m_frac_part_sz)
|
|
out << ".";
|
|
--i;
|
|
out << std::hex << std::setfill('0') << std::setw(2 * sizeof(unsigned)) << w[i];
|
|
}
|
|
}
|
|
|
|
void mpfx_manager::display(std::ostream & out, mpfx const & n) const {
|
|
if (is_neg(n))
|
|
out << "-";
|
|
unsigned * w = words(n);
|
|
unsigned sz = m_total_sz;
|
|
unsigned shift = UINT_MAX;
|
|
if (is_int(n)) {
|
|
w += m_frac_part_sz;
|
|
sz -= m_frac_part_sz;
|
|
}
|
|
else {
|
|
shift = ntz(m_total_sz, w);
|
|
if (shift > 0)
|
|
shr(m_total_sz, w, shift, m_total_sz, w);
|
|
}
|
|
|
|
sbuffer<char, 1024> str_buffer(11*sz, 0);
|
|
out << mp_decimal(w, sz, str_buffer.begin(), str_buffer.size(), 0);
|
|
if (!is_int(n)) {
|
|
SASSERT(shift != UINT_MAX);
|
|
// reverse effect of shr
|
|
if (shift > 0)
|
|
shl(m_total_sz, w, shift, m_total_sz, w);
|
|
// display denominator as a power of 2
|
|
unsigned k = sizeof(unsigned)*8*m_frac_part_sz - shift;
|
|
out << "/2";
|
|
if (k > 1)
|
|
out << "^" << k;
|
|
}
|
|
}
|
|
|
|
void mpfx_manager::display_smt2(std::ostream & out, mpfx const & n) const {
|
|
if (is_neg(n))
|
|
out << "(- ";
|
|
unsigned * w = words(n);
|
|
unsigned sz = m_total_sz;
|
|
if (is_int(n)) {
|
|
w += m_frac_part_sz;
|
|
sz -= m_frac_part_sz;
|
|
}
|
|
else {
|
|
out << "(/ ";
|
|
}
|
|
sbuffer<char, 1024> str_buffer(11*sz, 0);
|
|
out << mp_decimal(w, sz, str_buffer.begin(), str_buffer.size(), 0);
|
|
if (!is_int(n)) {
|
|
out << " ";
|
|
unsigned * w = m_buffer0.c_ptr();
|
|
for (unsigned i = 0; i < m_frac_part_sz; i++)
|
|
w[i] = 0;
|
|
w[m_frac_part_sz] = 1;
|
|
sbuffer<char, 1024> str_buffer2(11*(m_frac_part_sz+1), 0);
|
|
out << mp_decimal(w, m_frac_part_sz+1, str_buffer2.begin(), str_buffer2.size(), 0);
|
|
out << ")";
|
|
}
|
|
if (is_neg(n))
|
|
out << ")";
|
|
}
|
|
|
|
void mpfx_manager::display_decimal(std::ostream & out, mpfx const & n, unsigned prec) const {
|
|
if (is_neg(n))
|
|
out << "-";
|
|
unsigned * w = words(n);
|
|
sbuffer<char, 1024> str_buffer(11*m_int_part_sz, 0);
|
|
out << mp_decimal(w + m_frac_part_sz, m_int_part_sz, str_buffer.begin(), str_buffer.size(), 0);
|
|
if (!is_int(n)) {
|
|
out << ".";
|
|
unsigned * frac = m_buffer0.c_ptr();
|
|
::copy(m_frac_part_sz, w, m_frac_part_sz, frac);
|
|
unsigned ten = 10;
|
|
unsigned * n_frac = m_buffer1.c_ptr();
|
|
bool frac_is_zero = false;
|
|
unsigned i = 0;
|
|
while (!frac_is_zero) {
|
|
if (i >= prec) {
|
|
out << "?";
|
|
return;
|
|
}
|
|
multiply(frac, m_frac_part_sz, &ten, 1, n_frac, 0);
|
|
frac_is_zero = ::is_zero(m_frac_part_sz, n_frac);
|
|
SASSERT(n_frac[m_frac_part_sz] <= 9);
|
|
if (!frac_is_zero || n_frac[m_frac_part_sz] != 0)
|
|
out << n_frac[m_frac_part_sz];
|
|
n_frac[m_frac_part_sz] = 0;
|
|
std::swap(frac, n_frac);
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string mpfx_manager::to_string(mpfx const & a) const {
|
|
std::ostringstream buffer;
|
|
display(buffer, a);
|
|
return buffer.str();
|
|
}
|
|
|
|
std::string mpfx_manager::to_rational_string(mpfx const & a) const {
|
|
return to_string(a);
|
|
}
|
|
|
|
bool mpfx_manager::check(mpfx const & a) const {
|
|
SASSERT(!is_zero(a) || a.m_sign == 0);
|
|
SASSERT(is_zero(a) == ::is_zero(m_total_sz, words(a)));
|
|
return true;
|
|
}
|
|
|
|
unsigned mpfx_manager::prev_power_of_two(mpfx const & a) {
|
|
if (!is_pos(a))
|
|
return 0;
|
|
return m_int_part_sz * sizeof(unsigned) * 8 - nlz(m_int_part_sz, words(a) + m_frac_part_sz) - 1;
|
|
}
|