From 175f042db88bcbd8f2ce21316fb5c321355d601a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 28 Jul 2017 23:01:01 +0100 Subject: [PATCH] Fixed renormalization in fp.fma. Relates to #872. --- src/ast/fpa/fpa2bv_converter.cpp | 17 ++++++++++++++++- src/util/mpf.cpp | 11 +++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 979fed78e..0c9a1c866 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1672,6 +1672,22 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, extra_is_zero = m.mk_eq(extra, m_bv_util.mk_numeral(0, 2)); dbg_decouple("fpa2bv_fma_extra", extra); + res_exp = m.mk_ite(extra_is_zero, e_exp, m_bv_util.mk_bv_add(e_exp, m_bv_util.mk_numeral(1, ebits + 2))); + + // Renormalize + expr_ref zero_e2(m), min_exp(m), sig_lz(m), max_exp_delta(m), sig_lz_capped(m), renorm_delta(m); + zero_e2 = m_bv_util.mk_numeral(0, ebits + 2); + mk_min_exp(ebits+2, min_exp); + mk_leading_zeros(sig_abs, ebits+2, sig_lz); + sig_lz = m_bv_util.mk_bv_sub(sig_lz, m_bv_util.mk_numeral(2, ebits+2)); + max_exp_delta = m_bv_util.mk_bv_sub(res_exp, min_exp); + 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)); + dbg_decouple("fpa2bv_fma_sig_lz", sig_lz); + dbg_decouple("fpa2bv_fma_renorm_delta", renorm_delta); + unsigned too_short = 0; if (sbits < 5) { too_short = 6 - sbits + 1; @@ -1705,7 +1721,6 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, SASSERT(m_bv_util.get_bv_size(res_sig_2) == sbits + 4); res_sig = m.mk_ite(extra_is_zero, res_sig_1, res_sig_2); - res_exp = m.mk_ite(extra_is_zero, e_exp, m_bv_util.mk_bv_add(e_exp, m_bv_util.mk_numeral(1, ebits + 2))); dbg_decouple("fpa2bv_fma_res_sig", res_sig); dbg_decouple("fpa2bv_fma_res_exp", res_exp); diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index be19cbb9b..a2bf12a30 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -902,6 +902,7 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co TRACE("mpf_dbg", tout << "S'= " << m_mpz_manager.to_string(res.significand()) << std::endl; tout << "S'= " << to_string_binary(res, 1, 0) << std::endl; ); + // Renormalize bool renorm_sticky = false; SASSERT(m_mpz_manager.lt(res.significand(), m_powers2(2 * x.sbits + 1))); @@ -916,6 +917,16 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co tout << "S*= " << to_string_binary(res, 2, 0) << std::endl;); } + 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; // want << lz + 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; + m_mpz_manager.mul2k(res.significand(), renorm_delta); + + TRACE("mpf_dbg", tout << "R*= " << to_string_binary(res, 2, 0) << " (renormalized, delta=" << renorm_delta << ")" << std::endl;); + set(o, x.ebits, x.sbits, res.sign(), res.exponent(), mpz(0)); if (x.sbits >= 4) {