z3-z3-4.13.0.src.util.mpq.h Maven / Gradle / Ivy
The newest version!
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
mpq.h
Abstract:
Author:
Leonardo de Moura (leonardo) 2010-06-21.
Revision History:
--*/
#pragma once
#include "util/mpz.h"
#include "util/trace.h"
class mpq {
mpz m_num;
mpz m_den;
friend class mpq_manager;
friend class mpq_manager;
public:
mpq(int v):m_num(v), m_den(1) {}
mpq():m_den(1) {}
mpq(mpq &&) noexcept = default;
mpq & operator=(mpq&&) = default;
mpq & operator=(mpq const&) = delete;
mpz const & numerator() const { return m_num; }
mpz const & denominator() const { return m_den; }
};
template
class mpq_manager : public mpz_manager {
mpz m_tmp1;
mpz m_tmp2;
mpz m_tmp3;
mpz m_tmp4;
mpq m_q_tmp1;
mpq m_q_tmp2;
void reset_denominator(mpq & a) {
del(a.m_den);
a.m_den.set(1);
}
void normalize(mpq & a) {
if (SYNCH) {
mpz tmp;
gcd(a.m_num, a.m_den, tmp);
if (is_one(tmp)) {
del(tmp);
return;
}
div(a.m_num, tmp, a.m_num);
div(a.m_den, tmp, a.m_den);
del(tmp);
}
else {
gcd(a.m_num, a.m_den, m_tmp1);
if (is_one(m_tmp1))
return;
div(a.m_num, m_tmp1, a.m_num);
div(a.m_den, m_tmp1, a.m_den);
}
}
void rat_add(mpq const & a, mpq const & b, mpq & c);
void rat_add(mpq const & a, mpz const & b, mpq & c) {
STRACE("rat_mpq", tout << "[mpq] " << to_string(a) << " + " << to_string(b) << " == ";);
if (SYNCH) {
mpz tmp1;
mul(b, a.m_den, tmp1);
set(c.m_den, a.m_den);
add(a.m_num, tmp1, c.m_num);
normalize(c);
del(tmp1);
}
else {
mul(b, a.m_den, m_tmp1);
set(c.m_den, a.m_den);
add(a.m_num, m_tmp1, c.m_num);
normalize(c);
}
STRACE("rat_mpq", tout << to_string(c) << "\n";);
}
void rat_sub(mpq const & a, mpq const & b, mpq & c);
void rat_mul(mpq const & a, mpq const & b, mpq & c);
void rat_mul(mpz const & a, mpq const & b, mpq & c);
bool rat_lt(mpq const & a, mpq const & b);
template
void lin_arith_op(mpq const& a, mpq const& b, mpq& c, mpz& g, mpz& tmp1, mpz& tmp2, mpz& tmp3);
void rat_mul(mpq const & a, mpq const & b, mpq & c, mpz& g1, mpz& g2, mpz& tmp1, mpz& tmp2);
public:
typedef mpq numeral;
typedef mpq rational;
typedef mpz integer;
static bool precise() { return true; }
static bool field() { return true; }
mpq_manager() = default;
~mpq_manager();
void reset(mpz & a) { mpz_manager::reset(a); }
void reset(mpq & a) {
reset(a.m_num);
reset_denominator(a);
}
static bool is_small(mpz const & a) { return mpz_manager::is_small(a); }
static bool is_small(mpq const & a) { return is_small(a.m_num) && is_small(a.m_den); }
static mpq mk_q(int v) { return mpq(v); }
mpq mk_q(int n, int d) { mpq r; set(r, n, d); return r; }
void del(mpz & a) { mpz_manager::del(a); }
void del(mpq & a) {
del(a.m_num);
del(a.m_den);
}
static void del(mpq_manager* m, mpq & a) {
mpz_manager::del(m, a.m_num);
mpz_manager::del(m, a.m_den);
}
void get_numerator(mpq const & a, mpz & n) { set(n, a.m_num); }
void get_denominator(mpq const & a, mpz & d) { set(d, a.m_den); }
void get_numerator(mpq const & a, mpq & n) { get_numerator(a, n.m_num); reset_denominator(n); }
void get_denominator(mpq const & a, mpq & d) { get_denominator(a, d.m_num); reset_denominator(d); }
void neg(mpz & a) { mpz_manager::neg(a); }
void neg(mpq & a) { mpz_manager::neg(a.m_num); }
void abs(mpz & a) { mpz_manager::abs(a); }
void abs(mpq & a) { mpz_manager::abs(a.m_num); }
static int sign(mpz const & a) { return mpz_manager::sign(a); }
static int sign(mpq const & a) { return mpz_manager::sign(a.m_num); }
static bool is_pos(mpz const & a) { return mpz_manager::is_pos(a); }
static bool is_neg(mpz const & a) { return mpz_manager::is_neg(a); }
static bool is_zero(mpz const & a) { return mpz_manager::is_zero(a); }
static bool is_nonpos(mpz const & a) { return mpz_manager::is_nonpos(a); }
static bool is_nonneg(mpz const & a) { return mpz_manager::is_nonneg(a); }
static bool is_pos(mpq const & a) { return is_pos(a.m_num); }
static bool is_neg(mpq const & a) { return is_neg(a.m_num); }
static bool is_zero(mpq const & a) { return is_zero(a.m_num); }
static bool is_nonpos(mpq const & a) { return is_nonpos(a.m_num); }
static bool is_nonneg(mpq const & a) { return is_nonneg(a.m_num); }
static bool is_one(mpz const & a) { return mpz_manager::is_one(a); }
static bool is_one(mpq const & a) { return is_one(a.m_num) && is_one(a.m_den); }
static bool is_minus_one(mpz const & a) { return mpz_manager::is_minus_one(a); }
static bool is_minus_one(mpq const & a) { return is_minus_one(a.m_num) && is_one(a.m_den); }
void floor(mpq const & a, mpz & f);
void floor(mpq const & a, mpq & f) {
floor(a, f.m_num);
reset_denominator(f);
}
void ceil(mpq const & a, mpz & f);
void ceil(mpq const & a, mpq & f) {
ceil(a, f.m_num);
reset_denominator(f);
}
static bool is_int(mpq const & a) { return is_one(a.m_den); }
std::string to_string(mpq const & a) const;
std::string to_rational_string(numeral const & a) { return to_string(a); }
std::string to_string(mpz const & a) const { return mpz_manager::to_string(a); }
void display(std::ostream & out, mpz const & a) const { return mpz_manager::display(out, a); }
void display(std::ostream & out, mpq const & a) const;
void display_pp(std::ostream & out, mpq const & a) const { display(out, a); }
void display_smt2(std::ostream & out, mpz const & a, bool decimal) const { return mpz_manager::display_smt2(out, a, decimal); }
void display_smt2(std::ostream & out, mpq const & a, bool decimal) const;
void display_decimal(std::ostream & out, mpq const & a, unsigned prec, bool truncate = false);
void add(mpz const & a, mpz const & b, mpz & c) { mpz_manager::add(a, b, c); }
void add(mpq const & a, mpq const & b, mpq & c) {
STRACE("mpq", tout << "[mpq] " << to_string(a) << " + " << to_string(b) << " == ";);
if (is_zero(b)) {
set(c, a);
}
else if (is_zero(a)) {
set(c, b);
}
else if (is_int(a) && is_int(b)) {
mpz_manager::add(a.m_num, b.m_num, c.m_num);
reset_denominator(c);
}
else {
rat_add(a, b, c);
}
STRACE("mpq", tout << to_string(c) << "\n";);
}
void add(mpq const & a, mpz const & b, mpq & c) {
STRACE("mpq", tout << "[mpq] " << to_string(a) << " + " << to_string(b) << " == ";);
if (is_zero(b)) {
set(c, a);
}
else if (is_zero(a)) {
set(c, b);
}
else if (is_int(a)) {
mpz_manager::add(a.m_num, b, c.m_num);
reset_denominator(c);
}
else {
rat_add(a, b, c);
}
STRACE("mpq", tout << to_string(c) << "\n";);
}
void sub(mpz const & a, mpz const & b, mpz & c) { mpz_manager::sub(a, b, c); }
void sub(mpq const & a, mpq const & b, mpq & c) {
STRACE("mpq", tout << "[mpq] " << to_string(a) << " - " << to_string(b) << " == ";);
if (is_int(a) && is_int(b)) {
mpz_manager::sub(a.m_num, b.m_num, c.m_num);
reset_denominator(c);
}
else
rat_sub(a, b, c);
STRACE("mpq", tout << to_string(c) << "\n";);
}
void inc(mpz & a) { mpz_manager::inc(a); }
void dec(mpz & a) { mpz_manager::dec(a); }
void inc(mpq & a) { add(a, mpz(1), a); }
void dec(mpq & a) { add(a, mpz(-1), a); }
void mul(mpz const & a, mpz const & b, mpz & c) { mpz_manager::mul(a, b, c); }
void mul(mpz const & a, mpz const & b, mpq & c) {
mpz_manager::mul(a, b, c.m_num);
reset_denominator(c);
}
void mul(mpq const & a, mpq const & b, mpq & c) {
STRACE("mpq", tout << "[mpq] " << to_string(a) << " * " << to_string(b) << " == ";);
if (is_int(a) && is_int(b)) {
mpz_manager::mul(a.m_num, b.m_num, c.m_num);
reset_denominator(c);
}
else
rat_mul(a, b, c);
STRACE("mpq", tout << to_string(c) << "\n";);
}
void mul(mpz const & a, mpq const & b, mpq & c) {
STRACE("mpq", tout << "[mpq] " << to_string(a) << " * " << to_string(b) << " == ";);
if (is_int(b)) {
mpz_manager::mul(a, b.m_num, c.m_num);
reset_denominator(c);
}
else
rat_mul(a, b, c);
STRACE("mpq", tout << to_string(c) << "\n";);
}
void addmul(mpz const & a, mpz const & b, mpz const & c, mpz & d) {
return mpz_manager::addmul(a, b, c, d);
}
void submul(mpz const & a, mpz const & b, mpz const & c, mpz & d) {
return mpz_manager::submul(a, b, c, d);
}
// d <- a + b*c
void addmul(mpq const & a, mpq const & b, mpq const & c, mpq & d) {
if (is_one(b)) {
add(a, c, d);
}
else if (is_minus_one(b)) {
sub(a, c, d);
}
else if (is_zero(b) || is_zero(c)) {
set(d, a);
}
else {
if (SYNCH) {
mpq tmp;
mul(b,c,tmp);
add(a,tmp,d);
del(tmp);
}
else {
mul(b, c, m_q_tmp1);
add(a, m_q_tmp1, d);
}
}
}
// d <- a + b*c
void addmul(mpq const & a, mpz const & b, mpq const & c, mpq & d) {
if (is_one(b)) {
add(a, c, d);
}
else if (is_minus_one(b)) {
sub(a, c, d);
}
else if (is_zero(b) || is_zero(c)) {
set(d, a);
}
else {
if (SYNCH) {
mpq tmp;
mul(b,c,tmp);
add(a,tmp,d);
del(tmp);
}
else {
mul(b,c, m_q_tmp1);
add(a, m_q_tmp1, d);
}
}
}
// d <- a - b*c
void submul(mpq const & a, mpq const & b, mpq const & c, mpq & d) {
if (is_one(b)) {
sub(a, c, d);
}
else if (is_minus_one(b)) {
add(a, c, d);
}
else {
if (SYNCH) {
mpq tmp;
mul(b,c,tmp);
sub(a,tmp,d);
del(tmp);
}
else {
mul(b,c, m_q_tmp1);
sub(a, m_q_tmp1, d);
}
}
}
// d <- a - b*c
void submul(mpq const & a, mpz const & b, mpq const & c, mpq & d) {
if (is_one(b)) {
sub(a, c, d);
}
else if (is_minus_one(b)) {
add(a, c, d);
}
else {
if (SYNCH) {
mpq tmp;
mul(b,c,tmp);
sub(a,tmp,d);
del(tmp);
}
else {
mul(b,c, m_q_tmp1);
sub(a, m_q_tmp1, d);
}
}
}
void inv(mpq & a) {
SASSERT(!is_zero(a));
if (is_neg(a)) {
neg(a.m_num);
neg(a.m_den);
}
mpz_manager::swap(a.m_num, a.m_den);
}
void inv(mpq const & a, mpq & b) {
set(b, a);
inv(b);
}
void div(mpq const & a, mpq const & b, mpq & c) {
STRACE("mpq", tout << "[mpq] " << to_string(a) << " / " << to_string(b) << " == ";);
if (is_zero(a) || is_one(b)) {
set(c, a);
return;
}
if (&b == &c) {
mpz tmp; // it is not safe to use c.m_num at this point.
mul(a.m_num, b.m_den, tmp);
mul(a.m_den, b.m_num, c.m_den);
set(c.m_num, tmp);
del(tmp);
}
else {
mul(a.m_num, b.m_den, c.m_num);
mul(a.m_den, b.m_num, c.m_den);
}
if (mpz_manager::is_neg(c.m_den)) {
neg(c.m_num);
neg(c.m_den);
}
normalize(c);
STRACE("mpq", tout << to_string(c) << "\n";);
}
void div(mpq const & a, mpz const & b, mpq & c) {
STRACE("mpq", tout << "[mpq] " << to_string(a) << " / " << to_string(b) << " == ";);
if (is_zero(a) || is_one(b)) {
set(c, a);
return;
}
set(c.m_num, a.m_num);
mul(a.m_den, b, c.m_den);
if (mpz_manager::is_neg(b)) {
neg(c.m_num);
neg(c.m_den);
}
normalize(c);
STRACE("mpq", tout << to_string(c) << "\n";);
}
void acc_div(mpq & a, mpz const & b) {
STRACE("mpq", tout << "[mpq] " << to_string(a) << " / " << to_string(b) << " == ";);
mul(a.m_den, b, a.m_den);
if (mpz_manager::is_neg(b)) {
neg(a.m_num);
neg(a.m_den);
}
normalize(a);
STRACE("mpq", tout << to_string(a) << "\n";);
}
void machine_div(mpz const & a, mpz const & b, mpz & c) { mpz_manager::machine_div(a, b, c); }
void machine_div_rem(mpz const & a, mpz const & b, mpz & c, mpz & d) { mpz_manager::machine_div_rem(a, b, c, d); }
void machine_div2k(mpz const & a, unsigned k, mpz & c) { mpz_manager::machine_div2k(a, k, c); }
void div(mpz const & a, mpz const & b, mpz & c) { mpz_manager::div(a, b, c); }
void rat_div(mpz const & a, mpz const & b, mpq & c) {
set(c.m_num, a);
set(c.m_den, b);
normalize(c);
}
void machine_idiv(mpq const & a, mpq const & b, mpq & c) {
SASSERT(is_int(a) && is_int(b));
machine_div(a.m_num, b.m_num, c.m_num);
reset_denominator(c);
}
void machine_idiv_rem(mpq const & a, mpq const & b, mpq & c, mpq & d) {
SASSERT(is_int(a) && is_int(b));
machine_div_rem(a.m_num, b.m_num, c.m_num, d.m_num);
reset_denominator(c);
reset_denominator(d);
}
void machine_idiv(mpq const & a, mpq const & b, mpz & c) {
SASSERT(is_int(a) && is_int(b));
machine_div(a.m_num, b.m_num, c);
}
void machine_idiv2k(mpq const & a, unsigned k, mpq & c) {
SASSERT(is_int(a));
machine_div2k(a.m_num, k, c.m_num);
reset_denominator(c);
}
void idiv(mpq const & a, mpq const & b, mpq & c) {
SASSERT(is_int(a) && is_int(b));
div(a.m_num, b.m_num, c.m_num);
reset_denominator(c);
}
void idiv(mpq const & a, mpq const & b, mpz & c) {
SASSERT(is_int(a) && is_int(b));
div(a.m_num, b.m_num, c);
}
void rem(mpz const & a, mpz const & b, mpz & c) { mpz_manager::rem(a, b, c); }
void rem(mpq const & a, mpq const & b, mpq & c) {
SASSERT(is_int(a) && is_int(b));
rem(a.m_num, b.m_num, c.m_num);
reset_denominator(c);
}
void rem(mpq const & a, mpq const & b, mpz & c) {
SASSERT(is_int(a) && is_int(b));
rem(a.m_num, b.m_num, c);
}
void mod(mpz const & a, mpz const & b, mpz & c) { mpz_manager::mod(a, b, c); }
void mod(mpq const & a, mpq const & b, mpq & c) {
SASSERT(is_int(a) && is_int(b));
mod(a.m_num, b.m_num, c.m_num);
reset_denominator(c);
}
void mod(mpq const & a, mpq const & b, mpz & c) {
SASSERT(is_int(a) && is_int(b));
mod(a.m_num, b.m_num, c);
}
static unsigned hash(mpz const & a) { return mpz_manager::hash(a); }
static unsigned hash(mpq const & a) { return hash(a.m_num) + 3*hash(a.m_den); }
bool eq(mpz const & a, mpz const & b) { return mpz_manager::eq(a, b); }
bool eq(mpq const & a, mpq const & b) {
return eq(a.m_num, b.m_num) && eq(a.m_den, b.m_den);
}
bool lt(mpz const & a, mpz const & b) { return mpz_manager::lt(a, b); }
bool lt(mpq const & a, mpq const & b) {
if (is_int(a) && is_int(b))
return lt(a.m_num, b.m_num);
else
return rat_lt(a, b);
}
bool neq(mpz const & a, mpz const & b) { return mpz_manager::neq(a, b); }
bool gt(mpz const & a, mpz const & b) { return mpz_manager::gt(a, b); }
bool ge(mpz const & a, mpz const & b) { return mpz_manager::ge(a, b); }
bool le(mpz const & a, mpz const & b) { return mpz_manager::le(a, b); }
bool neq(mpq const & a, mpq const & b) { return !eq(a, b); }
bool gt(mpq const & a, mpq const & b) { return lt(b, a); }
bool ge(mpq const & a, mpq const & b) { return !lt(a, b); }
bool le(mpq const & a, mpq const & b) { return !lt(b, a); }
void gcd(mpz const & a, mpz const & b, mpz & c) { mpz_manager::gcd(a, b, c); }
void gcd(unsigned sz, mpz const * as, mpz & g) { mpz_manager::gcd(sz, as, g); }
void gcd(unsigned sz, mpq const * as, mpq & g);
void gcd(mpq const & a, mpq const & b, mpq & c) {
SASSERT(is_int(a) && is_int(b));
gcd(a.m_num, b.m_num, c.m_num);
reset_denominator(c);
}
void gcd(mpz const & r1, mpz const & r2, mpz & a, mpz & b, mpz & g) { mpz_manager::gcd(r1, r2, a, b, g); }
void gcd(mpq const & r1, mpq const & r2, mpq & a, mpq & b, mpq & g) {
SASSERT(is_int(r1) && is_int(r2));
reset_denominator(a);
reset_denominator(b);
reset_denominator(g);
gcd(r1.m_num, r2.m_num, a.m_num, b.m_num, g.m_num);
}
void lcm(mpz const & a, mpz const & b, mpz & c) { mpz_manager::lcm(a, b, c); }
void lcm(mpq const & a, mpq const & b, mpq & c) {
SASSERT(is_int(a) && is_int(b));
lcm(a.m_num, b.m_num, c.m_num);
reset_denominator(c);
}
bool divides(mpz const & a, mpz const & b) { return mpz_manager::divides(a, b); }
bool divides(mpq const & a, mpq const & b) {
SASSERT(is_int(a) && is_int(b));
return divides(a.m_num, b.m_num);
}
void bitwise_or(mpz const & a, mpz const & b, mpz & c) { return mpz_manager::bitwise_or(a, b, c); }
void bitwise_or(mpq const & a, mpq const & b, mpq & c) {
SASSERT(is_int(a) && is_int(b));
bitwise_or(a.m_num, b.m_num, c.m_num);
reset_denominator(c);
}
void bitwise_and(mpz const & a, mpz const & b, mpz & c) { return mpz_manager::bitwise_and(a, b, c); }
void bitwise_and(mpq const & a, mpq const & b, mpq & c) {
SASSERT(is_int(a) && is_int(b));
bitwise_and(a.m_num, b.m_num, c.m_num);
reset_denominator(c);
}
void bitwise_xor(mpz const & a, mpz const & b, mpz & c) { return mpz_manager::bitwise_xor(a, b, c); }
void bitwise_xor(mpq const & a, mpq const & b, mpq & c) {
SASSERT(is_int(a) && is_int(b));
bitwise_xor(a.m_num, b.m_num, c.m_num);
reset_denominator(c);
}
void bitwise_not(unsigned sz, mpz const & a, mpz & c) { return mpz_manager::bitwise_not(sz, a, c); }
void bitwise_not(unsigned sz, mpq const & a, mpq & c) {
SASSERT(is_int(a));
bitwise_not(sz, a.m_num, c.m_num);
reset_denominator(c);
}
void set(mpz & target, mpz const & source) { mpz_manager::set(target, source); }
void set(mpq & target, mpq const & source) {
set(target.m_num, source.m_num);
set(target.m_den, source.m_den);
}
void set(mpz & a, int val) { mpz_manager::set(a, val); }
void set(mpq & a, int val) {
set(a.m_num, val);
reset_denominator(a);
}
void set(mpq & a, int n, int d) {
SASSERT(d != 0);
if (d < 0) {
SASSERT(d != INT_MIN);
SASSERT(n != INT_MIN);
n = -n;
d = -d;
}
set(a.m_num, n);
set(a.m_den, d);
normalize(a);
}
void set(mpq & a, int64_t n, uint64_t d) {
SASSERT(d != 0);
set(a.m_num, n);
set(a.m_den, d);
normalize(a);
}
void set(mpq & a, mpz const & n, mpz const & d) {
if (is_neg(d)) {
set(a.m_num, n);
set(a.m_den, d);
neg(a.m_num);
neg(a.m_den);
}
else {
set(a.m_num, n);
set(a.m_den, d);
}
normalize(a);
}
void set(mpz & a, unsigned val) { mpz_manager::set(a, val); }
void set(mpq & a, unsigned val) {
set(a.m_num, val);
reset_denominator(a);
}
void set(mpz & a, char const * val) { mpz_manager::set(a, val); }
void set(mpq & a, char const * val);
void set(mpz & a, int64_t val) { mpz_manager::set(a, val); }
void set(mpq & a, int64_t val) {
set(a.m_num, val);
reset_denominator(a);
}
void set(mpz & a, uint64_t val) { mpz_manager::set(a, val); }
void set(mpq & a, uint64_t val) {
set(a.m_num, val);
reset_denominator(a);
}
void set(mpq & a, mpz const & val) {
mpz_manager::set(a.m_num, val);
reset_denominator(a);
}
void set(mpz & a, unsigned sz, digit_t const * digits) {
mpz_manager::set_digits(a, sz, digits);
}
void set(mpq & a, unsigned sz, digit_t const * digits) {
mpz_manager::set_digits(a.m_num, sz, digits);
reset_denominator(a);
}
mpq dup(const mpq & source) {
mpq temp;
set(temp, source);
return temp;
}
mpz dup(const mpz & source) {
mpz temp;
set(temp, source);
return temp;
}
void swap(mpz & a, mpz & b) noexcept { mpz_manager::swap(a, b); }
void swap(mpq & a, mpq & b) noexcept {
swap(a.m_num, b.m_num);
swap(a.m_den, b.m_den);
}
void swap_numerator(mpz & a, mpq & b) {
swap(a, b.m_num);
}
bool is_uint64(mpz const & a) const { return mpz_manager::is_uint64(a); }
bool is_int64(mpz const & a) const { return mpz_manager::is_int64(a); }
uint64_t get_uint64(mpz const & a) const { return mpz_manager::get_uint64(a); }
int64_t get_int64(mpz const & a) const { return mpz_manager::get_int64(a); }
bool is_uint64(mpq const & a) const { return is_int(a) && is_uint64(a.m_num); }
bool is_int64(mpq const & a) const { return is_int(a) && is_int64(a.m_num); }
uint64_t get_uint64(mpq const & a) const { SASSERT(is_uint64(a)); return get_uint64(a.m_num); }
int64_t get_int64(mpq const & a) const { SASSERT(is_int64(a)); return get_int64(a.m_num); }
double get_double(mpz const & a) const { return mpz_manager::get_double(a); }
double get_double(mpq const & a) const;
void power(mpz const & a, unsigned p, mpz & b) { mpz_manager::power(a, p, b); }
void power(mpq const & a, unsigned p, mpq & b);
bool is_power_of_two(mpz const & a, unsigned & shift) { return mpz_manager::is_power_of_two(a, shift); }
bool is_power_of_two(mpq const & a, unsigned & shift) { return is_int(a) && is_power_of_two(a.m_num, shift); }
unsigned bitsize(mpz const & a) { return mpz_manager::bitsize(a); }
unsigned bitsize(mpq const & a) { return is_int(a) ? bitsize(a.m_num) : bitsize(a.m_num) + bitsize(a.m_den); }
unsigned storage_size(mpz const & a) { return mpz_manager::size_info(a); }
unsigned storage_size(mpq const & a) { return mpz_manager::size_info(a.m_num) + mpz_manager::size_info(a.m_den); }
bool get_bit(mpq const& a, unsigned index) { SASSERT(is_int(a) && !is_neg(a)); return mpz_manager::get_bit(a.m_num, index); }
/**
\brief Return true if the number is a perfect square, and
store the square root in 'root'.
If the number n is positive and the result is false, then
root will contain the smallest integer r such that r*r > n.
*/
bool is_perfect_square(mpz const & a, mpz & r) { return mpz_manager::is_perfect_square(a, r); }
/**
\brief Return true if the numerator and denominators are perfect squares.
Store the square root in root.
If the result is false, then the value of root should be ignored.
*/
bool is_perfect_square(mpq const & a, mpq & r) {
if (is_int(a)) {
reset_denominator(r);
return is_perfect_square(a.m_num, r.m_num);
}
if (is_perfect_square(a.m_num, r.m_num) && is_perfect_square(a.m_den, r.m_den)) {
normalize(r);
return true;
}
return false;
}
bool root(mpz & a, unsigned n) { return mpz_manager::root(a, n); }
bool root(mpz const & a, unsigned n, mpz & r) { return mpz_manager::root(a, n, r); }
/**
\brief Return true if n-th root of a is rational, and store result in r.
*/
bool root(mpq const & a, unsigned n, mpq & r);
/**
\brief Return the biggest k s.t. 2^k <= a.
\remark Return 0 if a is not positive.
*/
unsigned prev_power_of_two(mpz const & a) { return mpz_manager::prev_power_of_two(a); }
unsigned prev_power_of_two(mpq const & a);
/**
\brief Return the smallest k s.t. a <= 2^k.
\remark Return 0 if a is not positive.
*/
unsigned next_power_of_two(mpz const & a) { return mpz_manager::next_power_of_two(a); }
unsigned next_power_of_two(mpq const & a);
bool is_int_perfect_square(mpq const & a, mpq & r) {
SASSERT(is_int(a));
reset_denominator(r);
return is_perfect_square(a.m_num, r.m_num);
}
bool is_even(mpz const & a) { return mpz_manager::is_even(a); }
public:
bool is_even(mpq const & a) { return is_int(a) && is_even(a.m_num); }
};
#ifndef SINGLE_THREAD
typedef mpq_manager synch_mpq_manager;
#else
typedef mpq_manager synch_mpq_manager;
#endif
typedef mpq_manager unsynch_mpq_manager;
typedef _scoped_numeral scoped_mpq;
typedef _scoped_numeral scoped_synch_mpq;
typedef _scoped_numeral_vector scoped_mpq_vector;