///|
fn ceil_rshift(man : BigInt, n : Int) -> BigInt {
if n <= 0 {
man
} else {
(man + ((1N << n) - 1N)) >> n
}
}
///|
fn should_shift_down(rnd : RoundMode, sign : Int) -> Bool {
match rnd {
Floor => sign == 0
Ceiling => sign == 1
Down => true
Up => false
Nearest => true
}
}
///|
fn round_mantissa(sign : Int, man : BigInt, n : Int, rnd : RoundMode) -> BigInt {
if n <= 0 {
man
} else {
match rnd {
Nearest => {
let t = man >> (n - 1)
let sticky_mask = (1N << (n - 1)) - 1N
let tie_break = (t & 2N) == 2N
let sticky = (man & sticky_mask) != 0N
if (t & 1N) == 1N && (tie_break || sticky) {
(t >> 1) + 1N
} else {
t >> 1
}
}
_ =>
if should_shift_down(rnd, sign) {
man >> n
} else {
ceil_rshift(man, n)
}
}
}
}
///|
pub fn normalize(
sign : Int,
man : BigInt,
exp : Int,
bc : Int,
prec : Int,
rnd : RoundMode,
) -> RawMpf {
if man == 0N {
fzero
} else {
let mut m = man
let mut e = exp
let mut bits = bc
if prec > 0 {
let cut = bits - prec
if cut > 0 {
m = round_mantissa(sign, m, cut, rnd)
e += cut
}
}
if m == 0N {
fzero
} else {
if (m & 1N) == 0N {
let t = m.ctz()
m = m >> t
e += t
}
bits = m.bit_length()
{ sign, man: m, exp: e, bc: bits }
}
}
}
///|
pub fn from_man_exp(
man : BigInt,
exp : Int,
prec : Int,
rnd : RoundMode,
) -> RawMpf {
if man == 0N {
fzero
} else {
let sign = if man < 0N { 1 } else { 0 }
let abs_man = if sign == 1 { -man } else { man }
let bc = abs_man.bit_length()
if prec <= 0 {
normalize(sign, abs_man, exp, bc, 0, rnd)
} else {
normalize(sign, abs_man, exp, bc, prec, rnd)
}
}
}
///|
pub fn from_int(n : Int) -> RawMpf {
from_man_exp(BigInt::from_int(n), 0, 0, round_down)
}
///|
pub fn is_zero(x : RawMpf) -> Bool {
x.man == 0N && x.bc == 0
}
///|
pub fn is_finite(x : RawMpf) -> Bool {
x.bc >= 0
}
///|
pub fn is_inf(x : RawMpf) -> Bool {
x.bc == -2 || x.bc == -3
}
///|
pub fn is_nan(x : RawMpf) -> Bool {
x.bc == -1
}