///|
/// Minimal arbitrary-precision complex floating literal backed by `symnum`'s
/// mpmath-compatible `Mpc`.
pub struct ComplexFloat {
value : @symnum.Mpc
prec : Int
} derive(Eq)
///|
fn complex_float_default_prec(prec : Int) -> Int {
if prec > 0 {
prec
} else {
53
}
}
///|
fn complex_common_prec(lhs : ComplexFloat, rhs : ComplexFloat) -> Int {
if lhs.precision() > rhs.precision() {
lhs.precision()
} else {
rhs.precision()
}
}
///|
fn complex_promote(value : ComplexFloat, prec : Int) -> ComplexFloat {
if value.precision() >= prec {
value
} else {
ComplexFloat::from_parts(
@symnum.mpf_pos(value.to_mpc().real, prec, @symnum.round_nearest),
@symnum.mpf_pos(value.to_mpc().imag, prec, @symnum.round_nearest),
prec~,
)
}
}
///|
pub fn ComplexFloat::from_mpc(
value : @symnum.Mpc,
prec? : Int = 53,
) -> ComplexFloat {
{ value, prec: complex_float_default_prec(prec) }
}
///|
pub fn ComplexFloat::from_parts(
real : @symnum.Mpf,
imag : @symnum.Mpf,
prec? : Int = 53,
) -> ComplexFloat {
let p = complex_float_default_prec(prec)
{ value: @symnum.make_mpc(real, imag~), prec: p }
}
///|
pub fn ComplexFloat::from_real(
real : Float,
imag? : Float = Float::from_int(0),
) -> ComplexFloat {
let p = if real.precision() > imag.precision() {
real.precision()
} else {
imag.precision()
}
{
value: @symnum.make_mpc(
@symnum.mpf_pos(real.to_mpf(), p, @symnum.round_nearest),
imag=@symnum.mpf_pos(imag.to_mpf(), p, @symnum.round_nearest),
),
prec: p,
}
}
///|
pub fn ComplexFloat::from_exact_parts(
real : @symnum.BigRational,
imag : @symnum.BigRational,
prec? : Int = 53,
) -> ComplexFloat {
let p = complex_float_default_prec(prec)
let real_float = Float::from_exact(real, prec=p) catch {
_ => Float::from_mpf(@symnum.fnan, prec=p)
}
let imag_float = Float::from_exact(imag, prec=p) catch {
_ => Float::from_mpf(@symnum.fnan, prec=p)
}
ComplexFloat::from_real(real_float, imag=imag_float)
}
///|
pub fn ComplexFloat::to_mpc(self : ComplexFloat) -> @symnum.Mpc {
self.value
}
///|
pub fn ComplexFloat::precision(self : ComplexFloat) -> Int {
self.prec
}
///|
pub fn ComplexFloat::real_part(self : ComplexFloat) -> Float {
Float::from_mpf(
@symnum.mpf_pos(self.value.real, self.prec, @symnum.round_nearest),
prec=self.prec,
)
}
///|
pub fn ComplexFloat::imag_part(self : ComplexFloat) -> Float {
Float::from_mpf(
@symnum.mpf_pos(self.value.imag, self.prec, @symnum.round_nearest),
prec=self.prec,
)
}
///|
pub fn ComplexFloat::is_finite(self : ComplexFloat) -> Bool {
@symnum.is_finite(self.value.real) && @symnum.is_finite(self.value.imag)
}
///|
pub fn ComplexFloat::to_rational_parts(
self : ComplexFloat,
) -> ((BigInt, BigInt), (BigInt, BigInt)) raise @symnum.MpfError {
(@symnum.to_rational(self.value.real), @symnum.to_rational(self.value.imag))
}
///|
pub fn ComplexFloat::format(self : ComplexFloat, dps? : Int) -> String {
let digits = match dps {
Some(v) if v > 0 => v
_ => @symnum.repr_dps(self.prec)
}
let real_s = self.real_part().format(dps=digits)
let imag_s = self.imag_part().format(dps=digits)
if @symnum.is_zero(self.value.imag) {
real_s
} else if @symnum.is_zero(self.value.real) {
"\{imag_s}*I"
} else if @symnum.mpf_sign(self.value.imag) < 0 {
let imag_abs = Float::from_mpf(
@symnum.mpf_abs(self.value.imag, self.prec, @symnum.round_nearest),
prec=self.prec,
)
"\{real_s} - \{imag_abs.format(dps=digits)}*I"
} else {
"\{real_s} + \{imag_s}*I"
}
}
///|
pub fn ComplexFloat::reciprocal(self : ComplexFloat) -> ComplexFloat {
ComplexFloat::from_mpc(
@symnum.mpc_div(
@symnum.make_mpc(@symnum.fone, imag=@symnum.fzero),
self.value,
self.prec,
@symnum.round_nearest,
),
prec=self.prec,
)
}
///|
pub impl Add for ComplexFloat with add(self, other : ComplexFloat) -> ComplexFloat {
let p = complex_common_prec(self, other)
let lhs = complex_promote(self, p)
let rhs = complex_promote(other, p)
ComplexFloat::from_mpc(
@symnum.mpc_add(lhs.to_mpc(), rhs.to_mpc(), p, @symnum.round_nearest),
prec=p,
)
}
///|
pub impl Mul for ComplexFloat with mul(self, other : ComplexFloat) -> ComplexFloat {
let p = complex_common_prec(self, other)
let lhs = complex_promote(self, p)
let rhs = complex_promote(other, p)
ComplexFloat::from_mpc(
@symnum.mpc_mul(lhs.to_mpc(), rhs.to_mpc(), p, @symnum.round_nearest),
prec=p,
)
}
///|
pub impl Neg for ComplexFloat with neg(self) -> ComplexFloat {
ComplexFloat::from_mpc(
@symnum.mpc_neg(self.to_mpc(), self.prec, @symnum.round_nearest),
prec=self.prec,
)
}
///|
pub impl Show for ComplexFloat with to_string(self) {
self.format()
}
///|
pub impl Show for ComplexFloat with output(self, logger : &Logger) -> Unit {
logger.write_string(self.to_string())
}
///|
pub fn complex_float_from_exact_parts(
real : @symnum.BigRational,
imag : @symnum.BigRational,
prec? : Int = 53,
) -> ComplexFloat {
ComplexFloat::from_exact_parts(real, imag, prec~)
}