z3-z3-4.13.0.src.util.mpq.cpp Maven / Gradle / Ivy
The newest version!
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
mpq.cpp
Abstract:
Author:
Leonardo de Moura (leonardo) 2010-06-21.
Revision History:
--*/
#include "util/mpq.h"
#include "util/warning.h"
#include "util/z3_exception.h"
template
mpq_manager::~mpq_manager() {
del(m_tmp1);
del(m_tmp2);
del(m_tmp3);
del(m_tmp4);
del(m_q_tmp1);
del(m_q_tmp2);
}
template
bool mpq_manager::rat_lt(mpq const & a, mpq const & b) {
mpz const & na = a.numerator();
mpz const & nb = b.numerator();
int sign_a = this->sign(na);
int sign_b = this->sign(nb);
if (sign_a < 0) {
if (sign_b >= 0) return true;
}
else if (sign_a == 0) {
if (sign_b > 0) return true;
SASSERT(sign_b <= 0); return false;
}
else {
SASSERT(sign_a > 0);
if (sign_b <= 0) return false;
}
SASSERT((sign_a > 0 && sign_b > 0) ||
(sign_a < 0 && sign_b < 0));
mpz const & da = a.denominator();
mpz const & db = b.denominator();
if (SYNCH) {
mpq tmp1;
mpq tmp2;
mul(na, db, tmp1);
mul(nb, da, tmp2);
bool r = lt(tmp1, tmp2);
del(tmp1);
del(tmp2);
return r;
}
else {
mul(na, db, m_q_tmp1);
mul(nb, da, m_q_tmp2);
return lt(m_q_tmp1, m_q_tmp2);
}
}
template
void mpq_manager::floor(mpq const & a, mpz & f) {
if (is_int(a)) {
set(f, a.m_num);
return;
}
bool is_neg_num = is_neg(a.m_num);
machine_div(a.m_num, a.m_den, f);
if (is_neg_num)
sub(f, this->mk_z(1), f);
}
template
void mpq_manager::ceil(mpq const & a, mpz & c) {
if (is_int(a)) {
set(c, a.m_num);
return;
}
bool is_pos_num = is_pos(a.m_num);
machine_div(a.m_num, a.m_den, c);
if (is_pos_num)
add(c, this->mk_z(1), c);
}
template
void mpq_manager::gcd(unsigned sz, mpq const * as, mpq & g) {
switch (sz) {
case 0:
reset(g);
return;
case 1:
set(g, as[0]);
abs(g);
return;
default:
break;
}
gcd(as[0], as[1], g);
for (unsigned i = 2; i < sz; i++) {
if (is_one(g))
return;
gcd(g, as[i], g);
}
}
template
std::string mpq_manager::to_string(mpq const & a) const {
if (is_int(a))
return to_string(a.m_num);
return to_string(a.m_num) + "/" + to_string(a.m_den);
}
template
void mpq_manager::display(std::ostream & out, mpq const & a) const {
if (is_int(a)) {
display(out, a.m_num);
}
else {
display(out, a.m_num);
out << "/";
display(out, a.m_den);
}
}
template
void mpq_manager::display_smt2(std::ostream & out, mpq const & a, bool decimal) const {
if (is_int(a)) {
display_smt2(out, a.m_num, decimal);
}
else {
out << "(/ ";
display_smt2(out, a.m_num, decimal);
out << " ";
display_smt2(out, a.m_den, decimal);
out << ")";
}
}
template
void mpq_manager::display_decimal(std::ostream & out, mpq const & a, unsigned prec, bool truncate) {
mpz n1, d1, v1;
get_numerator(a, n1);
get_denominator(a, d1);
if (is_neg(a)) {
out << "-";
neg(n1);
}
mpz ten(10);
div(n1, d1, v1);
display(out, v1);
rem(n1, d1, n1);
if (is_zero(n1))
goto end; // number is an integer
out << ".";
for (unsigned i = 0; i < prec; i++) {
mul(n1, ten, n1);
div(n1, d1, v1);
SASSERT(lt(v1, ten));
display(out, v1);
rem(n1, d1, n1);
if (is_zero(n1))
goto end; // number is precise
}
if (!truncate) out << "?";
end:
del(ten); del(n1); del(d1); del(v1);
}
template
void mpq_manager::set(mpq & a, char const * val) {
reset(a.m_num);
_scoped_numeral> _zten(*this);
_scoped_numeral> tmp(*this);
set(_zten, 10);
char const * str = val;
bool sign = false;
while (str[0] == ' ') ++str;
if (str[0] == '-')
sign = true;
while (str[0] && (str[0] != '/') && (str[0] != '.') && (str[0] != 'e') && (str[0] != 'E')) {
if ('0' <= str[0] && str[0] <= '9') {
SASSERT(str[0] - '0' <= 9);
mul(a.m_num, _zten, tmp);
add(tmp, this->mk_z(str[0] - '0'), a.m_num);
}
++str;
}
TRACE("mpq_set", tout << "[before] a: " << to_string(a) << "\n";);
if (str[0] == '/' || str[0] == '.' || str[0] == 'e' || str[0] == 'E') {
bool is_rat = str[0] == '/';
_scoped_numeral > tmp2(*this);
set(tmp2, 1);
bool has_den = false;
if (str[0] == '/' || str[0] == '.') {
has_den = true;
++str;
reset(a.m_den);
while (str[0] && (str[0] != 'e') && (str[0] != 'E')) {
if ('0' <= str[0] && str[0] <= '9') {
mul(a.m_den, _zten, tmp);
add(tmp, this->mk_z(str[0] - '0'), a.m_den);
if (!is_rat)
mul(tmp2, _zten, tmp2);
}
++str;
}
}
unsigned long long exp = 0;
bool exp_sign = false;
if (str[0] == 'e' || str[0] == 'E') {
if (is_rat)
throw default_exception("mixing rational/scientific notation");
++str;
if (str[0] == '-') {
exp_sign = true;
++str;
}
else if (str[0] == '+') {
exp_sign = false;
++str;
}
while (str[0]) {
if ('0' <= str[0] && str[0] <= '9') {
SASSERT(str[0] - '0' <= 9);
exp = (10*exp) + (str[0] - '0');
}
else if ('/' == str[0]) {
throw default_exception("mixing rational/scientific notation");
}
TRACE("mpq_set", tout << "[exp]: " << exp << ", str[0]: " << (str[0] - '0') << std::endl;);
++str;
}
}
if (!is_rat) {
// a <- a.m_num + a.m_den/tmp2
if (exp > static_cast(UINT_MAX))
throw default_exception("exponent is too big");
_scoped_numeral> b(*this);
if (has_den) {
set(b, a.m_den, tmp2);
set(a.m_den, 1);
add(a, b, a);
}
if (exp > 0) {
_scoped_numeral> _exp(*this);
_scoped_numeral> _qten(*this);
_qten = 10;
power(_qten, static_cast(exp), _exp);
TRACE("mpq_set", tout << "a: " << to_string(a) << ", exp_sign:" << exp_sign << ", exp: " << exp << " " << to_string(_exp) << std::endl;);
if (exp_sign)
div(a, _exp, a);
else
mul(a, _exp, a);
}
}
else {
// rational case
if (is_zero(a.m_den))
throw default_exception("division by zero");
}
}
else {
reset_denominator(a);
}
if (sign)
neg(a.m_num);
normalize(a);
}
template
void mpq_manager::power(mpq const & a, unsigned p, mpq & b) {
unsigned mask = 1;
mpq power;
set(power, a);
set(b, 1);
while (mask <= p) {
if (mask & p)
mul(b, power, b);
mul(power, power, power);
mask = mask << 1;
}
del(power);
}
template
double mpq_manager::get_double(mpq const & a) const {
double n;
double d;
n = get_double(a.m_num);
d = get_double(a.m_den);
SASSERT(d > 0.0);
return n/d;
}
template
bool mpq_manager::root(mpq const & a, unsigned n, mpq & r) {
return root(a.m_num, n, r.m_num) && root(a.m_den, n, r.m_den);
}
template
unsigned mpq_manager::prev_power_of_two(mpq const & a) {
_scoped_numeral > _tmp(*this);
floor(a, _tmp);
return prev_power_of_two(_tmp);
}
template
unsigned mpq_manager::next_power_of_two(mpq const & a) {
_scoped_numeral > _tmp(*this);
ceil(a, _tmp);
return next_power_of_two(_tmp);
}
template
template
void mpq_manager::lin_arith_op(mpq const& a, mpq const& b, mpq& c, mpz& g, mpz& tmp1, mpz& tmp2, mpz& tmp3) {
gcd(a.m_den, b.m_den, g);
if (is_one(g)) {
mul(a.m_num, b.m_den, tmp1);
mul(b.m_num, a.m_den, tmp2);
if (SUB) sub(tmp1, tmp2, c.m_num); else add(tmp1, tmp2, c.m_num);
mul(a.m_den, b.m_den, c.m_den);
}
else {
div(a.m_den, g, tmp3);
mul(tmp3, b.m_den, c.m_den);
mul(tmp3, b.m_num, tmp2);
div(b.m_den, g, tmp3);
mul(tmp3, a.m_num, tmp1);
if (SUB) sub(tmp1, tmp2, tmp3); else add(tmp1, tmp2, tmp3);
gcd(tmp3, g, tmp1);
if (is_one(tmp1)) {
set(c.m_num, tmp3);
}
else {
div(tmp3, tmp1, c.m_num);
div(c.m_den, tmp1, c.m_den);
}
}
}
template
void mpq_manager::rat_mul(mpq const & a, mpq const & b, mpq & c, mpz& g1, mpz& g2, mpz& tmp1, mpz& tmp2) {
#if 1
gcd(a.m_den, b.m_num, g1);
gcd(a.m_num, b.m_den, g2);
div(a.m_num, g2, tmp1);
div(b.m_num, g1, tmp2);
mul(tmp1, tmp2, c.m_num);
div(b.m_den, g2, tmp1);
div(a.m_den, g1, tmp2);
mul(tmp1, tmp2, c.m_den);
#else
mul(a.m_num, b.m_num, c.m_num);
mul(a.m_den, b.m_den, c.m_den);
normalize(c);
#endif
}
template
void mpq_manager::rat_mul(mpz const & a, mpq const & b, mpq & c) {
STRACE("rat_mpq", tout << "[mpq] " << to_string(a) << " * " << to_string(b) << " == ";);
mul(a, b.m_num, c.m_num);
set(c.m_den, b.m_den);
normalize(c);
STRACE("rat_mpq", tout << to_string(c) << "\n";);
}
template
void mpq_manager::rat_mul(mpq const & a, mpq const & b, mpq & c) {
STRACE("rat_mpq", tout << "[mpq] " << to_string(a) << " * " << to_string(b) << " == ";);
if (SYNCH) {
mpz g1, g2, tmp1, tmp2;
rat_mul(a, b, c, g1, g2, tmp1, tmp2);
del(g1);
del(g2);
del(tmp1);
del(tmp2);
}
else {
rat_mul(a, b, c, m_tmp1, m_tmp2, m_tmp3, m_tmp4);
}
STRACE("rat_mpq", tout << to_string(c) << "\n";);
}
template
void mpq_manager::rat_add(mpq const & a, mpq const & b, mpq & c) {
STRACE("rat_mpq", tout << "[mpq] " << to_string(a) << " + " << to_string(b) << " == ";);
if (SYNCH) {
mpz_stack tmp1, tmp2, tmp3, g;
lin_arith_op(a, b, c, g, tmp1, tmp2, tmp3);
del(tmp1);
del(tmp2);
del(tmp3);
del(g);
}
else {
lin_arith_op(a, b, c, m_tmp1, m_tmp2, m_tmp3, m_tmp4);
}
STRACE("rat_mpq", tout << to_string(c) << "\n";);
}
template
void mpq_manager::rat_sub(mpq const & a, mpq const & b, mpq & c) {
STRACE("rat_mpq", tout << "[mpq] " << to_string(a) << " - " << to_string(b) << " == ";);
if (SYNCH) {
mpz tmp1, tmp2, tmp3, g;
lin_arith_op(a, b, c, g, tmp1, tmp2, tmp3);
del(tmp1);
del(tmp2);
del(tmp3);
del(g);
}
else {
lin_arith_op(a, b, c, m_tmp1, m_tmp2, m_tmp3, m_tmp4);
}
STRACE("rat_mpq", tout << to_string(c) << "\n";);
}
#ifndef SINGLE_THREAD
template class mpq_manager;
#endif
template class mpq_manager;