///|
let py_hash_modulus : BigInt = 2305843009213693951N
///|
let py_hash_bits : Int = 61
///|
let py_hash_inf : Int = 314159
///|
let py_hash_nan : Int = 0
///|
let mpf_rand_gen : @random.Rand = @random.Rand::new()
///|
fn hash_exp_shift(exp : Int) -> Int {
if exp >= 0 {
exp % py_hash_bits
} else {
py_hash_bits - 1 - (-1 - exp) % py_hash_bits
}
}
///|
pub fn mpf_frexp(x : RawMpf) -> (RawMpf, Int) raise MpfError {
if is_zero(x) {
(fzero, 0)
} else if !is_finite(x) {
raise DomainError("mpf_frexp: non-finite input")
} else {
let n = x.bc + x.exp
(mpf_shift(x, -n), n)
}
}
///|
pub fn mpf_hash(x : RawMpf) -> Int {
if is_nan(x) {
return py_hash_nan
}
if x == finf {
return py_hash_inf
}
if x == fninf {
return -py_hash_inf
}
if is_zero(x) {
return 0
}
let mut h = x.man % py_hash_modulus
let shift = hash_exp_shift(x.exp)
h = (h << shift) % py_hash_modulus
if x.sign == 1 {
h = -h
}
if h == -1N {
-2
} else {
h.to_int()
}
}
///|
pub fn mpf_perturb(
x : RawMpf,
eps_sign : Int,
prec : Int,
rnd : RoundMode,
) -> RawMpf {
if rnd == round_nearest {
return mpf_pos(x, prec, rnd)
}
let perturb_sign = if eps_sign == 0 { 0 } else { 1 }
let eps : RawMpf = {
sign: perturb_sign,
man: 1N,
exp: x.exp + x.bc - prec - 1,
bc: 1,
}
let eps_is_negative = perturb_sign == 1
let away = if x.sign == 1 {
(rnd == round_down || rnd == round_ceiling) != eps_is_negative
} else {
(rnd == round_up || rnd == round_ceiling) != eps_is_negative
}
if away {
mpf_add(x, eps, prec, rnd)
} else {
mpf_pos(x, prec, rnd)
}
}
///|
pub fn mpf_rand(prec : Int) -> RawMpf {
if prec <= 0 {
return fzero
}
let man = mpf_rand_gen.bigint(prec)
from_man_exp(man, -prec, prec, round_floor)
}