mirror of
https://github.com/Z3Prover/z3
synced 2025-04-08 10:25:18 +00:00
Injected 3 missing bits of precision into fp.rem. Relates to #872.
This commit is contained in:
parent
a59907170d
commit
ecfd241e19
|
@ -1535,11 +1535,12 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
|
|||
|
||||
// Extend c
|
||||
expr_ref c_sig_ext(m);
|
||||
c_sig_ext = m_bv_util.mk_zero_extend(1, m_bv_util.mk_concat(c_sig, m_bv_util.mk_numeral(0, sbits - 1)));
|
||||
c_sig_ext = m_bv_util.mk_zero_extend(1, m_bv_util.mk_concat(c_sig, m_bv_util.mk_numeral(0, sbits - 1 + 3)));
|
||||
c_exp_ext = m_bv_util.mk_bv_sub(c_exp_ext, c_lz_ext);
|
||||
mul_sig = m_bv_util.mk_concat(mul_sig, m_bv_util.mk_numeral(0, 3));
|
||||
|
||||
SASSERT(m_bv_util.get_bv_size(mul_sig) == 2 * sbits);
|
||||
SASSERT(m_bv_util.get_bv_size(c_sig_ext) == 2 * sbits);
|
||||
SASSERT(m_bv_util.get_bv_size(mul_sig) == 2 * sbits + 3);
|
||||
SASSERT(m_bv_util.get_bv_size(c_sig_ext) == 2 * sbits + 3);
|
||||
dbg_decouple("fpa2bv_fma_c_sig_ext", c_sig_ext);
|
||||
dbg_decouple("fpa2bv_fma_c_exp_ext", c_exp_ext);
|
||||
|
||||
|
@ -1550,10 +1551,10 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
|
|||
|
||||
expr_ref e_sgn(m), e_sig(m), e_exp(m), f_sgn(m), f_sig(m), f_exp(m);
|
||||
m_simp.mk_ite(swap_cond, c_sgn, mul_sgn, e_sgn);
|
||||
m_simp.mk_ite(swap_cond, c_sig_ext, mul_sig, e_sig); // has 2 * sbits
|
||||
m_simp.mk_ite(swap_cond, c_sig_ext, mul_sig, e_sig); // has 2 * sbits + 3
|
||||
m_simp.mk_ite(swap_cond, c_exp_ext, mul_exp, e_exp); // has ebits + 2
|
||||
m_simp.mk_ite(swap_cond, mul_sgn, c_sgn, f_sgn);
|
||||
m_simp.mk_ite(swap_cond, mul_sig, c_sig_ext, f_sig); // has 2 * sbits
|
||||
m_simp.mk_ite(swap_cond, mul_sig, c_sig_ext, f_sig); // has 2 * sbits + 3
|
||||
m_simp.mk_ite(swap_cond, mul_exp, c_exp_ext, f_exp); // has ebits + 2
|
||||
|
||||
SASSERT(is_well_sorted(m, e_sgn));
|
||||
|
@ -1563,8 +1564,8 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
|
|||
SASSERT(is_well_sorted(m, f_sig));
|
||||
SASSERT(is_well_sorted(m, f_exp));
|
||||
|
||||
SASSERT(m_bv_util.get_bv_size(e_sig) == 2 * sbits);
|
||||
SASSERT(m_bv_util.get_bv_size(f_sig) == 2 * sbits);
|
||||
SASSERT(m_bv_util.get_bv_size(e_sig) == 2 * sbits + 3);
|
||||
SASSERT(m_bv_util.get_bv_size(f_sig) == 2 * sbits + 3);
|
||||
SASSERT(m_bv_util.get_bv_size(e_exp) == ebits + 2);
|
||||
SASSERT(m_bv_util.get_bv_size(f_exp) == ebits + 2);
|
||||
|
||||
|
@ -1581,7 +1582,7 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
|
|||
|
||||
// cap the delta
|
||||
expr_ref cap(m), cap_le_delta(m);
|
||||
cap = m_bv_util.mk_numeral(2*sbits, ebits+2);
|
||||
cap = m_bv_util.mk_numeral(2*sbits+3, ebits+2);
|
||||
cap_le_delta = m_bv_util.mk_ule(cap, exp_delta);
|
||||
m_simp.mk_ite(cap_le_delta, cap, exp_delta, exp_delta);
|
||||
SASSERT(m_bv_util.get_bv_size(exp_delta) == ebits+2);
|
||||
|
@ -1593,14 +1594,14 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
|
|||
expr_ref alignment_sticky_raw(m), alignment_sticky(m);
|
||||
shifted_big = m_bv_util.mk_bv_lshr(
|
||||
m_bv_util.mk_concat(f_sig, m_bv_util.mk_numeral(0, sbits)),
|
||||
m_bv_util.mk_zero_extend((3*sbits)-(ebits+2), exp_delta));
|
||||
shifted_f_sig = m_bv_util.mk_extract(3*sbits-1, sbits, shifted_big);
|
||||
m_bv_util.mk_zero_extend((3*sbits+3)-(ebits+2), exp_delta));
|
||||
shifted_f_sig = m_bv_util.mk_extract(3*sbits-1+3, sbits, shifted_big);
|
||||
alignment_sticky_raw = m_bv_util.mk_extract(sbits-1, 0, shifted_big);
|
||||
alignment_sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, alignment_sticky_raw.get());
|
||||
dbg_decouple("fpa2bv_fma_shifted_f_sig", shifted_f_sig);
|
||||
dbg_decouple("fpa2bv_fma_f_sig_alignment_sticky", alignment_sticky);
|
||||
SASSERT(is_well_sorted(m, alignment_sticky));
|
||||
SASSERT(m_bv_util.get_bv_size(shifted_f_sig) == 2 * sbits);
|
||||
SASSERT(m_bv_util.get_bv_size(shifted_f_sig) == 2*sbits+3);
|
||||
SASSERT(is_well_sorted(m, shifted_f_sig));
|
||||
|
||||
// Significant addition.
|
||||
|
@ -1612,14 +1613,14 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
|
|||
m_simp.mk_eq(e_sgn, f_sgn, eq_sgn);
|
||||
dbg_decouple("fpa2bv_fma_eq_sgn", eq_sgn);
|
||||
|
||||
SASSERT(m_bv_util.get_bv_size(e_sig) == 2*sbits + 2);
|
||||
SASSERT(m_bv_util.get_bv_size(shifted_f_sig) == 2*sbits + 2);
|
||||
SASSERT(m_bv_util.get_bv_size(e_sig) == 2*sbits+2+3);
|
||||
SASSERT(m_bv_util.get_bv_size(shifted_f_sig) == 2*sbits+2+3);
|
||||
|
||||
dbg_decouple("fpa2bv_fma_add_e_sig", e_sig);
|
||||
dbg_decouple("fpa2bv_fma_add_shifted_f_sig", shifted_f_sig);
|
||||
|
||||
expr_ref sum(m), e_plus_f(m), e_minus_f(m), sticky_wide(m);
|
||||
sticky_wide = m_bv_util.mk_zero_extend(2*sbits+1, alignment_sticky);
|
||||
sticky_wide = m_bv_util.mk_zero_extend(2*sbits+1+3, alignment_sticky);
|
||||
e_plus_f = m_bv_util.mk_bv_add(e_sig, shifted_f_sig);
|
||||
e_plus_f = m.mk_ite(m.mk_eq(m_bv_util.mk_extract(0, 0, e_plus_f), zero_1),
|
||||
m_bv_util.mk_bv_add(e_plus_f, sticky_wide),
|
||||
|
@ -1632,12 +1633,12 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
|
|||
dbg_decouple("fpa2bv_fma_f_sig_or_sticky", shifted_f_sig);
|
||||
|
||||
m_simp.mk_ite(eq_sgn, e_plus_f, e_minus_f, sum);
|
||||
SASSERT(m_bv_util.get_bv_size(sum) == 2*sbits + 2);
|
||||
SASSERT(m_bv_util.get_bv_size(sum) == 2*sbits+2+3);
|
||||
SASSERT(is_well_sorted(m, sum));
|
||||
dbg_decouple("fpa2bv_fma_add_sum", sum);
|
||||
|
||||
expr_ref sign_bv(m), n_sum(m);
|
||||
sign_bv = m_bv_util.mk_extract(2*sbits+1, 2*sbits+1, sum);
|
||||
sign_bv = m_bv_util.mk_extract(2*sbits+1+3, 2*sbits+1+3, sum);
|
||||
n_sum = m_bv_util.mk_bv_neg(sum);
|
||||
dbg_decouple("fpa2bv_fma_add_sign_bv", sign_bv);
|
||||
dbg_decouple("fpa2bv_fma_add_n_sum", n_sum);
|
||||
|
@ -1661,14 +1662,14 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
|
|||
dbg_decouple("fpa2bv_fma_res_sgn", res_sgn);
|
||||
|
||||
expr_ref is_sig_neg(m);
|
||||
is_sig_neg = m.mk_eq(one_1, m_bv_util.mk_extract(2 * sbits + 1, 2 * sbits + 1, sig_abs));
|
||||
is_sig_neg = m.mk_eq(one_1, m_bv_util.mk_extract(2*sbits+1+3, 2*sbits+1+3, sig_abs));
|
||||
sig_abs = m.mk_ite(is_sig_neg, m_bv_util.mk_bv_neg(sig_abs), sig_abs);
|
||||
dbg_decouple("fpa2bv_fma_is_sig_neg", is_sig_neg);
|
||||
|
||||
// Result could have overflown into 4.xxx.
|
||||
SASSERT(m_bv_util.get_bv_size(sig_abs) == 2 * sbits + 2);
|
||||
SASSERT(m_bv_util.get_bv_size(sig_abs) == 2*sbits+2+3);
|
||||
expr_ref extra(m), extra_is_zero(m);
|
||||
extra = m_bv_util.mk_extract(2 * sbits + 1, 2 * sbits, sig_abs);
|
||||
extra = m_bv_util.mk_extract(2*sbits+1+3, 2*sbits+3, sig_abs);
|
||||
extra_is_zero = m.mk_eq(extra, m_bv_util.mk_numeral(0, 2));
|
||||
dbg_decouple("fpa2bv_fma_extra", extra);
|
||||
|
||||
|
@ -1685,7 +1686,7 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
|
|||
sig_lz_capped = m.mk_ite(m_bv_util.mk_sle(sig_lz, max_exp_delta), sig_lz, max_exp_delta);
|
||||
renorm_delta = m.mk_ite(m_bv_util.mk_sle(zero_e2, sig_lz_capped), sig_lz_capped, zero_e2);
|
||||
res_exp = m_bv_util.mk_bv_sub(res_exp, renorm_delta);
|
||||
sig_abs = m_bv_util.mk_bv_shl(sig_abs, m_bv_util.mk_zero_extend(2*sbits-ebits, renorm_delta));
|
||||
sig_abs = m_bv_util.mk_bv_shl(sig_abs, m_bv_util.mk_zero_extend(2*sbits+3-ebits, renorm_delta));
|
||||
dbg_decouple("fpa2bv_fma_min_exp", min_exp);
|
||||
dbg_decouple("fpa2bv_fma_max_exp_delta", max_exp_delta);
|
||||
dbg_decouple("fpa2bv_fma_sig_lz", sig_lz);
|
||||
|
@ -1699,26 +1700,26 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
|
|||
}
|
||||
|
||||
expr_ref sig_abs_h1(m), sticky_h1(m), sticky_h1_red(m), sig_abs_h1_f(m), res_sig_1(m);
|
||||
sticky_h1 = m_bv_util.mk_extract(sbits - 5 + too_short, 0, sig_abs);
|
||||
sig_abs_h1 = m_bv_util.mk_extract(2 * sbits + 1 + too_short, sbits - 4 + too_short, sig_abs);
|
||||
sticky_h1 = m_bv_util.mk_extract(sbits - 5 + too_short + 3, 0, sig_abs);
|
||||
sig_abs_h1 = m_bv_util.mk_extract(2 * sbits + 1 + too_short + 3, sbits - 4 + too_short + 3, sig_abs);
|
||||
sticky_h1_red = m_bv_util.mk_zero_extend(sbits + 5, m.mk_app(m_bv_util.get_fid(), OP_BREDOR, sticky_h1.get()));
|
||||
expr * sticky_h1_red_args[2] = { sig_abs_h1, sticky_h1_red };
|
||||
sig_abs_h1_f = m_bv_util.mk_bv_or(2, sticky_h1_red_args);
|
||||
res_sig_1 = m_bv_util.mk_extract(sbits + 3, 0, sig_abs_h1_f);
|
||||
SASSERT(m_bv_util.get_bv_size(sticky_h1) == sbits - 4 + too_short);
|
||||
SASSERT(m_bv_util.get_bv_size(sticky_h1) == sbits - 4 + too_short + 3);
|
||||
SASSERT(m_bv_util.get_bv_size(sig_abs_h1) == sbits + 6);
|
||||
SASSERT(m_bv_util.get_bv_size(sticky_h1_red) == sbits + 6);
|
||||
SASSERT(m_bv_util.get_bv_size(sig_abs_h1_f) == sbits + 6);
|
||||
SASSERT(m_bv_util.get_bv_size(res_sig_1) == sbits + 4);
|
||||
|
||||
expr_ref sig_abs_h2(m), sticky_h2(m), sticky_h2_red(m), sig_abs_h2_f(m), res_sig_2(m);
|
||||
sticky_h2 = m_bv_util.mk_extract(sbits - 4 + too_short, 0, sig_abs);
|
||||
sig_abs_h2 = m_bv_util.mk_extract(2 * sbits + 1 + too_short, sbits - 3 + too_short, sig_abs);
|
||||
sticky_h2 = m_bv_util.mk_extract(sbits - 4 + too_short + 3, 0, sig_abs);
|
||||
sig_abs_h2 = m_bv_util.mk_extract(2 * sbits + 1 + too_short + 3, sbits - 3 + too_short + 3, sig_abs);
|
||||
sticky_h2_red = m_bv_util.mk_zero_extend(sbits + 4, m.mk_app(m_bv_util.get_fid(), OP_BREDOR, sticky_h1.get()));
|
||||
expr * sticky_h2_red_args[2] = { sig_abs_h2, sticky_h2_red };
|
||||
sig_abs_h2_f = m_bv_util.mk_zero_extend(1, m_bv_util.mk_bv_or(2, sticky_h2_red_args));
|
||||
res_sig_2 = m_bv_util.mk_extract(sbits + 3, 0, sig_abs_h2_f);
|
||||
SASSERT(m_bv_util.get_bv_size(sticky_h2) == sbits - 3 + too_short);
|
||||
SASSERT(m_bv_util.get_bv_size(sticky_h2) == sbits - 3 + too_short + 3);
|
||||
SASSERT(m_bv_util.get_bv_size(sig_abs_h2) == sbits + 5);
|
||||
SASSERT(m_bv_util.get_bv_size(sticky_h2_red) == sbits + 5);
|
||||
SASSERT(m_bv_util.get_bv_size(sig_abs_h2_f) == sbits + 6);
|
||||
|
|
|
@ -840,16 +840,19 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co
|
|||
SASSERT(m_mpz_manager.lt(mr.significand(), m_powers2(2*x.sbits)));
|
||||
SASSERT(m_mpz_manager.ge(mr.significand(), m_powers2(2*x.sbits - 2)));
|
||||
|
||||
// Introduce extra bits into c in _[0].[sbits-1] s.t. c in _[0].[2*sbits-2]
|
||||
c.set(x.ebits+2, 2*x.sbits-1, c.sign(), c.exponent(), c.significand());
|
||||
m_mpz_manager.mul2k(c.significand(), x.sbits - 1);
|
||||
// Introduce (sbits+3) extra bits into c in _[0].[sbits-1] s.t. c in _[0].[2*sbits-2]
|
||||
c.set(x.ebits+2, 2*x.sbits-1+3, c.sign(), c.exponent(), c.significand());
|
||||
m_mpz_manager.mul2k(c.significand(), x.sbits - 1 + 3);
|
||||
// And + 3 bits into mr as well.
|
||||
mr.set(x.ebits + 2, 2 * x.sbits - 1 + 3, mr.sign(), mr.exponent(), mr.significand());
|
||||
m_mpz_manager.mul2k(mr.significand(), 3);
|
||||
|
||||
TRACE("mpf_dbg", tout << "C_= " << to_string(c) << std::endl;
|
||||
tout << "C_= " << to_string_binary(c, 1, 0) << std::endl;);
|
||||
|
||||
SASSERT(m_mpz_manager.lt(c.significand(), m_powers2(2*x.sbits)));
|
||||
SASSERT(m_mpz_manager.lt(c.significand(), m_powers2(2*x.sbits + 3)));
|
||||
SASSERT(m_mpz_manager.is_zero(c.significand()) ||
|
||||
m_mpz_manager.ge(c.significand(), m_powers2(2*x.sbits - 2)));
|
||||
m_mpz_manager.ge(c.significand(), m_powers2(2*x.sbits - 2 + 3)));
|
||||
|
||||
if (exp(c) > exp(mr)) {
|
||||
TRACE("mpf_dbg", tout << "Swap!" << std::endl;);
|
||||
|
@ -860,8 +863,8 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co
|
|||
mpf_exp_t exp_delta_w = exp(mr) - exp(c);
|
||||
SASSERT(exp(mr) >= exp(c) && exp_delta_w >= 0);
|
||||
|
||||
if (exp_delta_w > 2 * x.sbits)
|
||||
exp_delta_w = 2 * x.sbits;
|
||||
if (exp_delta_w > 2 * x.sbits + 3)
|
||||
exp_delta_w = 2 * x.sbits + 3;
|
||||
|
||||
unsigned exp_delta = (unsigned)exp_delta_w;
|
||||
|
||||
|
@ -905,8 +908,8 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co
|
|||
// Renormalize
|
||||
bool renorm_sticky = false;
|
||||
|
||||
SASSERT(m_mpz_manager.lt(res.significand(), m_powers2(2 * x.sbits + 1)));
|
||||
if (m_mpz_manager.ge(res.significand(), m_powers2(2 * x.sbits)))
|
||||
SASSERT(m_mpz_manager.lt(res.significand(), m_powers2(2 * x.sbits + 1 + 3)));
|
||||
if (m_mpz_manager.ge(res.significand(), m_powers2(2 * x.sbits + 3)))
|
||||
{
|
||||
SASSERT(exp(res) < mk_max_exp(x.ebits)); // NYI.
|
||||
|
||||
|
@ -919,7 +922,7 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co
|
|||
|
||||
mpf_exp_t min_exp = mk_min_exp(x.ebits);
|
||||
unsigned sig_width = m_mpz_manager.prev_power_of_two(res.get().significand) + 1;
|
||||
mpf_exp_t sig_lz = 2 * x.sbits - sig_width;
|
||||
mpf_exp_t sig_lz = 2 * x.sbits + 3 - sig_width;
|
||||
mpf_exp_t max_exp_delta = res.exponent() - min_exp;
|
||||
unsigned renorm_delta = (unsigned) std::max((mpf_exp_t)0, std::min(sig_lz, max_exp_delta));
|
||||
res.get().exponent -= renorm_delta;
|
||||
|
@ -930,11 +933,11 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co
|
|||
set(o, x.ebits, x.sbits, res.sign(), res.exponent(), mpz(0));
|
||||
|
||||
if (x.sbits >= 4) {
|
||||
m_mpz_manager.machine_div_rem(res.significand(), m_powers2(x.sbits - 4), o.significand, sticky_rem);
|
||||
m_mpz_manager.machine_div_rem(res.significand(), m_powers2(x.sbits - 4 + 3), o.significand, sticky_rem);
|
||||
renorm_sticky |= !m_mpz_manager.is_zero(sticky_rem);
|
||||
}
|
||||
else {
|
||||
m_mpz_manager.mul2k(res.significand(), 4 - x.sbits, o.significand);
|
||||
m_mpz_manager.mul2k(res.significand(), 4 - x.sbits + 3, o.significand);
|
||||
}
|
||||
|
||||
if (renorm_sticky && m_mpz_manager.is_even(o.significand))
|
||||
|
|
Loading…
Reference in a new issue