use crate::complex::big;
use crate::complex::big::Format;
#[allow(deprecated)]
use crate::complex::SmallComplex;
use crate::complex::{MiniComplex, OrdComplex};
use crate::ext::xmpc;
use crate::ext::xmpc::{Ordering2, Round2};
use crate::float::big::ExpFormat;
use crate::float::{Round, Special};
use crate::misc::StringLike;
use crate::ops::AssignRound;
use crate::{Assign, Complex, Float};
use core::cmp::Ordering;
use core::fmt::{
Alignment, Binary, Debug, Display, Formatter, LowerExp, LowerHex, Octal, Result as FmtResult,
UpperExp, UpperHex,
};
use core::mem::MaybeUninit;
use gmp_mpfr_sys::mpc;
impl Clone for Complex {
#[inline]
fn clone(&self) -> Complex {
let mut ret = Complex::new_nan(self.prec());
let (real, imag) = (self.real(), self.imag());
if !real.is_nan() {
ret.mut_real().assign(real);
}
if !imag.is_nan() {
ret.mut_imag().assign(imag);
}
ret
}
#[inline]
fn clone_from(&mut self, source: &Complex) {
self.mut_real().clone_from(source.real());
self.mut_imag().clone_from(source.imag());
}
}
impl Drop for Complex {
#[inline]
fn drop(&mut self) {
unsafe {
mpc::clear(self.as_raw_mut());
}
}
}
impl<Re> From<Re> for Complex
where
Float: From<Re>,
{
#[inline]
fn from(re: Re) -> Self {
let real = Float::from(re);
let imag = Float::new(real.prec());
let mut dst = MaybeUninit::uninit();
xmpc::write_real_imag(&mut dst, real, imag);
unsafe { dst.assume_init() }
}
}
impl<Re, Im> From<(Re, Im)> for Complex
where
Float: From<Re> + From<Im>,
{
#[inline]
fn from((re, im): (Re, Im)) -> Self {
let (real, imag) = (Float::from(re), Float::from(im));
let mut dst = MaybeUninit::uninit();
xmpc::write_real_imag(&mut dst, real, imag);
unsafe { dst.assume_init() }
}
}
impl Display for Complex {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
let format = Format {
exp: ExpFormat::Point,
..Format::default()
};
fmt_radix(self, f, format)
}
}
impl Debug for Complex {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
let format = Format {
exp: ExpFormat::Point,
..Format::default()
};
fmt_radix(self, f, format)
}
}
impl LowerExp for Complex {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
let format = Format {
exp: ExpFormat::Exp,
..Format::default()
};
fmt_radix(self, f, format)
}
}
impl UpperExp for Complex {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
let format = Format {
to_upper: true,
exp: ExpFormat::Exp,
..Format::default()
};
fmt_radix(self, f, format)
}
}
impl Binary for Complex {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
let format = Format {
radix: 2,
prefix: "0b",
exp: ExpFormat::Point,
..Format::default()
};
fmt_radix(self, f, format)
}
}
impl Octal for Complex {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
let format = Format {
radix: 8,
prefix: "0o",
exp: ExpFormat::Point,
..Format::default()
};
fmt_radix(self, f, format)
}
}
impl LowerHex for Complex {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
let format = Format {
radix: 16,
prefix: "0x",
exp: ExpFormat::Point,
..Format::default()
};
fmt_radix(self, f, format)
}
}
impl UpperHex for Complex {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
let format = Format {
radix: 16,
to_upper: true,
prefix: "0x",
exp: ExpFormat::Point,
..Format::default()
};
fmt_radix(self, f, format)
}
}
impl AsRef<OrdComplex> for Complex {
#[inline]
fn as_ref(&self) -> &OrdComplex {
self.as_ord()
}
}
impl<T> Assign<T> for Complex
where
Self: AssignRound<T, Round = Round2, Ordering = Ordering2>,
{
#[inline]
fn assign(&mut self, src: T) {
self.assign_round(src, (Round::Nearest, Round::Nearest));
}
}
impl AssignRound for Complex {
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(&mut self, src: Complex, round: Round2) -> Ordering2 {
let (dst_real, dst_imag) = self.as_mut_real_imag();
let (src_real, src_imag) = src.into_real_imag();
(
dst_real.assign_round(src_real, round.0),
dst_imag.assign_round(src_imag, round.1),
)
}
}
impl AssignRound<&Complex> for Complex {
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(&mut self, src: &Complex, round: Round2) -> Ordering2 {
xmpc::set(self, src, round)
}
}
impl AssignRound<MiniComplex> for Complex {
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(&mut self, mut src: MiniComplex, round: Round2) -> Ordering2 {
self.assign_round(src.borrow_excl(), round)
}
}
impl AssignRound<&MiniComplex> for Complex {
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(&mut self, src: &MiniComplex, round: Round2) -> Ordering2 {
self.assign_round(&*src.borrow(), round)
}
}
#[allow(deprecated)]
impl AssignRound<SmallComplex> for Complex {
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(&mut self, src: SmallComplex, round: Round2) -> Ordering2 {
self.assign_round(&*src, round)
}
}
#[allow(deprecated)]
impl AssignRound<&SmallComplex> for Complex {
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(&mut self, src: &SmallComplex, round: Round2) -> Ordering2 {
self.assign_round(&**src, round)
}
}
impl<Re> AssignRound<Re> for Complex
where
Float: AssignRound<Re, Round = Round, Ordering = Ordering>,
{
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(&mut self, src: Re, round: Round2) -> Ordering2 {
let real_ord = self.mut_real().assign_round(src, round.0);
Assign::<Special>::assign(self.mut_imag(), Special::Zero);
(real_ord, Ordering::Equal)
}
}
impl<Re, Im> AssignRound<(Re, Im)> for Complex
where
Float: AssignRound<Re, Round = Round, Ordering = Ordering>
+ AssignRound<Im, Round = Round, Ordering = Ordering>,
{
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(&mut self, src: (Re, Im), round: Round2) -> Ordering2 {
let real_ord = self.mut_real().assign_round(src.0, round.0);
let imag_ord = self.mut_imag().assign_round(src.1, round.1);
(real_ord, imag_ord)
}
}
impl<'a, Re, Im> AssignRound<&'a (Re, Im)> for Complex
where
Float: AssignRound<&'a Re, Round = Round, Ordering = Ordering>
+ AssignRound<&'a Im, Round = Round, Ordering = Ordering>,
{
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(&mut self, src: &'a (Re, Im), round: Round2) -> Ordering2 {
let real_ord = self.mut_real().assign_round(&src.0, round.0);
let imag_ord = self.mut_imag().assign_round(&src.1, round.1);
(real_ord, imag_ord)
}
}
fn fmt_radix(c: &Complex, fmt: &mut Formatter<'_>, format: Format) -> FmtResult {
let format = Format {
precision: fmt.precision(),
sign_plus: fmt.sign_plus(),
prefix: if fmt.alternate() { format.prefix } else { "" },
..format
};
let mut s = StringLike::new_malloc();
big::append_to_string(&mut s, c, format);
let count = s.as_str().len();
let padding = match fmt.width() {
Some(width) if width > count => width - count,
_ => return fmt.write_str(s.as_str()),
};
let (padding_left, padding_right) = match fmt.align() {
Some(Alignment::Left) => (0, padding),
Some(Alignment::Right) | None => (padding, 0),
Some(Alignment::Center) => (padding / 2, padding - padding / 2),
};
let mut buf = [0; 4];
let fill_buf = fmt.fill().encode_utf8(&mut buf);
for _ in 0..padding_left {
fmt.write_str(fill_buf)?;
}
fmt.write_str(s.as_str())?;
for _ in 0..padding_right {
fmt.write_str(fill_buf)?;
}
Ok(())
}
unsafe impl Send for Complex {}
unsafe impl Sync for Complex {}
#[cfg(test)]
mod tests {
use crate::float;
use crate::float::{FreeCache, Round};
use crate::ops::AssignRound;
use crate::{Assign, Complex, Float};
use core::cmp::Ordering;
#[test]
fn check_assign() {
let nearest = (Round::Nearest, Round::Nearest);
let mut c = Complex::with_val(4, (1.0, 2.0));
assert_eq!(c, (1.0, 2.0));
let other = Complex::with_val(53, (14.75, 15.25));
let mut dir = c.assign_round(&other, nearest);
assert_eq!(c, (15.0, 15.0));
assert_eq!(dir, (Ordering::Greater, Ordering::Less));
dir = c.assign_round(3.0, nearest);
assert_eq!(c, (3.0, 0.0));
assert_eq!(dir, (Ordering::Equal, Ordering::Equal));
c.assign(other);
assert_eq!(c, (15.0, 15.0));
float::free_cache(FreeCache::All);
}
#[test]
fn check_from() {
let r = Float::with_val(53, 1.0);
let i = Float::with_val(53, 2.0);
let cr = Complex::from(r.clone());
assert_eq!(cr, r);
let ci = Complex::from((Float::new(53), i.clone()));
let cri = Complex::from((r, i));
let cr_ci = cr + ci;
assert_eq!(cri, cr_ci);
}
}