The mk_to_real function in fpa2bv_converter.cpp incorrectly computed the
exponent scaling factor for floats with negative exponents. The code was
computing 2^(1/|exp|) instead of 1/(2^|exp|) = 2^(-|exp|).
Root cause: after the loop that computed exp2 = |unbiased_exp| as an integer,
the code did:
one_div_exp2 = 1/exp2 (computed 1/|exp|, NOT 1/2^|exp|)
exp2 = ite(exp_is_neg, one_div_exp2, exp2)
two_exp2 = mk_power(two, exp2) -> gives 2^(1/|exp|) for negative exp
For example, for exp=-3 (as in Float32(0xBE7BE653)):
OLD (buggy): two_exp2 = 2^(1/3) ≈ 1.26 (wrong)
NEW (fixed): two_exp2 = 1/8 (correct: 2^(-3) = 1/8)
Fix: compute two_exp2 = 2^|exp| first, then use 1/two_exp2 for negative exponents:
two_exp2 = mk_power(two, exp2) (2^|exp|)
one_div_two_exp2 = 1/two_exp2 (1/2^|exp| = 2^(-|exp|))
two_exp2 = ite(exp_is_neg, one_div_two_exp2, two_exp2)
This bug affected:
1. QF_FPLRA: to_fp(RTZ, r) for symbolic real r in an interval containing
the exact rational value of a float returned UNSAT instead of SAT
2. fp.to_real: incorrect results for floats with negative exponents,
including denormals (which had the same issue via the lz subtraction)
Adds regression test in src/test/fpa.cpp for the to_fp (from real) case.
Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/56265d81-608a-4768-8c4d-30bd740d89fb
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
The mk_to_real function in fpa2bv_converter.cpp was missing the
normalization shift adjustment (lz) when computing the real-valued
exponent for denormal floating-point numbers.
When unpack(x, sgn, sig, exp, lz, normalize=true) normalizes a denormal
by shifting the significand left by lz positions, the returned exp does
not account for this shift. All other callers (mk_mul, mk_div, mk_fma)
correctly subtract lz from the exponent, but mk_to_real was missing this.
The fix subtracts zero-extended lz from the sign-extended exp to get the
true exponent, matching the convention used by other FP operations.
Fixes incorrect model with (_ FloatingPoint 2 24) and fp.to_real.
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
* Initial plan
* Add std::initializer_list overloads for BV and arith functions
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
* Update call sites to use initializer_list format for BV and arith functions
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
* Introduce X-macro-based trace tag definition
- Created trace_tags.def to centralize TRACE tag definitions
- Each tag includes a symbolic name and description
- Set up enum class TraceTag for type-safe usage in TRACE macros
* Add script to generate Markdown documentation from trace_tags.def
- Python script parses trace_tags.def and outputs trace_tags.md
* Refactor TRACE_NEW to prepend TraceTag and pass enum to is_trace_enabled
* trace: improve trace tag handling system with hierarchical tagging
- Introduce hierarchical tag-class structure: enabling a tag class activates all child tags
- Unify TRACE, STRACE, SCTRACE, and CTRACE under enum TraceTag
- Implement initial version of trace_tag.def using X(tag, tag_class, description)
(class names and descriptions to be refined in a future update)
* trace: replace all string-based TRACE tags with enum TraceTag
- Migrated all TRACE, STRACE, SCTRACE, and CTRACE macros to use enum TraceTag values instead of raw string literals
* trace : add cstring header
* trace : Add Markdown documentation generation from trace_tags.def via mk_api_doc.py
* trace : rename macro parameter 'class' to 'tag_class' and remove Unicode comment in trace_tags.h.
* trace : Add TODO comment for future implementation of tag_class activation
* trace : Disable code related to tag_class until implementation is ready (#7663).
* Improve 4be26eb543
* Add-on to 0f4f32c5d0
* Fix mk_numeral
* Fix corner-case in fp.div
* Fixes for corner-cases in mk_to_fp_(un)signed
* Fix out-of-range results in mpf_manager::fma
* Further adjustments for fp.to_fp_(un)signed
* fp.to_fp from real can't be NaN
* fp.to_fp from reals: add bounds
* Fix NaN encodings in theory_fpa.
* Fix fp.fma rounding with tiny floats
* Fix literal creation order in theory_fpa