///|
fn signed_man(x : RawMpf) -> BigInt {
if x.sign == 0 {
x.man
} else {
-x.man
}
}
///|
fn inf_with_sign(sign : Int) -> RawMpf {
if sign == 1 {
fninf
} else {
finf
}
}
///|
fn xor_sign(x : RawMpf, y : RawMpf) -> Int {
if x.sign == y.sign {
0
} else {
1
}
}
///|
fn negated(x : RawMpf) -> RawMpf {
if is_nan(x) {
fnan
} else if is_inf(x) {
if x.sign == 1 {
finf
} else {
fninf
}
} else if is_zero(x) {
x
} else {
{ sign: 1 - x.sign, man: x.man, exp: x.exp, bc: x.bc }
}
}
///|
pub fn mpf_add(x : RawMpf, y : RawMpf, prec : Int, rnd : RoundMode) -> RawMpf {
if is_nan(x) || is_nan(y) {
return fnan
}
if is_inf(x) || is_inf(y) {
if is_inf(x) && is_inf(y) {
if x.sign == y.sign {
return inf_with_sign(x.sign)
}
return fnan
}
if is_inf(x) {
return inf_with_sign(x.sign)
}
return inf_with_sign(y.sign)
}
if is_zero(x) {
return normalize(y.sign, y.man, y.exp, y.bc, prec, rnd)
}
if is_zero(y) {
return normalize(x.sign, x.man, x.exp, x.bc, prec, rnd)
}
let xm = signed_man(x)
let ym = signed_man(y)
if x.exp >= y.exp {
let delta = x.exp - y.exp
from_man_exp((xm << delta) + ym, y.exp, prec, rnd)
} else {
let delta = y.exp - x.exp
from_man_exp(xm + (ym << delta), x.exp, prec, rnd)
}
}
///|
pub fn mpf_sub(x : RawMpf, y : RawMpf, prec : Int, rnd : RoundMode) -> RawMpf {
mpf_add(x, negated(y), prec, rnd)
}
///|
pub fn mpf_mul(x : RawMpf, y : RawMpf, prec : Int, rnd : RoundMode) -> RawMpf {
if is_nan(x) || is_nan(y) {
return fnan
}
if is_inf(x) || is_inf(y) {
if is_zero(x) || is_zero(y) {
return fnan
}
return inf_with_sign(xor_sign(x, y))
}
if is_zero(x) || is_zero(y) {
return fzero
}
let sign = xor_sign(x, y)
let man = x.man * y.man
normalize(sign, man, x.exp + y.exp, man.bit_length(), prec, rnd)
}
///|
pub fn mpf_div(
x : RawMpf,
y : RawMpf,
prec : Int,
rnd : RoundMode,
) -> RawMpf raise MpfError {
if is_nan(x) || is_nan(y) {
return fnan
}
if is_zero(x) {
if is_zero(y) {
raise DivisionByZero("mpf_div: division by zero")
}
return fzero
}
if is_zero(y) {
raise DivisionByZero("mpf_div: division by zero")
}
if is_inf(x) && is_inf(y) {
return fnan
}
if is_inf(x) {
return inf_with_sign(xor_sign(x, y))
}
if is_inf(y) {
return fzero
}
let target_prec = if prec > 0 { prec } else { 1 }
let sign = xor_sign(x, y)
let d = y.bc - x.bc + 1
let extra = if d > 0 { d } else { 0 }
let p = target_prec + 8 + extra
let num = x.man << p
let q = num / y.man
let r = num % y.man
let sticky = if r == 0N { 0N } else { 1N }
let man = (q << 1) + sticky
let exp = x.exp - y.exp - p - 1
normalize(sign, man, exp, man.bit_length(), target_prec, rnd)
}