mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 09:35:32 +00:00
Merge branch 'master' of https://github.com/Z3Prover/z3
This commit is contained in:
commit
99314b7252
9 changed files with 363 additions and 144 deletions
|
@ -1066,15 +1066,14 @@ extern "C" {
|
|||
case OP_BV2INT: return Z3_OP_BV2INT;
|
||||
case OP_CARRY: return Z3_OP_CARRY;
|
||||
case OP_XOR3: return Z3_OP_XOR3;
|
||||
case OP_BSMUL_NO_OVFL:
|
||||
case OP_BUMUL_NO_OVFL:
|
||||
case OP_BSMUL_NO_UDFL:
|
||||
case OP_BSDIV_I:
|
||||
case OP_BUDIV_I:
|
||||
case OP_BSREM_I:
|
||||
case OP_BUREM_I:
|
||||
case OP_BSMOD_I:
|
||||
return Z3_OP_UNINTERPRETED;
|
||||
case OP_BSMUL_NO_OVFL: return Z3_OP_BSMUL_NO_OVFL;
|
||||
case OP_BUMUL_NO_OVFL: return Z3_OP_BUMUL_NO_OVFL;
|
||||
case OP_BSMUL_NO_UDFL: return Z3_OP_BSMUL_NO_UDFL;
|
||||
case OP_BSDIV_I: return Z3_OP_BSDIV_I;
|
||||
case OP_BUDIV_I: return Z3_OP_BUDIV_I;
|
||||
case OP_BSREM_I: return Z3_OP_BSREM_I;
|
||||
case OP_BUREM_I: return Z3_OP_BUREM_I;
|
||||
case OP_BSMOD_I: return Z3_OP_BSMOD_I;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return Z3_OP_UNINTERPRETED;
|
||||
|
|
|
@ -1060,6 +1060,15 @@ typedef enum {
|
|||
Z3_OP_CARRY,
|
||||
Z3_OP_XOR3,
|
||||
|
||||
Z3_OP_BSMUL_NO_OVFL,
|
||||
Z3_OP_BUMUL_NO_OVFL,
|
||||
Z3_OP_BSMUL_NO_UDFL,
|
||||
Z3_OP_BSDIV_I,
|
||||
Z3_OP_BUDIV_I,
|
||||
Z3_OP_BSREM_I,
|
||||
Z3_OP_BUREM_I,
|
||||
Z3_OP_BSMOD_I,
|
||||
|
||||
// Proofs
|
||||
Z3_OP_PR_UNDEF = 0x500,
|
||||
Z3_OP_PR_TRUE,
|
||||
|
|
|
@ -2235,14 +2235,17 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args
|
|||
SASSERT(is_well_sorted(m, result));
|
||||
}
|
||||
|
||||
|
||||
void fpa2bv_converter::mk_to_fp_float(func_decl * f, sort * s, expr * rm, expr * x, expr_ref & result) {
|
||||
SASSERT(is_app_of(rm, m_util.get_family_id(), OP_FPA_INTERNAL_RM));
|
||||
mk_to_fp_float(s, to_app(rm)->get_arg(0), x, result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_to_fp_float(sort * to_srt, expr * rm, expr * x, expr_ref & result) {
|
||||
unsigned from_sbits = m_util.get_sbits(m.get_sort(x));
|
||||
unsigned from_ebits = m_util.get_ebits(m.get_sort(x));
|
||||
unsigned to_sbits = m_util.get_sbits(s);
|
||||
unsigned to_ebits = m_util.get_ebits(s);
|
||||
|
||||
SASSERT(is_app_of(rm, m_util.get_family_id(), OP_FPA_INTERNAL_RM));
|
||||
expr * bv_rm = to_app(rm)->get_arg(0);
|
||||
unsigned to_sbits = m_util.get_sbits(to_srt);
|
||||
unsigned to_ebits = m_util.get_ebits(to_srt);
|
||||
|
||||
if (from_sbits == to_sbits && from_ebits == to_ebits)
|
||||
result = x;
|
||||
|
@ -2253,20 +2256,20 @@ void fpa2bv_converter::mk_to_fp_float(func_decl * f, sort * s, expr * rm, expr *
|
|||
|
||||
one1 = m_bv_util.mk_numeral(1, 1);
|
||||
expr_ref ninf(m), pinf(m);
|
||||
mk_pinf(f, pinf);
|
||||
mk_ninf(f, ninf);
|
||||
mk_pinf(to_srt, pinf);
|
||||
mk_ninf(to_srt, ninf);
|
||||
|
||||
// NaN -> NaN
|
||||
mk_is_nan(x, c1);
|
||||
mk_nan(f, v1);
|
||||
mk_nan(to_srt, v1);
|
||||
|
||||
// +0 -> +0
|
||||
mk_is_pzero(x, c2);
|
||||
mk_pzero(f, v2);
|
||||
mk_pzero(to_srt, v2);
|
||||
|
||||
// -0 -> -0
|
||||
mk_is_nzero(x, c3);
|
||||
mk_nzero(f, v3);
|
||||
mk_nzero(to_srt, v3);
|
||||
|
||||
// +oo -> +oo
|
||||
mk_is_pinf(x, c4);
|
||||
|
@ -2380,8 +2383,8 @@ void fpa2bv_converter::mk_to_fp_float(func_decl * f, sort * s, expr * rm, expr *
|
|||
dbg_decouple("fpa2bv_to_float_res_exp", res_exp);
|
||||
|
||||
expr_ref rounded(m);
|
||||
expr_ref rm_e(bv_rm, m);
|
||||
round(s, rm_e, res_sgn, res_sig, res_exp, rounded);
|
||||
expr_ref rm_e(rm, m);
|
||||
round(to_srt, rm_e, res_sgn, res_sig, res_exp, rounded);
|
||||
|
||||
expr_ref is_neg(m), sig_inf(m);
|
||||
m_simp.mk_eq(sgn, one1, is_neg);
|
||||
|
|
|
@ -144,6 +144,9 @@ public:
|
|||
void dbg_decouple(const char * prefix, expr_ref & e);
|
||||
expr_ref_vector m_extra_assertions;
|
||||
|
||||
bool is_special(func_decl * f) { return m_specials.contains(f); }
|
||||
bool is_uf2bvuf(func_decl * f) { return m_uf2bvuf.contains(f); }
|
||||
|
||||
protected:
|
||||
void mk_one(func_decl *f, expr_ref & sign, expr_ref & result);
|
||||
|
||||
|
@ -201,6 +204,8 @@ private:
|
|||
void mk_div(sort * s, expr_ref & bv_rm, expr_ref & x, expr_ref & y, expr_ref & result);
|
||||
void mk_rem(sort * s, expr_ref & x, expr_ref & y, expr_ref & result);
|
||||
void mk_round_to_integral(sort * s, expr_ref & rm, expr_ref & x, expr_ref & result);
|
||||
|
||||
void mk_to_fp_float(sort * s, expr * rm, expr * x, expr_ref & result);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -151,7 +151,7 @@ struct evaluator_cfg : public default_rewriter_cfg {
|
|||
st = m_f_rw.mk_eq_core(args[0], args[1], result);
|
||||
else if (s_fid == m_seq_rw.get_fid())
|
||||
st = m_seq_rw.mk_eq_core(args[0], args[1], result);
|
||||
else if (fid == m_ar_rw.get_fid())
|
||||
else if (s_fid == m_ar_rw.get_fid())
|
||||
st = mk_array_eq(args[0], args[1], result);
|
||||
if (st != BR_FAILED)
|
||||
return st;
|
||||
|
|
|
@ -85,8 +85,63 @@ namespace smt {
|
|||
}
|
||||
|
||||
void theory_fpa::fpa2bv_converter_wrapped::mk_uninterpreted_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
|
||||
// TODO: This introduces temporary variables/func_decls that should be filtered in the end.
|
||||
fpa2bv_converter::mk_uninterpreted_function(f, num, args, result);
|
||||
// TODO: This introduces temporary func_decls that should be filtered in the end.
|
||||
|
||||
TRACE("t_fpa", tout << "UF: " << mk_ismt2_pp(f, m) << std::endl; );
|
||||
SASSERT(f->get_arity() == num);
|
||||
|
||||
expr_ref_buffer new_args(m);
|
||||
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
if (is_float(args[i]) || is_rm(args[i])) {
|
||||
expr_ref ai(m), wrapped(m);
|
||||
ai = args[i];
|
||||
wrapped = m_th.wrap(ai);
|
||||
new_args.push_back(wrapped);
|
||||
m_extra_assertions.push_back(m.mk_eq(m_th.unwrap(wrapped, m.get_sort(ai)), ai));
|
||||
}
|
||||
else
|
||||
new_args.push_back(args[i]);
|
||||
}
|
||||
|
||||
func_decl * fd;
|
||||
if (m_uf2bvuf.find(f, fd))
|
||||
mk_uninterpreted_output(f->get_range(), fd, new_args, result);
|
||||
else {
|
||||
sort_ref_buffer new_domain(m);
|
||||
|
||||
for (unsigned i = 0; i < f->get_arity(); i++) {
|
||||
sort * di = f->get_domain()[i];
|
||||
if (is_float(di))
|
||||
new_domain.push_back(m_bv_util.mk_sort(m_util.get_sbits(di) + m_util.get_ebits(di)));
|
||||
else if (is_rm(di))
|
||||
new_domain.push_back(m_bv_util.mk_sort(3));
|
||||
else
|
||||
new_domain.push_back(di);
|
||||
}
|
||||
|
||||
sort * frng = f->get_range();
|
||||
sort_ref rng(frng, m);
|
||||
if (m_util.is_float(frng))
|
||||
rng = m_bv_util.mk_sort(m_util.get_ebits(frng) + m_util.get_sbits(frng));
|
||||
else if (m_util.is_rm(frng))
|
||||
rng = m_bv_util.mk_sort(3);
|
||||
|
||||
func_decl_ref fbv(m);
|
||||
fbv = m.mk_fresh_func_decl(new_domain.size(), new_domain.c_ptr(), rng);
|
||||
TRACE("t_fpa", tout << "New UF func_decl : " << mk_ismt2_pp(fbv, m) << std::endl;);
|
||||
|
||||
m_uf2bvuf.insert(f, fbv);
|
||||
m.inc_ref(f);
|
||||
m.inc_ref(fbv);
|
||||
|
||||
mk_uninterpreted_output(frng, fbv, new_args, result);
|
||||
}
|
||||
|
||||
expr_ref fapp(m);
|
||||
fapp = m.mk_app(f, num, args);
|
||||
m_extra_assertions.push_back(m.mk_eq(fapp, result));
|
||||
TRACE("t_fpa", tout << "UF result: " << mk_ismt2_pp(result, m) << std::endl; );
|
||||
}
|
||||
|
||||
expr_ref theory_fpa::fpa2bv_converter_wrapped::mk_min_unspecified(func_decl * f, expr * x, expr * y) {
|
||||
|
@ -284,30 +339,40 @@ namespace smt {
|
|||
app_ref theory_fpa::wrap(expr * e) {
|
||||
SASSERT(!m_fpa_util.is_wrap(e));
|
||||
ast_manager & m = get_manager();
|
||||
sort * e_srt = m.get_sort(e);
|
||||
app_ref res(m);
|
||||
|
||||
func_decl *w;
|
||||
if (is_app(e) &&
|
||||
to_app(e)->get_family_id() == get_family_id() &&
|
||||
to_app(e)->get_decl_kind() == OP_FPA_FP) {
|
||||
expr * cargs[3] = { to_app(e)->get_arg(0), to_app(e)->get_arg(1), to_app(e)->get_arg(2) };
|
||||
res = m_bv_util.mk_concat(3, cargs);
|
||||
m_th_rw((expr_ref&)res);
|
||||
}
|
||||
else {
|
||||
sort * e_srt = m.get_sort(e);
|
||||
func_decl * w;
|
||||
|
||||
if (!m_wraps.find(e_srt, w)) {
|
||||
SASSERT(!m_wraps.contains(e_srt));
|
||||
if (!m_wraps.find(e_srt, w)) {
|
||||
SASSERT(!m_wraps.contains(e_srt));
|
||||
|
||||
sort * bv_srt;
|
||||
if (m_converter.is_rm(e_srt))
|
||||
bv_srt = m_bv_util.mk_sort(3);
|
||||
else {
|
||||
SASSERT(m_converter.is_float(e_srt));
|
||||
unsigned ebits = m_fpa_util.get_ebits(e_srt);
|
||||
unsigned sbits = m_fpa_util.get_sbits(e_srt);
|
||||
bv_srt = m_bv_util.mk_sort(ebits + sbits);
|
||||
sort * bv_srt;
|
||||
if (m_converter.is_rm(e_srt))
|
||||
bv_srt = m_bv_util.mk_sort(3);
|
||||
else {
|
||||
SASSERT(m_converter.is_float(e_srt));
|
||||
unsigned ebits = m_fpa_util.get_ebits(e_srt);
|
||||
unsigned sbits = m_fpa_util.get_sbits(e_srt);
|
||||
bv_srt = m_bv_util.mk_sort(ebits + sbits);
|
||||
}
|
||||
|
||||
w = m.mk_func_decl(get_family_id(), OP_FPA_INTERNAL_BVWRAP, 0, 0, 1, &e_srt, bv_srt);
|
||||
m_wraps.insert(e_srt, w);
|
||||
m.inc_ref(w);
|
||||
}
|
||||
|
||||
w = m.mk_func_decl(get_family_id(), OP_FPA_INTERNAL_BVWRAP, 0, 0, 1, &e_srt, bv_srt);
|
||||
m_wraps.insert(e_srt, w);
|
||||
m.inc_ref(w);
|
||||
res = m.mk_app(w, e);
|
||||
}
|
||||
|
||||
app_ref res(m);
|
||||
res = m.mk_app(w, e);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -389,59 +454,6 @@ namespace smt {
|
|||
return res;
|
||||
}
|
||||
|
||||
#if 0
|
||||
expr_ref theory_fpa::convert_uf(expr * e) {
|
||||
SASSERT(is_app(e));
|
||||
ast_manager & m = get_manager();
|
||||
expr_ref res(m);
|
||||
|
||||
app * a = to_app(e);
|
||||
func_decl * f = a->get_decl();
|
||||
sort * const * domain = f->get_domain();
|
||||
unsigned arity = f->get_arity();
|
||||
|
||||
expr_ref_buffer new_args(m);
|
||||
expr_ref unwrapped(m);
|
||||
|
||||
for (unsigned i = 0; i < arity; i++) {
|
||||
expr * ai = a->get_arg(i);
|
||||
if (m_fpa_util.is_float(ai) || m_fpa_util.is_rm(ai)) {
|
||||
if (m_fpa_util.is_unwrap(ai))
|
||||
unwrapped = ai;
|
||||
else {
|
||||
// unwrapped = unwrap(wrap(ai), domain[i]);
|
||||
// assert_cnstr(m.mk_eq(unwrapped, ai));
|
||||
// assert_cnstr();
|
||||
unwrapped = convert_term(ai);
|
||||
}
|
||||
|
||||
new_args.push_back(unwrapped);
|
||||
TRACE("t_fpa_detail", tout << "UF arg(" << i << ") = " << mk_ismt2_pp(unwrapped, get_manager()) << "\n";);
|
||||
}
|
||||
else
|
||||
new_args.push_back(ai);
|
||||
}
|
||||
|
||||
sort * rng = f->get_range();
|
||||
if (m_fpa_util.is_float(rng)) {
|
||||
unsigned sbits = m_fpa_util.get_sbits(rng);
|
||||
unsigned bv_sz = m_fpa_util.get_ebits(rng) + sbits;
|
||||
expr_ref wrapped(m);
|
||||
wrapped = wrap(m.mk_app(f, new_args.size(), new_args.c_ptr()));
|
||||
|
||||
m_converter.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, wrapped),
|
||||
m_bv_util.mk_extract(bv_sz - 2, sbits - 1, wrapped),
|
||||
m_bv_util.mk_extract(sbits - 2, 0, wrapped),
|
||||
res);
|
||||
}
|
||||
else
|
||||
res = m.mk_app(f, new_args.size(), new_args.c_ptr());
|
||||
|
||||
TRACE("t_fpa_detail", tout << "UF call = " << mk_ismt2_pp(res, get_manager()) << "\n";);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
expr_ref theory_fpa::convert_conversion_term(expr * e) {
|
||||
/* This is for the conversion functions fp.to_* */
|
||||
ast_manager & m = get_manager();
|
||||
|
@ -606,6 +618,7 @@ namespace smt {
|
|||
// Therefore, we translate and assert them here.
|
||||
fpa_op_kind k = (fpa_op_kind)term->get_decl_kind();
|
||||
switch (k) {
|
||||
case OP_FPA_TO_FP:
|
||||
case OP_FPA_TO_UBV:
|
||||
case OP_FPA_TO_SBV:
|
||||
case OP_FPA_TO_REAL:
|
||||
|
@ -966,4 +979,16 @@ namespace smt {
|
|||
out << r->get_id() << " --> " << mk_ismt2_pp(n, m) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
bool theory_fpa::include_func_interp(func_decl * f) {
|
||||
TRACE("t_fpa", tout << "f = " << mk_ismt2_pp(f, get_manager()) << std::endl;);
|
||||
func_decl * wt;
|
||||
|
||||
if (m_wraps.find(f->get_range(), wt) || m_unwraps.find(f->get_range(), wt))
|
||||
return wt == f;
|
||||
else if (m_converter.is_uf2bvuf(f) || m_converter.is_special(f))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -83,7 +83,7 @@ namespace smt {
|
|||
virtual ~fpa2bv_converter_wrapped() {}
|
||||
virtual void mk_const(func_decl * f, expr_ref & result);
|
||||
virtual void mk_rm_const(func_decl * f, expr_ref & result);
|
||||
virtual void mk_uninterpreted_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
virtual void mk_uninterpreted_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
|
||||
|
||||
virtual expr_ref mk_min_unspecified(func_decl * f, expr * x, expr * y);
|
||||
virtual expr_ref mk_max_unspecified(func_decl * f, expr * x, expr * y);
|
||||
|
@ -112,7 +112,7 @@ namespace smt {
|
|||
result.append(m_deps);
|
||||
}
|
||||
|
||||
virtual app * mk_value(model_generator & mg, ptr_vector<expr> & values);
|
||||
virtual app * mk_value(model_generator & mg, ptr_vector<expr> & values);
|
||||
};
|
||||
|
||||
class fpa_rm_value_proc : public model_value_proc {
|
||||
|
@ -163,6 +163,7 @@ namespace smt {
|
|||
virtual char const * get_name() const { return "fpa"; }
|
||||
|
||||
virtual model_value_proc * mk_value(enode * n, model_generator & mg);
|
||||
virtual bool include_func_interp(func_decl * f);
|
||||
|
||||
void assign_eh(bool_var v, bool is_true);
|
||||
virtual void relevant_eh(app * n);
|
||||
|
|
261
src/util/mpf.cpp
261
src/util/mpf.cpp
|
@ -1214,11 +1214,194 @@ void mpf_manager::to_ieee_bv_mpz(const mpf & x, scoped_mpz & o) {
|
|||
}
|
||||
}
|
||||
|
||||
void mpf_manager::renormalize(unsigned ebits, unsigned sbits, mpf_exp_t & exp, mpz & sig) {
|
||||
if (m_mpz_manager.is_zero(sig))
|
||||
return;
|
||||
|
||||
const mpz & pg = m_powers2(sbits);
|
||||
while (m_mpz_manager.ge(sig, pg)) {
|
||||
m_mpz_manager.machine_div2k(sig, 1);
|
||||
exp++;
|
||||
}
|
||||
|
||||
const mpz & pl = m_powers2(sbits-1);
|
||||
while (m_mpz_manager.lt(sig, pl)) {
|
||||
m_mpz_manager.mul2k(sig, 1);
|
||||
exp--;
|
||||
}
|
||||
}
|
||||
|
||||
void mpf_manager::partial_remainder(mpf & x, mpf const & y, mpf_exp_t const & exp_diff, bool partial) {
|
||||
unsigned ebits = x.ebits;
|
||||
unsigned sbits = x.sbits;
|
||||
|
||||
SASSERT(-1 <= exp_diff && exp_diff < INT64_MAX);
|
||||
SASSERT(exp_diff < ebits+sbits || partial);
|
||||
|
||||
signed int D = (signed int)(exp_diff);
|
||||
mpf_exp_t N = sbits-1;
|
||||
|
||||
TRACE("mpf_dbg_rem", tout << "x=" << to_string(x) << std::endl;
|
||||
tout << "y=" << to_string(y) << std::endl;
|
||||
tout << "d=" << D << std::endl;
|
||||
tout << "partial=" << partial << std::endl;);
|
||||
|
||||
SASSERT(m_mpz_manager.lt(x.significand, m_powers2(sbits)));
|
||||
SASSERT(m_mpz_manager.ge(x.significand, m_powers2(sbits - 1)));
|
||||
SASSERT(m_mpz_manager.lt(y.significand, m_powers2(sbits)));
|
||||
SASSERT(m_mpz_manager.ge(y.significand, m_powers2(sbits - 1)));
|
||||
|
||||
// 1. Compute a/b
|
||||
bool x_div_y_sgn = x.sign != y.sign;
|
||||
mpf_exp_t x_div_y_exp = D;
|
||||
scoped_mpz x_sig_shifted(m_mpz_manager), x_div_y_sig_lrg(m_mpz_manager), x_div_y_rem(m_mpz_manager);
|
||||
scoped_mpz x_rem_y_sig(m_mpz_manager);
|
||||
m_mpz_manager.mul2k(x.significand, 2*sbits + 2, x_sig_shifted);
|
||||
m_mpz_manager.machine_div_rem(x_sig_shifted, y.significand, x_div_y_sig_lrg, x_div_y_rem); // rem useful?
|
||||
// x/y is in x_diuv_y_sig_lrg and has sbits+3 extra bits.
|
||||
|
||||
TRACE("mpf_dbg_rem", tout << "X/Y_exp=" << x_div_y_exp << std::endl;
|
||||
tout << "X/Y_sig_lrg=" << m_mpz_manager.to_string(x_div_y_sig_lrg) << std::endl;
|
||||
tout << "X/Y_rem=" << m_mpz_manager.to_string(x_div_y_rem) << std::endl;
|
||||
tout << "X/Y~=" << to_string_hexfloat(x_div_y_sgn, x_div_y_exp, x_div_y_sig_lrg, ebits, sbits, sbits+3) << std::endl;);
|
||||
|
||||
// 2. Round a/b to integer Q/QQ
|
||||
bool Q_sgn = x_div_y_sgn;
|
||||
mpf_exp_t Q_exp = x_div_y_exp;
|
||||
scoped_mpz Q_sig(m_mpz_manager), Q_rem(m_mpz_manager);
|
||||
unsigned Q_shft = (sbits-1) + (sbits+3) - (unsigned) (partial ? N :Q_exp);
|
||||
if (partial) {
|
||||
// Round according to MPF_ROUND_TOWARD_ZERO
|
||||
SASSERT(0 < N && N < Q_exp && Q_exp < INT_MAX);
|
||||
m_mpz_manager.machine_div2k(x_div_y_sig_lrg, Q_shft, Q_sig);
|
||||
}
|
||||
else {
|
||||
// Round according to MPF_ROUND_NEAREST_TEVEN
|
||||
m_mpz_manager.machine_div_rem(x_div_y_sig_lrg, m_powers2(Q_shft), Q_sig, Q_rem);
|
||||
const mpz & shiftm1_p = m_powers2(Q_shft-1);
|
||||
bool tie = m_mpz_manager.eq(Q_rem, shiftm1_p);
|
||||
bool more_than_tie = m_mpz_manager.gt(Q_rem, shiftm1_p);
|
||||
TRACE("mpf_dbg_rem", tout << "tie= " << tie << "; >tie= " << more_than_tie << std::endl;);
|
||||
if ((tie && m_mpz_manager.is_odd(Q_sig)) || more_than_tie)
|
||||
m_mpz_manager.inc(Q_sig);
|
||||
}
|
||||
m_mpz_manager.mul2k(Q_sig, Q_shft);
|
||||
m_mpz_manager.machine_div2k(Q_sig, sbits+3);
|
||||
renormalize(ebits, sbits, Q_exp, Q_sig);
|
||||
|
||||
TRACE("mpf_dbg_rem", tout << "Q_exp=" << Q_exp << std::endl;
|
||||
tout << "Q_sig=" << m_mpz_manager.to_string(Q_sig) << std::endl;
|
||||
tout << "Q=" << to_string_hexfloat(Q_sgn, Q_exp, Q_sig, ebits, sbits, 0) << std::endl;);
|
||||
|
||||
if ((D == -1 || partial) && m_mpz_manager.is_zero(Q_sig))
|
||||
return; // This means x % y = x.
|
||||
|
||||
// no extra bits in Q_sig.
|
||||
SASSERT(!m_mpz_manager.is_zero(Q_sig));
|
||||
SASSERT(m_mpz_manager.lt(Q_sig, m_powers2(sbits)));
|
||||
SASSERT(m_mpz_manager.ge(Q_sig, m_powers2(sbits - 1)));
|
||||
|
||||
|
||||
// 3. Compute Y*Q / Y*QQ*2^{D-N}
|
||||
bool YQ_sgn = y.sign ^ Q_sgn;
|
||||
scoped_mpz YQ_sig(m_mpz_manager);
|
||||
mpf_exp_t YQ_exp = Q_exp + y.exponent;
|
||||
m_mpz_manager.mul(y.significand, Q_sig, YQ_sig);
|
||||
renormalize(ebits, 2*sbits-1, YQ_exp, YQ_sig); // YQ_sig has `sbits-1' extra bits.
|
||||
|
||||
TRACE("mpf_dbg_rem", tout << "YQ_sgn=" << YQ_sgn << std::endl;
|
||||
tout << "YQ_exp=" << YQ_exp << std::endl;
|
||||
tout << "YQ_sig=" << m_mpz_manager.to_string(YQ_sig) << std::endl;
|
||||
tout << "YQ=" << to_string_hexfloat(YQ_sgn, YQ_exp, YQ_sig, ebits, sbits, sbits-1) << std::endl;);
|
||||
|
||||
// `sbits-1' extra bits in YQ_sig.
|
||||
SASSERT(m_mpz_manager.lt(YQ_sig, m_powers2(2*sbits-1)));
|
||||
SASSERT(m_mpz_manager.ge(YQ_sig, m_powers2(2*sbits-2)) || YQ_exp <= mk_bot_exp(ebits));
|
||||
|
||||
// 4. Compute X-Y*Q
|
||||
mpf_exp_t X_YQ_exp = x.exponent;
|
||||
scoped_mpz X_YQ_sig(m_mpz_manager);
|
||||
mpf_exp_t exp_delta = exp(x) - YQ_exp;
|
||||
TRACE("mpf_dbg_rem", tout << "exp_delta=" << exp_delta << std::endl;);
|
||||
SASSERT(INT_MIN < exp_delta && exp_delta <= INT_MAX);
|
||||
scoped_mpz minuend(m_mpz_manager), subtrahend(m_mpz_manager);
|
||||
|
||||
scoped_mpz x_sig_lrg(m_mpz_manager);
|
||||
m_mpz_manager.mul2k(x.significand, sbits-1, x_sig_lrg); // sbits-1 extra bits into x
|
||||
|
||||
m_mpz_manager.set(minuend, x_sig_lrg);
|
||||
m_mpz_manager.set(subtrahend, YQ_sig);
|
||||
|
||||
SASSERT(m_mpz_manager.lt(minuend, m_powers2(2*sbits-1)));
|
||||
SASSERT(m_mpz_manager.ge(minuend, m_powers2(2*sbits-2)));
|
||||
SASSERT(m_mpz_manager.lt(subtrahend, m_powers2(2*sbits-1)));
|
||||
SASSERT(m_mpz_manager.ge(subtrahend, m_powers2(2*sbits-2)));
|
||||
|
||||
if (exp_delta != 0) {
|
||||
scoped_mpz sticky_rem(m_mpz_manager);
|
||||
m_mpz_manager.set(sticky_rem, 0);
|
||||
if (exp_delta > sbits+5)
|
||||
sticky_rem.swap(subtrahend);
|
||||
else if (exp_delta > 0)
|
||||
m_mpz_manager.machine_div_rem(subtrahend, m_powers2((unsigned)exp_delta), subtrahend, sticky_rem);
|
||||
else {
|
||||
SASSERT(exp_delta < 0);
|
||||
exp_delta = -exp_delta;
|
||||
m_mpz_manager.mul2k(subtrahend, (int)exp_delta);
|
||||
}
|
||||
if (!m_mpz_manager.is_zero(sticky_rem) && m_mpz_manager.is_even(subtrahend))
|
||||
m_mpz_manager.inc(subtrahend);
|
||||
TRACE("mpf_dbg_rem", tout << "aligned subtrahend=" << m_mpz_manager.to_string(subtrahend) << std::endl;);
|
||||
}
|
||||
|
||||
m_mpz_manager.sub(minuend, subtrahend, X_YQ_sig);
|
||||
TRACE("mpf_dbg_rem", tout << "X_YQ_sig'=" << m_mpz_manager.to_string(X_YQ_sig) << std::endl;);
|
||||
|
||||
bool neg = m_mpz_manager.is_neg(X_YQ_sig);
|
||||
if (neg) m_mpz_manager.neg(X_YQ_sig);
|
||||
bool X_YQ_sgn = ((!x.sign && !YQ_sgn && neg) ||
|
||||
(x.sign && YQ_sgn && !neg) ||
|
||||
(x.sign && !YQ_sgn));
|
||||
|
||||
// 5. Rounding
|
||||
if (m_mpz_manager.is_zero(X_YQ_sig))
|
||||
mk_zero(ebits, sbits, x.sign, x);
|
||||
else {
|
||||
renormalize(ebits, 2*sbits-1, X_YQ_exp, X_YQ_sig);
|
||||
|
||||
TRACE("mpf_dbg_rem", tout << "minuend=" << m_mpz_manager.to_string(minuend) << std::endl;
|
||||
tout << "subtrahend=" << m_mpz_manager.to_string(subtrahend) << std::endl;
|
||||
tout << "X_YQ_sgn=" << X_YQ_sgn << std::endl;
|
||||
tout << "X_YQ_exp=" << X_YQ_exp << std::endl;
|
||||
tout << "X_YQ_sig=" << m_mpz_manager.to_string(X_YQ_sig) << std::endl;
|
||||
tout << "X-YQ=" << to_string_hexfloat(X_YQ_sgn, X_YQ_exp, X_YQ_sig, ebits, sbits, sbits-1) << std::endl;);
|
||||
|
||||
// `sbits-1' extra bits in X_YQ_sig
|
||||
SASSERT(m_mpz_manager.lt(X_YQ_sig, m_powers2(2*sbits-1)));
|
||||
scoped_mpz rnd_bits(m_mpz_manager);
|
||||
m_mpz_manager.machine_div_rem(X_YQ_sig, m_powers2(sbits-1), X_YQ_sig, rnd_bits);
|
||||
TRACE("mpf_dbg_rem", tout << "final sticky=" << m_mpz_manager.to_string(rnd_bits) << std::endl; );
|
||||
|
||||
// Round to nearest, ties to even.
|
||||
if (m_mpz_manager.eq(rnd_bits, mpz(32))) { // tie.
|
||||
if (m_mpz_manager.is_odd(X_YQ_sig)) {
|
||||
m_mpz_manager.inc(X_YQ_sig);
|
||||
}
|
||||
}
|
||||
else if (m_mpz_manager.gt(rnd_bits, mpz(32)))
|
||||
m_mpz_manager.inc(X_YQ_sig);
|
||||
|
||||
set(x, ebits, sbits, X_YQ_sgn, X_YQ_exp, X_YQ_sig);
|
||||
}
|
||||
|
||||
TRACE("mpf_dbg_rem", tout << "partial remainder = " << to_string_hexfloat(x) << std::endl;);
|
||||
}
|
||||
|
||||
void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) {
|
||||
SASSERT(x.sbits == y.sbits && x.ebits == y.ebits);
|
||||
|
||||
TRACE("mpf_dbg", tout << "X = " << to_string(x) << std::endl;);
|
||||
TRACE("mpf_dbg", tout << "Y = " << to_string(y) << std::endl;);
|
||||
TRACE("mpf_dbg_rem", tout << "X = " << to_string(x) << "=" << to_string_hexfloat(x) << std::endl;
|
||||
tout << "Y = " << to_string(y) << "=" << to_string_hexfloat(y) << std::endl;);
|
||||
|
||||
if (is_nan(x) || is_nan(y))
|
||||
mk_nan(x.ebits, x.sbits, o);
|
||||
|
@ -1231,58 +1414,35 @@ void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) {
|
|||
else if (is_zero(x))
|
||||
set(o, x);
|
||||
else {
|
||||
// This is a generalized version of the algorithm for FPREM1 in the Intel
|
||||
SASSERT(is_regular(x) && is_regular(y));
|
||||
|
||||
// This is a generalized version of the algorithm for FPREM1 in the `Intel
|
||||
// 64 and IA-32 Architectures Software Developer's Manual',
|
||||
// Section 3-402 Vol. 2A FPREM1-Partial Remainder'.
|
||||
// Section 3-402 Vol. 2A `FPREM1-Partial Remainder'.
|
||||
scoped_mpf ST0(*this), ST1(*this);
|
||||
set(ST0, x);
|
||||
set(ST1, y);
|
||||
unpack(ST0, true);
|
||||
unpack(ST1, true);
|
||||
|
||||
const mpf_exp_t B = x.sbits-1; // max bits per iteration.
|
||||
const mpf_exp_t B = x.sbits;
|
||||
mpf_exp_t D;
|
||||
do {
|
||||
D = ST0.exponent() - ST1.exponent();
|
||||
TRACE("mpf_dbg_rem", tout << "st0=" << to_string_hexfloat(ST0) << std::endl;
|
||||
tout << "st1=" << to_string_hexfloat(ST1) << std::endl;
|
||||
tout << "D=" << D << std::endl;);
|
||||
|
||||
if (D < B) {
|
||||
scoped_mpf ST0_DIV_ST1(*this), Q(*this), ST1_MUL_Q(*this), ST0p(*this);
|
||||
div(MPF_ROUND_NEAREST_TEVEN, ST0, ST1, ST0_DIV_ST1);
|
||||
round_to_integral(MPF_ROUND_NEAREST_TEVEN, ST0_DIV_ST1, Q);
|
||||
mul(MPF_ROUND_NEAREST_TEVEN, ST1, Q, ST1_MUL_Q);
|
||||
sub(MPF_ROUND_NEAREST_TEVEN, ST0, ST1_MUL_Q, ST0p);
|
||||
TRACE("mpf_dbg_rem", tout << "ST0/ST1=" << to_string_hexfloat(ST0_DIV_ST1) << std::endl;
|
||||
tout << "Q=" << to_string_hexfloat(Q) << std::endl;
|
||||
tout << "ST1*Q=" << to_string_hexfloat(ST1_MUL_Q) << std::endl;
|
||||
tout << "ST0'=" << to_string_hexfloat(ST0p) << std::endl;);
|
||||
set(ST0, ST0p);
|
||||
if (ST0.exponent() < ST1.exponent() - 1) {
|
||||
D = 0;
|
||||
}
|
||||
else {
|
||||
const mpf_exp_t N = B;
|
||||
scoped_mpf ST0_DIV_ST1(*this), QQ(*this), ST1_MUL_QQ(*this), ST0p(*this);
|
||||
div(MPF_ROUND_TOWARD_ZERO, ST0, ST1, ST0_DIV_ST1);
|
||||
ST0_DIV_ST1.get().exponent -= D - N;
|
||||
round_to_integral(MPF_ROUND_TOWARD_ZERO, ST0_DIV_ST1, QQ);
|
||||
mul(MPF_ROUND_NEAREST_TEVEN, ST1, QQ, ST1_MUL_QQ);
|
||||
ST1_MUL_QQ.get().exponent += D - N;
|
||||
sub(MPF_ROUND_NEAREST_TEVEN, ST0, ST1_MUL_QQ, ST0p);
|
||||
TRACE("mpf_dbg_rem", tout << "ST0/ST1/2^{D-N}=" << to_string_hexfloat(ST0_DIV_ST1) << std::endl;
|
||||
tout << "QQ=" << to_string_hexfloat(QQ) << std::endl;
|
||||
tout << "ST1*QQ*2^{D-N}=" << to_string_hexfloat(ST1_MUL_QQ) << std::endl;
|
||||
tout << "ST0'=" << to_string_hexfloat(ST0p) << std::endl;);
|
||||
SASSERT(!eq(ST0, ST0p));
|
||||
set(ST0, ST0p);
|
||||
D = ST0.exponent() - ST1.exponent();
|
||||
partial_remainder(ST0.get(), ST1.get(), D, (D >= B));
|
||||
}
|
||||
} while (D >= B && !ST0.is_zero());
|
||||
|
||||
SASSERT(ST0.exponent() - ST1.exponent() <= D);
|
||||
} while (D >= B);
|
||||
|
||||
set(o, ST0);
|
||||
if (is_zero(o))
|
||||
o.sign = x.sign;
|
||||
m_mpz_manager.mul2k(ST0.significand(), 3);
|
||||
set(o, x.ebits, x.sbits, MPF_ROUND_TOWARD_ZERO, ST0);
|
||||
round(MPF_ROUND_NEAREST_TEVEN, o);
|
||||
}
|
||||
|
||||
TRACE("mpf_dbg_rem", tout << "R = " << to_string(o) << "=" << to_string_hexfloat(o) << std::endl; );
|
||||
TRACE("mpf_dbg", tout << "REMAINDER = " << to_string(o) << std::endl;);
|
||||
}
|
||||
|
||||
|
@ -1364,9 +1524,9 @@ std::string mpf_manager::to_string(mpf const & x) {
|
|||
}
|
||||
}
|
||||
|
||||
//DEBUG_CODE(
|
||||
// res += " " + to_string_hexfloat(x);
|
||||
//);
|
||||
DEBUG_CODE(
|
||||
res += " " + to_string_raw(x);
|
||||
);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -1407,6 +1567,19 @@ std::string mpf_manager::to_string_raw(mpf const & x) {
|
|||
return res;
|
||||
}
|
||||
|
||||
std::string mpf_manager::to_string_hexfloat(bool sgn, mpf_exp_t exp, scoped_mpz const & sig, unsigned ebits, unsigned sbits, unsigned rbits) {
|
||||
scoped_mpf q(*this);
|
||||
scoped_mpz q_sig(m_mpz_manager);
|
||||
m_mpz_manager.set(q_sig, sig);
|
||||
if (rbits != 0) m_mpz_manager.div(q_sig, m_powers2(rbits), q_sig); // restore scale
|
||||
if (m_mpz_manager.ge(q_sig, m_powers2(sbits-1)))
|
||||
m_mpz_manager.sub(q_sig, m_powers2(sbits-1), q_sig); // strip hidden bit
|
||||
else if (exp == mk_min_exp(ebits))
|
||||
exp = mk_bot_exp(ebits);
|
||||
set(q, ebits, sbits, sgn, exp, q_sig);
|
||||
return to_string(q.get());
|
||||
}
|
||||
|
||||
std::string mpf_manager::to_string_hexfloat(mpf const & x) {
|
||||
std::stringstream ss("");
|
||||
std::ios::fmtflags ff = ss.setf(std::ios_base::hex | std::ios_base::uppercase |
|
||||
|
|
|
@ -185,9 +185,6 @@ public:
|
|||
void mk_pinf(unsigned ebits, unsigned sbits, mpf & o);
|
||||
void mk_ninf(unsigned ebits, unsigned sbits, mpf & o);
|
||||
|
||||
std::string to_string_raw(mpf const & a);
|
||||
std::string to_string_hexfloat(mpf const & a);
|
||||
|
||||
unsynch_mpz_manager & mpz_manager(void) { return m_mpz_manager; }
|
||||
unsynch_mpq_manager & mpq_manager(void) { return m_mpq_manager; }
|
||||
|
||||
|
@ -226,6 +223,9 @@ protected:
|
|||
void round(mpf_rounding_mode rm, mpf & o);
|
||||
void round_sqrt(mpf_rounding_mode rm, mpf & o);
|
||||
|
||||
void renormalize(unsigned ebits, unsigned sbits, mpf_exp_t & exp, mpz & sig);
|
||||
void partial_remainder(mpf & x, mpf const & y, mpf_exp_t const & exp_diff, bool partial);
|
||||
|
||||
void mk_round_inf(mpf_rounding_mode rm, mpf & o);
|
||||
|
||||
// Convert x into a mpz numeral. zm is the manager that owns o.
|
||||
|
@ -284,6 +284,9 @@ protected:
|
|||
}
|
||||
};
|
||||
|
||||
std::string to_string_raw(mpf const & a);
|
||||
std::string to_string_hexfloat(mpf const & a);
|
||||
std::string to_string_hexfloat(bool sgn, mpf_exp_t exp, scoped_mpz const & sig, unsigned ebits, unsigned sbits, unsigned rbits);
|
||||
public:
|
||||
powers2 m_powers2;
|
||||
};
|
||||
|
@ -291,6 +294,7 @@ public:
|
|||
class scoped_mpf : public _scoped_numeral<mpf_manager> {
|
||||
friend class mpf_manager;
|
||||
mpz & significand() { return get().significand; }
|
||||
const mpz & significand() const { return get().significand; }
|
||||
bool sign() const { return get().sign; }
|
||||
mpf_exp_t exponent() const { return get().exponent; }
|
||||
unsigned sbits() const { return get().sbits; }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue