#pragma once
#include "util/id_gen.h"
#include "util/util.h"
#include "util/vector.h"
#include "util/z3_exception.h"
#include "util/scoped_numeral.h"
#include "util/scoped_numeral_vector.h"
#include "util/mpn.h"
class mpfx_manager;
class mpfx {
friend class mpfx_manager;
unsigned m_sign:1;
unsigned m_sig_idx:31; public:
mpfx():
m_sign(0),
m_sig_idx(0) {
}
void swap(mpfx & other) noexcept {
unsigned sign = m_sign; m_sign = other.m_sign; other.m_sign = sign;
unsigned sig_idx = m_sig_idx; m_sig_idx = other.m_sig_idx; other.m_sig_idx = sig_idx;
}
};
inline void swap(mpfx & m1, mpfx & m2) noexcept { m1.swap(m2); }
class mpz;
class mpq;
template<bool SYNCH> class mpz_manager;
template<bool SYNCH> class mpq_manager;
#ifndef SINGLE_THREAD
typedef mpz_manager<true> synch_mpz_manager;
typedef mpq_manager<true> synch_mpq_manager;
#else
typedef mpz_manager<false> synch_mpz_manager;
typedef mpq_manager<false> synch_mpq_manager;
#endif
typedef mpz_manager<false> unsynch_mpz_manager;
typedef mpq_manager<false> unsynch_mpq_manager;
class mpfx_manager {
unsigned m_int_part_sz;
unsigned m_frac_part_sz;
unsigned m_total_sz; mutable unsigned_vector m_words; unsigned m_capacity; bool m_to_plus_inf; id_gen m_id_gen;
mutable unsigned_vector m_buffer0, m_buffer1, m_buffer2;
unsigned_vector m_tmp_digits;
mpfx m_one;
mpn_manager m_mpn_manager;
unsigned * words(mpfx const & n) const { return m_words.data() + (n.m_sig_idx * m_total_sz); }
unsigned sz(unsigned * ws) const;
void ensure_capacity(unsigned sig_idx) {
while (sig_idx >= m_capacity)
expand();
}
void expand();
void allocate_if_needed(mpfx & n) {
if (n.m_sig_idx == 0)
allocate(n);
}
void allocate(mpfx & n);
void set_epsilon(mpfx & n);
void add_sub(bool is_sub, mpfx const & a, mpfx const & b, mpfx & c);
template<bool SYNCH>
void set_core(mpfx & n, mpz_manager<SYNCH> & m, mpz const & v);
template<bool SYNCH>
void set_core(mpfx & n, mpq_manager<SYNCH> & m, mpq const & v);
template<bool SYNCH>
void to_mpz_core(mpfx const & n, mpz_manager<SYNCH> & m, mpz & t);
template<bool SYNCH>
void to_mpq_core(mpfx const & n, mpq_manager<SYNCH> & m, mpq & t);
public:
typedef mpfx numeral;
static bool precise() { return false; }
static bool field() { return true; }
class exception : public z3_exception {
char const * what() const noexcept override { return "multi-precision fixed point (mpfx) exception"; }
};
class overflow_exception : public exception {
char const * what() const noexcept override { return "multi-precision fixed point (mpfx) overflow"; }
};
class div0_exception : public exception {
char const * what() const noexcept override { return "multi-precision fixed point (mpfx) division by zero"; }
};
mpfx_manager(unsigned int_sz = 2, unsigned frac_sz = 1, unsigned initial_capacity = 1024);
~mpfx_manager();
void round_to_plus_inf() { m_to_plus_inf = true; }
void round_to_minus_inf() { m_to_plus_inf = false; }
void set_rounding(bool to_plus_inf) { m_to_plus_inf = to_plus_inf; }
bool rounding_to_plus_inf() const { return m_to_plus_inf; }
static bool sign(mpfx const & n) { return is_neg(n); }
void reset(mpfx & n);
bool is_int(mpfx const & n) const;
static bool is_zero(mpfx const & n) { return n.m_sig_idx == 0; }
static bool is_pos(mpfx const & n) { return n.m_sign == 0 && !is_zero(n); }
static bool is_neg(mpfx const & n) { return n.m_sign != 0; }
static bool is_nonpos(mpfx const & n) { return !is_pos(n); }
static bool is_nonneg(mpfx const & n) { return !is_neg(n); }
bool is_abs_one(mpfx const & n) const;
bool is_one(mpfx const & n) const { return is_pos(n) && is_abs_one(n); }
bool is_minus_one(mpfx const & n) const { return is_neg(n) && is_abs_one(n); }
bool is_int64(mpfx const & a) const;
bool is_uint64(mpfx const & a) const;
void del(mpfx & n);
static void neg(mpfx & a) { if (!is_zero(a)) a.m_sign = !a.m_sign; }
static void abs(mpfx & a) { a.m_sign = 0; }
static void swap(mpfx & a, mpfx & b) noexcept { a.swap(b); }
void add(mpfx const & a, mpfx const & b, mpfx & c);
void sub(mpfx const & a, mpfx const & b, mpfx & c);
void inc(mpfx & a) { add(a, m_one, a); }
void dec(mpfx & a) { sub(a, m_one, a); }
void mul(mpfx const & a, mpfx const & b, mpfx & c);
void div(mpfx const & a, mpfx const & b, mpfx & c);
void inv(mpfx & a) { div(m_one, a, a); }
void inv(mpfx const & a, mpfx & b) { set(b, a); inv(b); }
void div2k(mpfx & a, unsigned k);
void div2k(mpfx const & a, unsigned k, mpfx & b) { set(b, a); div2k(b, k); }
void div2(mpfx & a) { div2k(a, 1); }
void div2(mpfx const & a, mpfx & b) { div2k(a, 1, b); }
void power(mpfx const & a, unsigned k, mpfx & b);
bool is_power_of_two(mpfx const & a, unsigned & k) const;
bool is_power_of_two(mpfx const & a) const;
bool eq(mpfx const & a, mpfx const & b) const;
bool neq(mpfx const & a, mpfx const & b) const { return !eq(a, b); }
bool lt(mpfx const & a, mpfx const & b) const;
bool gt(mpfx const & a, mpfx const & b) const { return lt(b, a); }
bool le(mpfx const & a, mpfx const & b) const { return !lt(b, a); }
bool ge(mpfx const & a, mpfx const & b) const { return !lt(a, b); }
void set(mpfx & n, int v);
void set(mpfx & n, unsigned v);
void set(mpfx & n, int64_t v);
void set(mpfx & n, uint64_t v);
void set(mpfx & n, int num, unsigned den);
void set(mpfx & n, int64_t num, uint64_t den);
void set(mpfx & n, mpfx const & v);
void set(mpfx & n, unsynch_mpz_manager & m, mpz const & v);
void set(mpfx & n, unsynch_mpq_manager & m, mpq const & v);
#ifndef SINGLE_THREAD
void set(mpfx & n, synch_mpz_manager & m, mpz const & v);
void set(mpfx & n, synch_mpq_manager & m, mpq const & v);
#endif
void set_plus_epsilon(mpfx & n);
void set_minus_epsilon(mpfx & n);
void floor(mpfx & n);
void floor(mpfx const & n, mpfx & o) { set(o, n); floor(o); }
void ceil(mpfx & n);
void ceil(mpfx const & n, mpfx & o) { set(o, n); ceil(o); }
int64_t get_int64(mpfx const & n) const;
uint64_t get_uint64(mpfx const & n) const;
void to_mpz(mpfx const & n, unsynch_mpz_manager & m, mpz & t);
#ifndef SINGLE_THREAD
void to_mpz(mpfx const & n, synch_mpz_manager & m, mpz & t);
#endif
void to_mpq(mpfx const & n, unsynch_mpq_manager & m, mpq & t);
#ifndef SINGLE_THREAD
void to_mpq(mpfx const & n, synch_mpq_manager & m, mpq & t);
#endif
unsigned prev_power_of_two(mpfx const & a);
void display(std::ostream & out, mpfx const & n) const;
void display_pp(std::ostream & out, mpfx const & n) const { display(out, n); }
void display_smt2(std::ostream & out, mpfx const & n) const;
void display_decimal(std::ostream & out, mpfx const & n, unsigned prec = UINT_MAX) const;
void display_raw(std::ostream & out, mpfx const & n) const;
std::string to_string(mpfx const & a) const;
std::string to_rational_string(mpfx const & a) const;
bool check(mpfx const & a) const;
};
typedef _scoped_numeral<mpfx_manager> scoped_mpfx;
typedef _scoped_numeral_vector<mpfx_manager> scoped_mpfx_vector;