#pragma once
#include "util/manage_warnings.h"
#include "util/mpq.h"
#include "util/rational.h"
#include "util/vector.h"
class mpbq {
mpz m_num = 0;
unsigned m_k = 0; friend class mpbq_manager;
public:
mpbq() = default;
mpbq(int v):m_num(v), m_k(0) {}
mpbq(int v, unsigned k):m_num(v), m_k(k) {}
mpz const & numerator() const { return m_num; }
unsigned k() const { return m_k; }
void swap(mpbq & other) noexcept { m_num.swap(other.m_num); std::swap(m_k, other.m_k); }
};
inline void swap(mpbq & m1, mpbq & m2) noexcept { m1.swap(m2); }
typedef svector<mpbq> mpbq_vector;
class mpbq_manager {
unsynch_mpz_manager & m_manager;
mpz m_tmp;
mpz m_tmp2;
mpbq m_addmul_tmp;
mpz m_select_int_tmp1;
mpz m_select_int_tmp2;
mpz m_select_small_tmp;
mpbq m_select_small_tmp1;
mpbq m_select_small_tmp2;
mpz m_div_tmp1, m_div_tmp2, m_div_tmp3;
void normalize(mpbq & a);
bool select_integer(mpbq const & lower, mpbq const & upper, mpz & r);
bool select_integer(unsynch_mpq_manager & qm, mpq const & lower, mpbq const & upper, mpz & r);
bool select_integer(unsynch_mpq_manager & qm, mpbq const & lower, mpq const & upper, mpz & r);
bool select_integer(unsynch_mpq_manager & qm, mpq const & lower, mpq const & upper, mpz & r);
public:
static bool precise() { return true; }
static bool field() { return false; }
typedef mpbq numeral;
mpbq_manager(unsynch_mpz_manager & m);
~mpbq_manager();
static void swap(mpbq & a, mpbq & b) noexcept { a.swap(b); }
void del(mpbq & a) { m_manager.del(a.m_num); }
void reset(mpbq & a) { m_manager.reset(a.m_num); a.m_k = 0; }
void reset(mpbq_vector & v);
void set(mpbq & a, int n) { m_manager.set(a.m_num, n); a.m_k = 0; }
void set(mpbq & a, unsigned n) { m_manager.set(a.m_num, n); a.m_k = 0; }
void set(mpbq & a, int n, unsigned k) { m_manager.set(a.m_num, n); a.m_k = k; normalize(a); }
void set(mpbq & a, mpz const & n, unsigned k) { m_manager.set(a.m_num, n); a.m_k = k; normalize(a); }
void set(mpbq & a, mpz const & n) { m_manager.set(a.m_num, n); a.m_k = 0; }
void set(mpbq & a, mpbq const & b) { m_manager.set(a.m_num, b.m_num); a.m_k = b.m_k; }
void set(mpbq & a, int64_t n, unsigned k) { m_manager.set(a.m_num, n); a.m_k = k; normalize(a); }
bool is_int(mpbq const & a) const { return a.m_k == 0; }
void get_numerator(mpbq const & a, mpz & n) { m_manager.set(n, a.m_num); }
unsigned get_denominator_power(mpbq const & a) { return a.m_k; }
bool is_zero(mpbq const & a) const { return m_manager.is_zero(a.m_num); }
bool is_nonzero(mpbq const & a) const { return !is_zero(a); }
bool is_one(mpbq const & a) const { return a.m_k == 0 && m_manager.is_one(a.m_num); }
bool is_pos(mpbq const & a) const { return m_manager.is_pos(a.m_num); }
bool is_neg(mpbq const & a) const { return m_manager.is_neg(a.m_num); }
bool is_nonpos(mpbq const & a) const { return m_manager.is_nonpos(a.m_num); }
bool is_nonneg(mpbq const & a) const { return m_manager.is_nonneg(a.m_num); }
void add(mpbq const & a, mpbq const & b, mpbq & r);
void add(mpbq const & a, mpz const & b, mpbq & r);
void sub(mpbq const & a, mpbq const & b, mpbq & r);
void sub(mpbq const & a, mpz const & b, mpbq & r);
void mul(mpbq const & a, mpbq const & b, mpbq & r);
void mul(mpbq const & a, mpz const & b, mpbq & r);
void addmul(mpbq const & a, mpbq const & b, mpbq const & c, mpbq & r) {
mul(b, c, m_addmul_tmp);
add(a, m_addmul_tmp, r);
}
void addmul(mpbq const & a, mpz const & b, mpbq const & c, mpbq & r) {
mul(c, b, m_addmul_tmp);
add(a, m_addmul_tmp, r);
}
void neg(mpbq & a) { m_manager.neg(a.m_num); }
void div2(mpbq & a) { bool old_k_zero = (a.m_k == 0); a.m_k++; if (old_k_zero) normalize(a); }
void div2k(mpbq & a, unsigned k) { bool old_k_zero = (a.m_k == 0); a.m_k += k; if (old_k_zero) normalize(a); }
void mul2(mpbq & a);
void mul2k(mpbq & a, unsigned k);
void power(mpbq & a, unsigned k);
void power(mpbq const & a, unsigned k, mpbq & b) { set(b, a); power(b, k); }
bool root_lower(mpbq & a, unsigned n);
bool root_lower(mpbq const & a, unsigned n, mpbq & r) { set(r, a); return root_lower(r, n); }
bool root_upper(mpbq & a, unsigned n);
bool root_upper(mpbq const & a, unsigned n, mpbq & r) { set(r, a); return root_upper(r, n); }
bool eq(mpbq const & a, mpbq const & b) { return a.m_k == b.m_k && m_manager.eq(a.m_num, b.m_num); }
bool lt(mpbq const & a, mpbq const & b);
bool neq(mpbq const & a, mpbq const & b) { return !eq(a, b); }
bool gt(mpbq const & a, mpbq const & b) { return lt(b, a); }
bool ge(mpbq const & a, mpbq const & b) { return le(b, a); }
bool le(mpbq const & a, mpbq const & b) { return !gt(a, b); }
bool eq(mpbq const & a, mpq const & b);
bool lt(mpbq const & a, mpq const & b);
bool le(mpbq const & a, mpq const & b);
bool neq(mpbq const & a, mpq const & b) { return !eq(a, b); }
bool gt(mpbq const & a, mpq const & b) { return !le(a, b); }
bool ge(mpbq const & a, mpq const & b) { return !lt(a, b); }
bool eq(mpbq const & a, mpz const & b) { return m_manager.eq(a.m_num, b) && a.m_k == 0; }
bool lt(mpbq const & a, mpz const & b);
bool le(mpbq const & a, mpz const & b);
bool neq(mpbq const & a, mpz const & b) { return !eq(a, b); }
bool gt(mpbq const & a, mpz const & b) { return !le(a, b); }
bool ge(mpbq const & a, mpz const & b) { return !lt(a, b); }
int magnitude_lb(mpbq const & a);
int magnitude_ub(mpbq const & a);
bool lt_1div2k(mpbq const & a, unsigned k);
std::string to_string(mpbq const & a);
bool to_mpbq(mpq const & q, mpbq & bq);
void refine_upper(mpq const & q, mpbq & l, mpbq & u);
void refine_lower(mpq const & q, mpbq & l, mpbq & u);
template<typename mpz_manager>
void floor(mpz_manager & m, mpbq const & a, mpz & f) {
if (is_int(a)) {
m.set(f, a.m_num);
return;
}
bool is_neg_num = is_neg(a);
m.machine_div2k(a.m_num, a.m_k, f);
if (is_neg_num)
m.sub(f, mpz(1), f);
}
template<typename mpz_manager>
void ceil(mpz_manager & m, mpbq const & a, mpz & c) {
if (is_int(a)) {
m.set(c, a.m_num);
return;
}
bool is_pos_num = is_pos(a);
m.machine_div2k(a.m_num, a.m_k, c);
if (is_pos_num)
m.add(c, mpz(1), c);
}
bool select_small(mpbq const & lower, mpbq const & upper, mpbq & r);
void select_small_core(mpbq const & lower, mpbq const & upper, mpbq & r);
void select_small_core(unsynch_mpq_manager & qm, mpq const & lower, mpbq const & upper, mpbq & r);
void select_small_core(unsynch_mpq_manager & qm, mpbq const & lower, mpq const & upper, mpbq & r);
void select_small_core(unsynch_mpq_manager & qm, mpq const & lower, mpq const & upper, mpbq & r);
std::ostream& display(std::ostream & out, mpbq const & a);
std::ostream& display_pp(std::ostream & out, mpbq const & a);
std::ostream& display_decimal(std::ostream & out, mpbq const & a, unsigned prec = 8);
std::ostream& display_decimal(std::ostream & out, mpbq const & a, mpbq const & b, unsigned prec);
std::ostream& display_smt2(std::ostream & out, mpbq const & a, bool decimal);
void approx(mpbq & n, unsigned k, bool to_plus_inf);
void approx_div(mpbq const & a, mpbq const & b, mpbq & c, unsigned k=32, bool to_plus_inf=false);
};
template<typename mpq_manager>
void to_mpq(mpq_manager & m, mpbq const & source, mpq & target) {
mpq two(2);
m.power(two, source.k(), target);
m.inv(target);
m.mul(source.numerator(), target, target);
}
rational to_rational(mpbq const & m);
typedef _scoped_numeral<mpbq_manager> scoped_mpbq;
typedef _scoped_numeral_vector<mpbq_manager> scoped_mpbq_vector;
#define MPBQ_MK_COMPARISON_CORE(EXTERNAL, INTERNAL, TYPE) \
inline bool EXTERNAL(scoped_mpbq const & a, TYPE const & b) { \
mpbq_manager & m = a.m(); \
scoped_mpbq _b(m); \
m.set(_b, b); \
return m.INTERNAL(a, _b); \
}
#define MPBQ_MK_COMPARISON(EXTERNAL, INTERNAL) \
MPBQ_MK_COMPARISON_CORE(EXTERNAL, INTERNAL, int) \
MPBQ_MK_COMPARISON_CORE(EXTERNAL, INTERNAL, mpz) \
START_DISABLE_EXTRA_SEMI_WARNING;
MPBQ_MK_COMPARISON(operator==, eq);
MPBQ_MK_COMPARISON(operator!=, neq);
MPBQ_MK_COMPARISON(operator<, lt);
MPBQ_MK_COMPARISON(operator<=, le);
MPBQ_MK_COMPARISON(operator>, gt);
MPBQ_MK_COMPARISON(operator>=, ge);
END_DISABLE_WARNING;
#undef MPBQ_MK_COMPARISON
#undef MPBQ_MK_COMPARISON_CORE
#define MPBQ_MK_BINARY_CORE(EXTERNAL, INTERNAL, TYPE) \
inline scoped_mpbq EXTERNAL(scoped_mpbq const & a, TYPE const & b) { \
mpbq_manager & m = a.m(); \
scoped_mpbq _b(m); \
m.set(_b, b); \
scoped_mpbq r(m); \
m.INTERNAL(a, _b, r); \
return r; \
}
#define MPBQ_MK_BINARY(EXTERNAL, INTERNAL) \
MPBQ_MK_BINARY_CORE(EXTERNAL, INTERNAL, int) \
MPBQ_MK_BINARY_CORE(EXTERNAL, INTERNAL, mpz) \
MPBQ_MK_BINARY(operator+, add)
MPBQ_MK_BINARY(operator-, sub)
MPBQ_MK_BINARY(operator*, mul)
#undef MPBQ_MK_BINARY
#undef MPBQ_MK_BINARY_CORE