mirror of
https://github.com/Z3Prover/z3
synced 2025-04-15 05:18:44 +00:00
330 lines
11 KiB
C++
330 lines
11 KiB
C++
/*++
|
|
Copyright (c) 2011 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
mpf.h
|
|
|
|
Abstract:
|
|
|
|
Multi Precision Floating Point Numbers
|
|
|
|
Author:
|
|
|
|
Christoph Wintersteiger (cwinter) 2011-12-01.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#ifndef MPF_H_
|
|
#define MPF_H_
|
|
|
|
#include<string>
|
|
#include "util/mpz.h"
|
|
#include "util/mpq.h"
|
|
#include "util/map.h"
|
|
#include "util/scoped_numeral.h"
|
|
#include "util/scoped_numeral_vector.h"
|
|
#include "util/hash.h"
|
|
|
|
typedef enum {
|
|
MPF_ROUND_NEAREST_TEVEN,
|
|
MPF_ROUND_NEAREST_TAWAY,
|
|
MPF_ROUND_TOWARD_POSITIVE,
|
|
MPF_ROUND_TOWARD_NEGATIVE,
|
|
MPF_ROUND_TOWARD_ZERO
|
|
} mpf_rounding_mode;
|
|
|
|
typedef int64_t mpf_exp_t;
|
|
|
|
class mpf {
|
|
friend class mpf_manager;
|
|
friend class scoped_mpf;
|
|
unsigned ebits:15;
|
|
unsigned sbits:16;
|
|
unsigned sign:1; // counts as one sbit.
|
|
mpz significand;
|
|
mpf_exp_t exponent;
|
|
mpf & operator=(mpf const & other) { UNREACHABLE(); return *this; }
|
|
void set(unsigned _ebits, unsigned _sbits);
|
|
public:
|
|
mpf();
|
|
mpf(unsigned ebits, unsigned sbits);
|
|
mpf(mpf && other) :
|
|
ebits(other.ebits),
|
|
sbits(other.sbits),
|
|
sign(other.sign),
|
|
significand(std::move(other.significand)),
|
|
exponent(other.exponent) {}
|
|
~mpf();
|
|
unsigned get_ebits() const { return ebits; }
|
|
unsigned get_sbits() const { return sbits; }
|
|
void swap(mpf & other);
|
|
};
|
|
|
|
class mpf_manager {
|
|
unsynch_mpq_manager m_mpq_manager;
|
|
unsynch_mpz_manager & m_mpz_manager; // A mpq_manager is a mpz_manager, reusing it.
|
|
|
|
public:
|
|
typedef mpf numeral;
|
|
|
|
mpf_manager();
|
|
~mpf_manager();
|
|
|
|
void reset(mpf & o, unsigned ebits, unsigned sbits) { set(o, ebits, sbits, 0); }
|
|
void set(mpf & o, unsigned ebits, unsigned sbits, int value);
|
|
void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, int n, int d);
|
|
void set(mpf & o, unsigned ebits, unsigned sbits, float value);
|
|
void set(mpf & o, unsigned ebits, unsigned sbits, double value);
|
|
void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, mpq const & value);
|
|
void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, char const * value);
|
|
void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, mpz const & exponent, mpq const & significand);
|
|
void set(mpf & o, unsigned ebits, unsigned sbits, bool sign, mpf_exp_t exponent, uint64_t significand);
|
|
void set(mpf & o, unsigned ebits, unsigned sbits, bool sign, mpf_exp_t exponent, mpz const & significand);
|
|
void set(mpf & o, mpf const & x);
|
|
void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, mpf const & x);
|
|
|
|
void del(mpf & x) {
|
|
m_mpz_manager.del(x.significand);
|
|
}
|
|
|
|
void abs(mpf & o);
|
|
void abs(mpf const & x, mpf & o);
|
|
|
|
void neg(mpf & o);
|
|
void neg(mpf const & x, mpf & o);
|
|
|
|
bool is_zero(mpf const & x);
|
|
bool is_neg(mpf const & x);
|
|
bool is_pos(mpf const & x);
|
|
bool is_one(mpf const & x);
|
|
|
|
bool is_nzero(mpf const & x);
|
|
bool is_pzero(mpf const & x);
|
|
|
|
// structural eq
|
|
bool eq_core(mpf const & x, mpf const & y) {
|
|
return
|
|
x.ebits == y.ebits &&
|
|
x.sbits == y.sbits &&
|
|
x.sign == y.sign &&
|
|
m_mpz_manager.eq(x.significand, y.significand) &&
|
|
x.exponent == y.exponent;
|
|
}
|
|
|
|
bool eq(mpf const & x, mpf const & y);
|
|
bool lt(mpf const & x, mpf const & y);
|
|
bool lte(mpf const & x, mpf const & y);
|
|
bool le(mpf const & x, mpf const & y) { return lte(x, y); }
|
|
bool gt(mpf const & x, mpf const & y);
|
|
bool gte(mpf const & x, mpf const & y);
|
|
bool ge(mpf const & x, mpf const & y) { return gte(x, y); }
|
|
|
|
void add(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & o);
|
|
void sub(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & o);
|
|
void mul(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & o);
|
|
void div(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & o);
|
|
|
|
void fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf const &z, mpf & o);
|
|
|
|
void sqrt(mpf_rounding_mode rm, mpf const & x, mpf & o);
|
|
|
|
void round_to_integral(mpf_rounding_mode rm, mpf const & x, mpf & o);
|
|
|
|
void rem(mpf const & x, mpf const & y, mpf & o);
|
|
|
|
void maximum(mpf const & x, mpf const & y, mpf & o);
|
|
void minimum(mpf const & x, mpf const & y, mpf & o);
|
|
|
|
std::string to_string(mpf const & a);
|
|
std::string to_rational_string(mpf const & a);
|
|
void display_decimal(std::ostream & out, mpf const & a, unsigned k);
|
|
void display_smt2(std::ostream & out, mpf const & a, bool decimal);
|
|
|
|
// Convert x into a mpq numeral. zm is the manager that owns o.
|
|
void to_rational(mpf const & x, unsynch_mpq_manager & qm, mpq & o);
|
|
void to_rational(mpf const & x, scoped_mpq & o) { to_rational(x, o.m(), o); }
|
|
|
|
double to_double(mpf const & x);
|
|
float to_float(mpf const & x);
|
|
|
|
bool sgn(mpf const & x) const { return x.sign; }
|
|
const mpz & sig(mpf const & x) const { return x.significand; }
|
|
void sig_normalized(mpf const & x, mpz & res) {
|
|
mpf t;
|
|
set(t, x);
|
|
unpack(t, true);
|
|
mpz_manager().set(res, t.significand);
|
|
del(t);
|
|
}
|
|
const mpf_exp_t & exp(mpf const & x) const { return x.exponent; }
|
|
mpf_exp_t exp_normalized(mpf const & x) {
|
|
if (is_zero(x))
|
|
return 0;
|
|
else {
|
|
mpf t;
|
|
set(t, x);
|
|
unpack(t, true);
|
|
mpf_exp_t r = t.exponent;
|
|
del(t);
|
|
return r;
|
|
}
|
|
}
|
|
|
|
bool is_nan(mpf const & x);
|
|
bool is_inf(mpf const & x);
|
|
bool is_pinf(mpf const & x);
|
|
bool is_ninf(mpf const & x);
|
|
bool is_normal(mpf const & x);
|
|
bool is_denormal(mpf const & x);
|
|
bool is_regular(mpf const & x) { return x.sbits == 0 || is_normal(x) || is_denormal(x); }
|
|
|
|
bool is_int(mpf const & x);
|
|
|
|
void mk_zero(unsigned ebits, unsigned sbits, bool sign, mpf & o);
|
|
void mk_nzero(unsigned ebits, unsigned sbits, mpf & o);
|
|
void mk_pzero(unsigned ebits, unsigned sbits, mpf & o);
|
|
void mk_nan(unsigned ebits, unsigned sbits, mpf & o);
|
|
void mk_inf(unsigned ebits, unsigned sbits, bool sign, mpf & o);
|
|
void mk_pinf(unsigned ebits, unsigned sbits, mpf & o);
|
|
void mk_ninf(unsigned ebits, unsigned sbits, mpf & o);
|
|
|
|
unsynch_mpz_manager & mpz_manager() { return m_mpz_manager; }
|
|
unsynch_mpq_manager & mpq_manager() { return m_mpq_manager; }
|
|
|
|
unsigned hash(mpf const & a) {
|
|
return hash_u_u(m_mpz_manager.hash(a.significand),
|
|
m_mpz_manager.hash(hash_ull(a.exponent)));
|
|
}
|
|
|
|
void mk_max_value(unsigned ebits, unsigned sbits, bool sign, mpf & o);
|
|
mpf_exp_t mk_bot_exp(unsigned ebits);
|
|
mpf_exp_t mk_top_exp(unsigned ebits);
|
|
mpf_exp_t mk_max_exp(unsigned ebits);
|
|
mpf_exp_t mk_min_exp(unsigned ebits);
|
|
|
|
mpf_exp_t bias_exp(unsigned ebits, mpf_exp_t unbiased_exponent);
|
|
mpf_exp_t unbias_exp(unsigned ebits, mpf_exp_t biased_exponent);
|
|
|
|
/**
|
|
\brief Return the biggest k s.t. 2^k <= a.
|
|
|
|
\remark Return 0 if a is not positive.
|
|
*/
|
|
unsigned prev_power_of_two(mpf const & a);
|
|
|
|
void to_sbv_mpq(mpf_rounding_mode rm, const mpf & x, scoped_mpq & o);
|
|
void to_ieee_bv_mpz(const mpf & x, scoped_mpz & o);
|
|
|
|
protected:
|
|
void mk_one(unsigned ebits, unsigned sbits, bool sign, mpf & o) const;
|
|
|
|
bool has_bot_exp(mpf const & x);
|
|
bool has_top_exp(mpf const & x);
|
|
|
|
void unpack(mpf & o, bool normalize);
|
|
void add_sub(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & o, bool sub);
|
|
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.
|
|
void to_mpz(mpf const & x, unsynch_mpz_manager & zm, mpz & o);
|
|
void to_mpz(mpf const & x, scoped_mpz & o) { to_mpz(x, o.m(), o); }
|
|
|
|
class powers2 {
|
|
unsynch_mpz_manager & m;
|
|
u_map<mpz*> m_p;
|
|
u_map<mpz*> m_pn;
|
|
u_map<mpz*> m_pm1;
|
|
u_map<mpz*> m_pm1n;
|
|
public:
|
|
powers2(unsynch_mpz_manager & m) : m(m) {}
|
|
~powers2() {
|
|
dispose(m_p);
|
|
dispose(m_pn);
|
|
dispose(m_pm1);
|
|
dispose(m_pm1n);
|
|
}
|
|
|
|
void dispose(u_map<mpz*> & map) {
|
|
for (u_map<mpz*>::iterator it = map.begin(); it != map.end(); it++) {
|
|
m.del(*it->m_value);
|
|
dealloc(it->m_value);
|
|
}
|
|
}
|
|
|
|
const mpz & operator()(unsigned n, bool negated = false) {
|
|
u_map<mpz*> & map = (negated) ? m_pn : m_p;
|
|
u_map<mpz*>::iterator it = map.find_iterator(n);
|
|
if (it != map.end())
|
|
return *it->m_value;
|
|
else {
|
|
mpz * new_obj = alloc(mpz);
|
|
map.insert(n, new_obj);
|
|
m.power(unsynch_mpz_manager::mk_z(2), n, *new_obj);
|
|
if (negated) m.neg(*new_obj);
|
|
return *new_obj;
|
|
}
|
|
}
|
|
|
|
const mpz & m1(unsigned n, bool negated=false) { // (2 ^ n) - 1
|
|
u_map<mpz*> & map = (negated) ? m_pm1n : m_pm1;
|
|
u_map<mpz*>::iterator it = map.find_iterator(n);
|
|
if (it != map.end())
|
|
return *it->m_value;
|
|
else {
|
|
mpz * new_obj = alloc(mpz);
|
|
map.insert(n, new_obj);
|
|
m.power(unsynch_mpz_manager::mk_z(2), n, *new_obj);
|
|
m.dec(*new_obj);
|
|
if (negated) m.neg(*new_obj);
|
|
return *new_obj;
|
|
}
|
|
}
|
|
};
|
|
|
|
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);
|
|
std::string to_string_binary(mpf const & x, unsigned upper_extra, unsigned lower_extra);
|
|
public:
|
|
powers2 m_powers2;
|
|
};
|
|
|
|
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; }
|
|
void set(unsigned ebits, unsigned sbits) { get().set(ebits, sbits); }
|
|
void set(unsigned ebits, unsigned sbits, bool sign, mpf_exp_t exp, mpz & significand) {
|
|
get().set(ebits, sbits);
|
|
get().exponent = exp;
|
|
get().sign = sign;
|
|
if (&get().significand != &significand)
|
|
m().mpz_manager().set(get().significand, significand);
|
|
}
|
|
void set(unsigned ebits, unsigned sbits, bool sign, mpf_exp_t exp) {
|
|
get().set(ebits, sbits);
|
|
get().exponent = exp;
|
|
get().sign = sign;
|
|
m().mpz_manager().set(get().significand, 0);
|
|
}
|
|
public:
|
|
scoped_mpf(mpf_manager & m):_scoped_numeral<mpf_manager>(m) {}
|
|
scoped_mpf(scoped_mpf const & n):_scoped_numeral<mpf_manager>(n) {}
|
|
scoped_mpf(mpf_manager & m, unsigned ebits, unsigned sbits):_scoped_numeral<mpf_manager>(m) { set(ebits, sbits); }
|
|
};
|
|
|
|
typedef _scoped_numeral_vector<mpf_manager> scoped_mpf_vector;
|
|
|
|
#endif
|