use {Assign, AssignRound, Float};
#[cfg(feature = "integer")]
use Integer;
#[cfg(feature = "rational")]
use Rational;
use complex::OrdComplex;
use ext::mpc as xmpc;
use float::{self, Constant, ParseFloatError, Round, Special, ValidFloat};
use inner::{Inner, InnerMut};
use ops::{AddAssignRound, AddFrom, AddFromRound, DivAssignRound, DivFrom,
DivFromRound, MulAssignRound, MulFrom, MulFromRound, NegAssign, Pow,
PowAssign, PowAssignRound, PowFrom, PowFromRound, SubAssignRound,
SubFrom, SubFromRound};
#[cfg(feature = "rand")]
use rand::RandState;
use gmp_mpfr_sys::mpc::{self, mpc_t};
use gmp_mpfr_sys::mpfr;
use std::ascii::AsciiExt;
use std::cmp::Ordering;
use std::error::Error;
use std::fmt::{self, Binary, Debug, Display, Formatter, LowerExp, LowerHex,
Octal, UpperExp, UpperHex};
use std::i32;
use std::marker::PhantomData;
use std::mem;
use std::ops::{Add, AddAssign, Deref, Div, DivAssign, Mul, MulAssign, Neg,
Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign};
use std::os::raw::c_int;
use std::ptr;
pub trait Prec {
fn prec(self) -> (u32, u32);
}
impl Prec for u32 {
#[inline]
fn prec(self) -> (u32, u32) {
(self, self)
}
}
impl Prec for (u32, u32) {
#[inline]
fn prec(self) -> (u32, u32) {
self
}
}
type Round2 = (Round, Round);
type Ordering2 = (Ordering, Ordering);
pub struct Complex {
inner: mpc_t,
}
impl Clone for Complex {
#[inline]
fn clone(&self) -> Complex {
let prec = self.prec();
let mut ret = Complex::new(prec);
ret.assign(self);
ret
}
#[inline]
fn clone_from(&mut self, source: &Complex) {
self.assign(source);
}
}
impl Default for Complex {
#[inline]
fn default() -> Complex {
Complex::new(53)
}
}
impl Drop for Complex {
#[inline]
fn drop(&mut self) {
unsafe {
mpc::clear(self.inner_mut());
}
}
}
macro_rules! math_op1_complex {
{
$func:path;
$(#[$attr:meta])*
fn $method:ident($($param:ident: $T:ty),*);
$(#[$attr_mut:meta])*
fn $method_mut:ident;
$(#[$attr_round:meta])*
fn $method_round:ident;
$(#[$attr_ref:meta])*
fn $method_ref:ident -> $Ref:ident;
} => {
math_op1_round! {
Complex, Round2 => Ordering2;
$func, rraw2 => ordering2;
$(#[$attr])*
fn $method($($param: $T),*);
$(#[$attr_mut])*
fn $method_mut;
$(#[$attr_round])*
fn $method_round;
$(#[$attr_ref])*
fn $method_ref -> $Ref;
}
}
}
macro_rules! ref_math_op1_complex {
{
$func:path;
$(#[$attr_ref:meta])*
struct $Ref:ident { $($param:ident: $T:ty),* }
} => {
ref_math_op1_round! {
Complex, Round2 => Ordering2;
$func, rraw2 => ordering2;
$(#[$attr_ref])*
struct $Ref { $($param: $T),* }
}
}
}
macro_rules! math_op1_2_complex {
{
$func:path;
$(#[$attr:meta])*
fn $method:ident($rop:ident $(, $param:ident: $T:ty),*);
$(#[$attr_mut:meta])*
fn $method_mut:ident;
$(#[$attr_round:meta])*
fn $method_round:ident;
$(#[$attr_ref:meta])*
fn $method_ref:ident -> $Ref:ident;
} => {
math_op1_2_round! {
Complex, Round2 => (Ordering2, Ordering2);
$func, rraw2, rraw2 => ordering4;
$(#[$attr])*
fn $method($rop $(, $param: $T)*);
$(#[$attr_mut])*
fn $method_mut;
$(#[$attr_round])*
fn $method_round;
$(#[$attr_ref])*
fn $method_ref -> $Ref;
}
}
}
macro_rules! ref_math_op1_2_complex {
{
$func:path;
$(#[$attr_ref:meta])*
struct $Ref:ident { $($param:ident: $T:ty),* }
} => {
ref_math_op1_2_round! {
Complex, Round2 => (Ordering2, Ordering2);
$func, rraw2, rraw2 => ordering4;
$(#[$attr_ref])*
struct $Ref { $($param: $T),* }
}
}
}
impl Complex {
#[inline]
fn new_nan<P: Prec>(prec: P) -> Complex {
let p = prec.prec();
assert!(
p.0 >= float::prec_min() && p.0 <= float::prec_max() &&
p.1 >= float::prec_min() &&
p.1 <= float::prec_max(),
"precision out of range"
);
unsafe {
let mut c: Complex = mem::uninitialized();
mpc::init3(c.inner_mut(), p.0 as mpfr::prec_t, p.1 as mpfr::prec_t);
c
}
}
#[inline]
pub fn new<P: Prec>(prec: P) -> Complex {
let mut ret = Complex::new_nan(prec);
ret.mut_real().assign(Special::Zero);
ret.mut_imag().assign(Special::Zero);
ret
}
#[inline]
pub fn with_val<P: Prec, T>(prec: P, val: T) -> Complex
where
Complex: Assign<T>,
{
let mut ret = Complex::new_nan(prec);
ret.assign(val);
ret
}
#[inline]
pub fn with_val_round<P: Prec, T>(
prec: P,
val: T,
round: Round2,
) -> (Complex, Ordering2)
where
Complex: AssignRound<T, Round = Round2, Ordering = Ordering2>,
{
let mut ret = Complex::new_nan(prec);
let ord = ret.assign_round(val, round);
(ret, ord)
}
#[inline]
pub fn prec(&self) -> (u32, u32) {
(self.real().prec(), self.imag().prec())
}
#[inline]
pub fn set_prec<P: Prec>(&mut self, prec: P) {
self.set_prec_round(prec, Default::default());
}
#[inline]
pub fn set_prec_round<P: Prec>(
&mut self,
prec: P,
round: Round2,
) -> Ordering2 {
let p = prec.prec();
let (real, imag) = self.as_mut_real_imag();
(
real.set_prec_round(p.0, round.0),
imag.set_prec_round(p.1, round.1),
)
}
#[inline]
pub fn from_str<P: Prec>(
src: &str,
prec: P,
) -> Result<Complex, ParseComplexError> {
let mut val = Complex::new_nan(prec);
val.assign_str(src)?;
Ok(val)
}
#[inline]
pub fn from_str_round<P: Prec>(
src: &str,
prec: P,
round: Round2,
) -> Result<(Complex, Ordering2), ParseComplexError> {
let mut val = Complex::new_nan(prec);
let ord = val.assign_str_round(src, round)?;
Ok((val, ord))
}
#[inline]
pub fn from_str_radix<P: Prec>(
src: &str,
radix: i32,
prec: P,
) -> Result<Complex, ParseComplexError> {
let mut val = Complex::new_nan(prec);
val.assign_str_radix(src, radix)?;
Ok(val)
}
#[inline]
pub fn from_str_radix_round<P: Prec>(
src: &str,
radix: i32,
prec: P,
round: Round2,
) -> Result<(Complex, Ordering2), ParseComplexError> {
let mut val = Complex::new_nan(prec);
let ord = val.assign_str_radix_round(src, radix, round)?;
Ok((val, ord))
}
pub fn valid_str_radix(
src: &str,
radix: i32,
) -> Result<ValidComplex, ParseComplexError> {
use self::ParseComplexError as Error;
use self::ParseErrorKind as Kind;
let p = if src.starts_with('(') {
let space = src.find(' ')
.ok_or(Error {
kind: Kind::MissingSpace,
})?;
let real_str = &src[1..space];
let re = Float::valid_str_radix(real_str, radix).map_err(|e| {
Error {
kind: Kind::InvalidRealFloat(e),
}
})?;
let rest = &src[space + 1..];
let close = rest.find(')')
.ok_or(Error {
kind: Kind::MissingClose,
})?;
let imag_str = &rest[0..close];
let im = Float::valid_str_radix(imag_str, radix).map_err(|e| {
Error {
kind: Kind::InvalidImagFloat(e),
}
})?;
if close != rest.len() - 1 {
return Err(Error {
kind: Kind::CloseNotLast,
});
}
ValidPoss::Complex(re, im)
} else {
let re = Float::valid_str_radix(src, radix).map_err(|e| {
Error {
kind: Kind::InvalidFloat(e),
}
})?;
ValidPoss::Real(re)
};
Ok(ValidComplex { poss: p })
}
#[inline]
pub fn to_string_radix(
&self,
radix: i32,
num_digits: Option<usize>,
) -> String {
self.to_string_radix_round(radix, num_digits, Default::default())
}
pub fn to_string_radix_round(
&self,
radix: i32,
num_digits: Option<usize>,
round: Round2,
) -> String {
let mut buf = String::from("(");
buf += &self.real()
.to_string_radix_round(radix, num_digits, round.0);
buf.push(' ');
buf += &self.imag()
.to_string_radix_round(radix, num_digits, round.0);
buf.push(')');
buf
}
#[inline]
pub fn assign_str(&mut self, src: &str) -> Result<(), ParseComplexError> {
self.assign_str_radix(src, 10)
}
#[inline]
pub fn assign_str_round(
&mut self,
src: &str,
round: Round2,
) -> Result<Ordering2, ParseComplexError> {
self.assign_str_radix_round(src, 10, round)
}
#[inline]
pub fn assign_str_radix(
&mut self,
src: &str,
radix: i32,
) -> Result<(), ParseComplexError> {
self.assign_str_radix_round(src, radix, Default::default())
.map(|_| ())
}
#[inline]
pub fn assign_str_radix_round(
&mut self,
src: &str,
radix: i32,
round: Round2,
) -> Result<Ordering2, ParseComplexError> {
Ok(self.assign_round(
Complex::valid_str_radix(src, radix)?,
round,
))
}
#[inline]
pub fn real(&self) -> &Float {
unsafe {
let ptr = mpc::realref_const(self.inner());
&*(ptr as *const Float)
}
}
#[inline]
pub fn imag(&self) -> &Float {
unsafe {
let ptr = mpc::imagref_const(self.inner());
&*(ptr as *const Float)
}
}
#[inline]
pub fn mut_real(&mut self) -> &mut Float {
unsafe {
let ptr = mpc::realref(self.inner_mut());
&mut *(ptr as *mut Float)
}
}
#[inline]
pub fn mut_imag(&mut self) -> &mut Float {
unsafe {
let ptr = mpc::imagref(self.inner_mut());
&mut *(ptr as *mut Float)
}
}
#[inline]
pub fn as_real_imag(&self) -> (&Float, &Float) {
(self.real(), self.imag())
}
#[inline]
pub fn as_mut_real_imag(&mut self) -> (&mut Float, &mut Float) {
unsafe {
let real_ptr = mpc::realref(self.inner_mut());
let imag_ptr = mpc::imagref(self.inner_mut());
(
&mut *(real_ptr as *mut Float),
&mut *(imag_ptr as *mut Float),
)
}
}
#[inline]
pub fn into_real_imag(mut self) -> (Float, Float) {
let (mut real, mut imag) = unsafe { mem::uninitialized() };
unsafe {
let real_imag = self.as_mut_real_imag();
ptr::copy_nonoverlapping(real_imag.0, &mut real, 1);
ptr::copy_nonoverlapping(real_imag.1, &mut imag, 1);
}
mem::forget(self);
(real, imag)
}
pub fn as_neg(&self) -> BorrowComplex {
let mut ret = BorrowComplex {
inner: self.inner,
phantom: PhantomData,
};
let (self_re, self_im) = self.as_real_imag();
unsafe {
if self_re.is_nan() {
mpfr::set_nanflag();
} else {
(*mpc::realref(&mut ret.inner)).sign.neg_assign();
}
if self_im.is_nan() {
mpfr::set_nanflag();
} else {
(*mpc::imagref(&mut ret.inner)).sign.neg_assign();
}
}
ret
}
pub fn as_conj(&self) -> BorrowComplex {
let mut ret = BorrowComplex {
inner: self.inner,
phantom: PhantomData,
};
let self_im = self.imag();
unsafe {
if self_im.is_nan() {
mpfr::set_nanflag();
} else {
(*mpc::imagref(&mut ret.inner)).sign.neg_assign();
}
}
ret
}
pub fn as_mul_i(&self, negative: bool) -> BorrowComplex {
let (self_re, self_im) = self.as_real_imag();
let (self_re_nan, self_im_nan) = (self_re.is_nan(), self_im.is_nan());
let (self_re, self_im) = (self_re.inner(), self_im.inner());
let mut ret = BorrowComplex {
inner: unsafe { mem::uninitialized() },
phantom: PhantomData,
};
let (ret_re, ret_im) = unsafe {
let re = &mut *mpc::realref(&mut ret.inner);
let im = &mut *mpc::imagref(&mut ret.inner);
(re, im)
};
*ret_re = *self_im;
*ret_im = *self_re;
unsafe {
if negative {
if self_re_nan {
mpfr::set_nanflag();
} else {
ret_im.sign.neg_assign();
}
} else if self_im_nan {
mpfr::set_nanflag();
} else {
ret_re.sign.neg_assign();
}
}
ret
}
pub fn as_ord(&self) -> &OrdComplex {
unsafe { &*(self as *const _ as *const _) }
}
math_op1_no_round! {
Complex;
mpc::proj, rraw2;
fn proj();
fn proj_mut;
fn proj_ref -> ProjRef;
}
math_op1_complex! {
mpc::sqr;
fn square();
fn square_mut;
fn square_round;
fn square_ref -> SquareRef;
}
math_op1_complex! {
mpc::sqrt;
fn sqrt();
fn sqrt_mut;
fn sqrt_round;
fn sqrt_ref -> SqrtRef;
}
math_op1_no_round! {
Complex;
mpc::conj, rraw2;
fn conj();
fn conj_mut;
fn conj_ref -> ConjugateRef;
}
#[inline]
pub fn abs(self) -> Float {
let (mut re, im) = self.into_real_imag();
re.hypot_mut(&im);
re
}
#[inline]
pub fn abs_mut(&mut self) {
let (re, im) = self.as_mut_real_imag();
re.hypot_mut(im);
im.assign(Special::Zero);
}
#[inline]
pub fn abs_ref(&self) -> AbsRef {
AbsRef { ref_self: self }
}
#[inline]
pub fn arg(self) -> Float {
let (mut re, im) = self.into_real_imag();
unsafe {
mpfr::atan2(
re.inner_mut(),
im.inner(),
re.inner(),
rraw(Round::Nearest),
);
}
re
}
#[inline]
pub fn arg_mut(&mut self) {
self.arg_round(Default::default());
}
#[inline]
pub fn arg_round(&mut self, round: Round2) -> Ordering2 {
let (re, im) = self.as_mut_real_imag();
let ret = unsafe {
mpfr::atan2(re.inner_mut(), im.inner(), re.inner(), rraw(round.0))
};
let dir_re = ordering1(ret);
let dir_im = im.assign_round(Special::Zero, round.1);
(dir_re, dir_im)
}
#[inline]
pub fn arg_ref(&self) -> ArgRef {
ArgRef { ref_self: self }
}
math_op1_complex! {
xmpc::mul_i;
fn mul_i(negative: bool);
fn mul_i_mut;
fn mul_i_round;
fn mul_i_ref -> MulIRef;
}
math_op1_complex! {
xmpc::recip;
fn recip();
fn recip_mut;
fn recip_round;
fn recip_ref -> RecipRef;
}
#[inline]
pub fn norm(self) -> Float {
Float::with_val(self.real().prec(), self.norm_ref())
}
#[inline]
pub fn norm_mut(&mut self) {
self.norm_round(Default::default());
}
#[inline]
pub fn norm_round(&mut self, round: Round2) -> Ordering2 {
let (norm, dir_re) =
Float::with_val_round(self.real().prec(), self.norm_ref(), round.0);
let (real, imag) = self.as_mut_real_imag();
mem::replace(real, norm);
let dir_im = imag.assign_round(Special::Zero, round.1);
(dir_re, dir_im)
}
#[inline]
pub fn norm_ref(&self) -> NormRef {
NormRef { ref_self: self }
}
math_op1_complex! {
mpc::log;
fn ln();
fn ln_mut;
fn ln_round;
fn ln_ref -> LnRef;
}
math_op1_complex! {
mpc::log10;
fn log10();
fn log10_mut;
fn log10_round;
fn log10_ref -> Log10Ref;
}
math_op1_complex! {
mpc::exp;
fn exp();
fn exp_mut;
fn exp_round;
fn exp_ref -> ExpRef;
}
math_op1_complex! {
mpc::sin;
fn sin();
fn sin_mut;
fn sin_round;
fn sin_ref -> SinRef;
}
math_op1_complex! {
mpc::cos;
fn cos();
fn cos_mut;
fn cos_round;
fn cos_ref -> CosRef;
}
math_op1_2_complex! {
mpc::sin_cos;
fn sin_cos(cos);
fn sin_cos_mut;
fn sin_cos_round;
fn sin_cos_ref -> SinCosRef;
}
math_op1_complex! {
mpc::tan;
fn tan();
fn tan_mut;
fn tan_round;
fn tan_ref -> TanRef;
}
math_op1_complex! {
mpc::sinh;
fn sinh();
fn sinh_mut;
fn sinh_round;
fn sinh_ref -> SinhRef;
}
math_op1_complex! {
mpc::cosh;
fn cosh();
fn cosh_mut;
fn cosh_round;
fn cosh_ref -> CoshRef;
}
math_op1_complex! {
mpc::tanh;
fn tanh();
fn tanh_mut;
fn tanh_round;
fn tanh_ref -> TanhRef;
}
math_op1_complex! {
mpc::asin;
fn asin();
fn asin_mut;
fn asin_round;
fn asin_ref -> AsinRef;
}
math_op1_complex! {
mpc::acos;
fn acos();
fn acos_mut;
fn acos_round;
fn acos_ref -> AcosRef;
}
math_op1_complex! {
mpc::atan;
fn atan();
fn atan_mut;
fn atan_round;
fn atan_ref -> AtanRef;
}
math_op1_complex! {
mpc::asinh;
fn asinh();
fn asinh_mut;
fn asinh_round;
fn asinh_ref -> AsinhRef;
}
math_op1_complex! {
mpc::acosh;
fn acosh();
fn acosh_mut;
fn acosh_round;
fn acosh_ref -> AcoshRef;
}
math_op1_complex! {
mpc::atanh;
fn atanh();
fn atanh_mut;
fn atanh_round;
fn atanh_ref -> AtanhRef;
}
#[cfg(feature = "rand")]
#[inline]
pub fn assign_random_bits(
&mut self,
rng: &mut RandState,
) -> Result<(), ()> {
let (real, imag) = self.as_mut_real_imag();
real.assign_random_bits(rng)?;
imag.assign_random_bits(rng)
}
#[cfg(feature = "rand")]
#[inline]
pub fn assign_random_cont(&mut self, rng: &mut RandState) {
self.assign_random_cont_round(rng, Default::default());
}
#[cfg(feature = "rand")]
#[inline]
pub fn assign_random_cont_round(
&mut self,
rng: &mut RandState,
round: Round2,
) -> Ordering2 {
let (real, imag) = self.as_mut_real_imag();
(
real.assign_random_cont_round(rng, round.0),
imag.assign_random_cont_round(rng, round.1),
)
}
}
impl From<(Float, Float)> for Complex {
#[inline]
fn from((real, imag): (Float, Float)) -> Complex {
let mut dst: Complex = unsafe { mem::uninitialized() };
unsafe {
let mut real_imag = dst.as_mut_real_imag();
ptr::copy_nonoverlapping(&real, real_imag.0, 1);
ptr::copy_nonoverlapping(&imag, real_imag.1, 1);
}
mem::forget(real);
mem::forget(imag);
dst
}
}
impl From<OrdComplex> for Complex {
#[inline]
fn from(ord: OrdComplex) -> Complex {
unsafe { mem::transmute(ord) }
}
}
impl Display for Complex {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 10, false, "", false)
}
}
impl Debug for Complex {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 10, false, "", true)
}
}
impl LowerExp for Complex {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 10, false, "", false)
}
}
impl UpperExp for Complex {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 10, true, "", false)
}
}
impl Binary for Complex {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 2, false, "0b", false)
}
}
impl Octal for Complex {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 8, false, "0o", false)
}
}
impl LowerHex for Complex {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 16, false, "0x", false)
}
}
impl UpperHex for Complex {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 16, true, "0x", false)
}
}
impl<T> Assign<T> for Complex
where
Complex: AssignRound<T, Round = Round2, Ordering = Ordering2>,
{
#[inline]
fn assign(&mut self, other: T) {
self.assign_round(other, Default::default());
}
}
impl AssignRound<Complex> for Complex {
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(&mut self, other: Complex, round: Round2) -> Ordering2 {
self.assign_round(&other, round)
}
}
impl<'a> AssignRound<&'a Complex> for Complex {
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(&mut self, other: &Complex, round: Round2) -> Ordering2 {
let ret =
unsafe { mpc::set(self.inner_mut(), other.inner(), rraw2(round)) };
ordering2(ret)
}
}
macro_rules! assign_ref {
{ $T:ty } => {
impl<'a> AssignRound<&'a $T> for Complex {
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(
&mut self,
other: &'a $T,
round: Round2,
) -> Ordering2 {
let (real, imag) = self.as_mut_real_imag();
let ord1 = real.assign_round(other, round.0);
let ord2 = imag.assign_round(0, round.1);
(ord1, ord2)
}
}
};
}
macro_rules! assign {
{ $T:ty } => {
impl AssignRound<$T> for Complex {
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(&mut self, other: $T, round: Round2) -> Ordering2 {
let (real, imag) = self.as_mut_real_imag();
let ord1 = real.assign_round(other, round.0);
let ord2 = imag.assign_round(0, round.1);
(ord1, ord2)
}
}
};
}
#[cfg(feature = "integer")]
assign_ref! { Integer }
#[cfg(feature = "rational")]
assign_ref! { Rational }
assign_ref! { Float }
#[cfg(feature = "integer")]
assign! { Integer }
#[cfg(feature = "rational")]
assign! { Rational }
assign! { Float }
assign! { Special }
assign! { Constant }
assign! { i32 }
assign! { i64 }
assign! { u32 }
assign! { u64 }
assign! { f32 }
assign! { f64 }
impl<T, U> AssignRound<(T, U)> for Complex
where
Float: AssignRound<T, Round = Round, Ordering = Ordering>,
Float: AssignRound<U, Round = Round, Ordering = Ordering>,
{
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(&mut self, other: (T, U), round: Round2) -> Ordering2 {
let (real, imag) = self.as_mut_real_imag();
let ord1 = real.assign_round(other.0, round.0);
let ord2 = imag.assign_round(other.1, round.1);
(ord1, ord2)
}
}
ref_math_op1_complex! { mpc::proj; struct ProjRef {} }
ref_math_op1_complex! { mpc::sqr; struct SquareRef {} }
ref_math_op1_complex! { mpc::sqrt; struct SqrtRef {} }
ref_math_op1_complex! { mpc::conj; struct ConjugateRef {} }
pub struct AbsRef<'a> {
ref_self: &'a Complex,
}
impl<'a> AssignRound<AbsRef<'a>> for Float {
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(&mut self, src: AbsRef<'a>, round: Round) -> Ordering {
let ret = unsafe {
mpc::abs(self.inner_mut(), src.ref_self.inner(), rraw(round))
};
ret.cmp(&0)
}
}
pub struct ArgRef<'a> {
ref_self: &'a Complex,
}
impl<'a> AssignRound<ArgRef<'a>> for Float {
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(&mut self, src: ArgRef<'a>, round: Round) -> Ordering {
let ret = unsafe {
mpc::arg(self.inner_mut(), src.ref_self.inner(), rraw(round))
};
ret.cmp(&0)
}
}
ref_math_op1_complex! { xmpc::mul_i; struct MulIRef { negative: bool } }
ref_math_op1_complex! { xmpc::recip; struct RecipRef {} }
pub struct NormRef<'a> {
ref_self: &'a Complex,
}
impl<'a> AssignRound<NormRef<'a>> for Float {
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(&mut self, src: NormRef<'a>, round: Round) -> Ordering {
let ret = unsafe {
mpc::norm(self.inner_mut(), src.ref_self.inner(), rraw(round))
};
ret.cmp(&0)
}
}
ref_math_op1_complex! { mpc::log; struct LnRef {} }
ref_math_op1_complex! { mpc::log10; struct Log10Ref {} }
ref_math_op1_complex! { mpc::exp; struct ExpRef {} }
ref_math_op1_complex! { mpc::sin; struct SinRef {} }
ref_math_op1_complex! { mpc::cos; struct CosRef {} }
ref_math_op1_2_complex! { mpc::sin_cos; struct SinCosRef {} }
ref_math_op1_complex! { mpc::tan; struct TanRef {} }
ref_math_op1_complex! { mpc::sinh; struct SinhRef {} }
ref_math_op1_complex! { mpc::cosh; struct CoshRef {} }
ref_math_op1_complex! { mpc::tanh; struct TanhRef {} }
ref_math_op1_complex! { mpc::asin; struct AsinRef {} }
ref_math_op1_complex! { mpc::acos; struct AcosRef {} }
ref_math_op1_complex! { mpc::atan; struct AtanRef {} }
ref_math_op1_complex! { mpc::asinh; struct AsinhRef {} }
ref_math_op1_complex! { mpc::acosh; struct AcoshRef {} }
ref_math_op1_complex! { mpc::atanh; struct AtanhRef {} }
#[derive(Clone, Copy)]
pub struct BorrowComplex<'a> {
inner: mpc_t,
phantom: PhantomData<&'a Complex>,
}
impl<'a> Deref for BorrowComplex<'a> {
type Target = Complex;
#[inline]
fn deref(&self) -> &Complex {
let ptr = (&self.inner) as *const _ as *const _;
unsafe { &*ptr }
}
}
impl Neg for Complex {
type Output = Complex;
#[inline]
fn neg(mut self) -> Complex {
self.neg_assign();
self
}
}
impl NegAssign for Complex {
#[inline]
fn neg_assign(&mut self) {
unsafe {
mpc::neg(self.inner_mut(), self.inner(), rraw2(Default::default()));
}
}
}
impl<'a> Neg for &'a Complex {
type Output = NegRef<'a>;
#[inline]
fn neg(self) -> NegRef<'a> {
NegRef { val: self }
}
}
pub struct NegRef<'a> {
val: &'a Complex,
}
impl<'a> AssignRound<NegRef<'a>> for Complex {
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(&mut self, src: NegRef<'a>, round: Round2) -> Ordering2 {
let ret = unsafe {
mpc::neg(self.inner_mut(), src.val.inner(), rraw2(round))
};
ordering2(ret)
}
}
macro_rules! arith_binary_self_complex {
{
$func:path;
$Imp:ident $method:ident;
$ImpAssign:ident $method_assign:ident;
$ImpAssignRound:ident $method_assign_round:ident;
$ImpFrom:ident $method_from:ident;
$ImpFromRound:ident $method_from_round:ident;
$Ref:ident
} => {
arith_binary_self_round! {
Complex, Round2 => Ordering2;
$func, rraw2 => ordering2;
$Imp $method;
$ImpAssign $method_assign;
$ImpAssignRound $method_assign_round;
$ImpFrom $method_from;
$ImpFromRound $method_from_round;
$Ref
}
}
}
macro_rules! arith_forward_complex {
{
$func:path;
$Imp:ident $method:ident;
$ImpAssign:ident $method_assign:ident;
$ImpAssignRound:ident $method_assign_round:ident;
$T:ty;
$Ref:ident $RefOwn:ident
} => {
arith_forward_round! {
Complex, Round2 => Ordering2;
$func, rraw2 => ordering2;
$Imp $method;
$ImpAssign $method_assign;
$ImpAssignRound $method_assign_round;
$T;
$Ref $RefOwn
}
}
}
macro_rules! arith_commut_complex {
{
$func:path;
$Imp:ident $method:ident;
$ImpAssign:ident $method_assign:ident;
$ImpAssignRound:ident $method_assign_round:ident;
$ImpFrom:ident $method_from:ident;
$ImpFromRound:ident $method_from_round:ident;
$T:ty;
$Ref:ident $RefOwn:ident
} => {
arith_commut_round! {
Complex, Round2 => Ordering2;
$func, rraw2 => ordering2;
$Imp $method;
$ImpAssign $method_assign;
$ImpAssignRound $method_assign_round;
$ImpFrom $method_from;
$ImpFromRound $method_from_round;
$T;
$Ref $RefOwn
}
}
}
macro_rules! arith_noncommut_complex {
{
$func:path, $func_from:path;
$Imp:ident $method:ident;
$ImpAssign:ident $method_assign:ident;
$ImpAssignRound:ident $method_assign_round:ident;
$ImpFrom:ident $method_from:ident;
$ImpFromRound:ident $method_from_round:ident;
$T:ty;
$Ref:ident $RefFrom:ident $RefOwn:ident $RefFromOwn:ident
} => {
arith_noncommut_round! {
Complex, Round2 => Ordering2;
$func, $func_from, rraw2 => ordering2;
$Imp $method;
$ImpAssign $method_assign;
$ImpAssignRound $method_assign_round;
$ImpFrom $method_from;
$ImpFromRound $method_from_round;
$T;
$Ref $RefFrom $RefOwn $RefFromOwn
}
}
}
arith_binary_self_complex! {
mpc::add;
Add add;
AddAssign add_assign;
AddAssignRound add_assign_round;
AddFrom add_from;
AddFromRound add_from_round;
AddRef
}
arith_binary_self_complex! {
mpc::sub;
Sub sub;
SubAssign sub_assign;
SubAssignRound sub_assign_round;
SubFrom sub_from;
SubFromRound sub_from_round;
SubRef
}
arith_binary_self_complex! {
mpc::mul;
Mul mul;
MulAssign mul_assign;
MulAssignRound mul_assign_round;
MulFrom mul_from;
MulFromRound mul_from_round;
MulRef
}
arith_binary_self_complex! {
mpc::div;
Div div;
DivAssign div_assign;
DivAssignRound div_assign_round;
DivFrom div_from;
DivFromRound div_from_round;
DivRef
}
arith_binary_self_complex! {
mpc::pow;
Pow pow;
PowAssign pow_assign;
PowAssignRound pow_assign_round;
PowFrom pow_from;
PowFromRound pow_from_round;
PowRef
}
arith_commut_complex! {
mpc::add_fr;
Add add;
AddAssign add_assign;
AddAssignRound add_assign_round;
AddFrom add_from;
AddFromRound add_from_round;
Float;
AddRefFloat AddRefFloatOwn
}
arith_noncommut_complex! {
mpc::sub_fr, mpc::fr_sub;
Sub sub;
SubAssign sub_assign;
SubAssignRound sub_assign_round;
SubFrom sub_from;
SubFromRound sub_from_round;
Float;
SubRefFloat SubFromRefFloat SubRefFloatOwn SubFromRefFloatOwn
}
arith_commut_complex! {
mpc::mul_fr;
Mul mul;
MulAssign mul_assign;
MulAssignRound mul_assign_round;
MulFrom mul_from;
MulFromRound mul_from_round;
Float;
MulRefFloat MulRefFloatOwn
}
arith_noncommut_complex! {
mpc::div_fr, mpc::fr_div;
Div div;
DivAssign div_assign;
DivAssignRound div_assign_round;
DivFrom div_from;
DivFromRound div_from_round;
Float;
DivRefFloat DivFromRefFloat DivRefFloatOwn DivFromRefFloatOwn
}
arith_forward_complex! {
mpc::pow_fr;
Pow pow;
PowAssign pow_assign;
PowAssignRound pow_assign_round;
Float;
PowRefFloat PowRefFloatOwn
}
#[cfg(feature = "integer")]
arith_forward_complex! {
mpc::pow_z;
Pow pow;
PowAssign pow_assign;
PowAssignRound pow_assign_round;
Integer;
PowRefInteger PowRefIntegerOwn
}
macro_rules! arith_prim_complex {
{
$func:path;
$Imp:ident $method:ident;
$ImpAssign:ident $method_assign:ident;
$ImpAssignRound:ident $method_assign_round:ident;
$T:ty;
$Ref:ident
} => {
arith_prim_round! {
Complex, Round2 => Ordering2;
$func, rraw2 => ordering2;
$Imp $method;
$ImpAssign $method_assign;
$ImpAssignRound $method_assign_round;
$T;
$Ref
}
}
}
macro_rules! arith_prim_exact_complex {
{
$func:path;
$Imp:ident $method:ident;
$ImpAssign:ident $method_assign:ident;
$T:ty;
$Ref:ident
} => {
arith_prim_exact_round! {
Complex, Round2 => Ordering2;
$func, rraw2 => ordering2;
$Imp $method;
$ImpAssign $method_assign;
$T;
$Ref
}
}
}
macro_rules! arith_prim_commut_complex {
{
$func:path;
$Imp:ident $method:ident;
$ImpAssign:ident $method_assign:ident;
$ImpAssignRound:ident $method_assign_round:ident;
$ImpFrom:ident $method_from:ident;
$ImpFromRound:ident $method_from_round:ident;
$T:ty;
$Ref:ident
} => {
arith_prim_commut_round! {
Complex, Round2 => Ordering2;
$func, rraw2 => ordering2;
$Imp $method;
$ImpAssign $method_assign;
$ImpAssignRound $method_assign_round;
$ImpFrom $method_from;
$ImpFromRound $method_from_round;
$T;
$Ref
}
}
}
macro_rules! arith_prim_noncommut_complex {
{
$func:path, $func_from:path;
$Imp:ident $method:ident;
$ImpAssign:ident $method_assign:ident;
$ImpAssignRound:ident $method_assign_round:ident;
$ImpFrom:ident $method_from:ident;
$ImpFromRound:ident $method_from_round:ident;
$T:ty;
$Ref:ident $RefFrom:ident
} => {
arith_prim_noncommut_round! {
Complex, Round2 => Ordering2;
$func, $func_from, rraw2 => ordering2;
$Imp $method;
$ImpAssign $method_assign;
$ImpAssignRound $method_assign_round;
$ImpFrom $method_from;
$ImpFromRound $method_from_round;
$T;
$Ref $RefFrom
}
}
}
arith_prim_commut_complex! {
mpc::add_ui;
Add add;
AddAssign add_assign;
AddAssignRound add_assign_round;
AddFrom add_from;
AddFromRound add_from_round;
u32;
AddRefU32
}
arith_prim_noncommut_complex! {
mpc::sub_ui, xmpc::ui_sub;
Sub sub;
SubAssign sub_assign;
SubAssignRound sub_assign_round;
SubFrom sub_from;
SubFromRound sub_from_round;
u32;
SubRefU32 SubFromRefU32
}
arith_prim_commut_complex! {
mpc::mul_ui;
Mul mul;
MulAssign mul_assign;
MulAssignRound mul_assign_round;
MulFrom mul_from;
MulFromRound mul_from_round;
u32;
MulRefU32
}
arith_prim_noncommut_complex! {
mpc::div_ui, xmpc::ui_div;
Div div;
DivAssign div_assign;
DivAssignRound div_assign_round;
DivFrom div_from;
DivFromRound div_from_round;
u32;
DivRefU32 DivFromRefU32
}
arith_prim_commut_complex! {
xmpc::add_si;
Add add;
AddAssign add_assign;
AddAssignRound add_assign_round;
AddFrom add_from;
AddFromRound add_from_round;
i32;
AddRefI32
}
arith_prim_noncommut_complex! {
xmpc::sub_si, xmpc::si_sub;
Sub sub;
SubAssign sub_assign;
SubAssignRound sub_assign_round;
SubFrom sub_from;
SubFromRound sub_from_round;
i32;
SubRefI32 SubFromRefI32
}
arith_prim_commut_complex! {
mpc::mul_si;
Mul mul;
MulAssign mul_assign;
MulAssignRound mul_assign_round;
MulFrom mul_from;
MulFromRound mul_from_round;
i32;
MulRefI32
}
arith_prim_noncommut_complex! {
xmpc::div_si, xmpc::si_div;
Div div;
DivAssign div_assign;
DivAssignRound div_assign_round;
DivFrom div_from;
DivFromRound div_from_round;
i32;
DivRefI32 DivFromRefI32
}
arith_prim_exact_complex! {
mpc::mul_2ui;
Shl shl;
ShlAssign shl_assign;
u32;
ShlRefU32
}
arith_prim_exact_complex! {
mpc::div_2ui;
Shr shr;
ShrAssign shr_assign;
u32;
ShrRefU32
}
arith_prim_complex! {
mpc::pow_ui;
Pow pow;
PowAssign pow_assign;
PowAssignRound pow_assign_round;
u32;
PowRefU32
}
arith_prim_exact_complex! {
mpc::mul_2si;
Shl shl;
ShlAssign shl_assign;
i32;
ShlRefI32
}
arith_prim_exact_complex! {
mpc::div_2si;
Shr shr;
ShrAssign shr_assign;
i32;
ShrRefI32
}
arith_prim_complex! {
mpc::pow_si;
Pow pow;
PowAssign pow_assign;
PowAssignRound pow_assign_round;
i32;
PowRefI32
}
arith_prim_complex! {
mpc::pow_d;
Pow pow;
PowAssign pow_assign;
PowAssignRound pow_assign_round;
f64;
PowRefF64
}
arith_prim_complex! {
xmpc::pow_f32;
Pow pow;
PowAssign pow_assign;
PowAssignRound pow_assign_round;
f32;
PowRefF32
}
mul_op_commut_round! {
Complex, Round2 => Ordering2;
add_mul, rraw2 => ordering2;
Add add;
AddAssign add_assign;
AddAssignRound add_assign_round;
AddFrom add_from;
AddFromRound add_from_round;
MulRef;
AddMulRef
}
mul_op_noncommut_round! {
Complex, Round2 => Ordering2;
sub_mul, mul_sub, rraw2 => ordering2;
Sub sub;
SubAssign sub_assign;
SubAssignRound sub_assign_round;
SubFrom sub_from;
SubFromRound sub_from_round;
MulRef;
SubMulRef SubMulFromRef
}
unsafe fn add_mul(
rop: *mut mpc_t,
add: *const mpc_t,
mul: MulRef,
rnd: mpc::rnd_t,
) -> c_int {
mpc::fma(rop, mul.lhs.inner(), mul.rhs.inner(), add, rnd)
}
unsafe fn sub_mul(
rop: *mut mpc_t,
add: *const mpc_t,
mul: MulRef,
rnd: mpc::rnd_t,
) -> c_int {
xmpc::submul(rop, add, (mul.lhs.inner(), mul.rhs.inner()), rnd)
}
unsafe fn mul_sub(
rop: *mut mpc_t,
mul: MulRef,
sub: *const mpc_t,
rnd: mpc::rnd_t,
) -> c_int {
xmpc::mulsub(rop, (mul.lhs.inner(), mul.rhs.inner()), sub, rnd)
}
impl PartialEq for Complex {
#[inline]
fn eq(&self, other: &Complex) -> bool {
self.real().eq(other.real()) && self.imag().eq(other.imag())
}
}
impl<T, U> PartialEq<(T, U)> for Complex
where
Float: PartialEq<T>,
Float: PartialEq<U>,
{
#[inline]
fn eq(&self, other: &(T, U)) -> bool {
self.real().eq(&other.0) && self.imag().eq(&other.1)
}
}
macro_rules! eq_tuple {
{ $T:ty, $U:ty } => {
impl PartialEq<Complex> for ($T, $U) {
#[inline]
fn eq(&self, other: &Complex) -> bool {
self.0.eq(other.real()) && self.1.eq(other.imag())
}
}
}
}
macro_rules! eq {
{ $T:ty } => {
#[cfg(feature = "integer")]
eq_tuple! { $T, Integer }
#[cfg(feature = "rational")]
eq_tuple! { $T, Rational }
eq_tuple! { $T, Float }
eq_tuple! { $T, u32 }
eq_tuple! { $T, i32 }
eq_tuple! { $T, f64 }
eq_tuple! { $T, f32 }
impl PartialEq<$T> for Complex {
#[inline]
fn eq(&self, other: &$T) -> bool {
self.real().eq(other) && self.imag().is_zero()
}
}
impl PartialEq<Complex> for $T {
#[inline]
fn eq(&self, other: &Complex) -> bool {
self.eq(other.real()) && other.imag().is_zero()
}
}
}
}
#[cfg(feature = "integer")]
eq! { Integer }
#[cfg(feature = "rational")]
eq! { Rational }
eq! { Float }
eq! { u32 }
eq! { i32 }
eq! { f64 }
eq! { f32 }
sum_prod! { Complex, Complex::with_val(53, 0), Complex::with_val(53, 1) }
fn fmt_radix(
c: &Complex,
fmt: &mut Formatter,
radix: i32,
to_upper: bool,
prefix: &str,
show_neg_zero: bool,
) -> fmt::Result {
let (real, imag) = c.as_real_imag();
let mut buf = String::from("(");
fmt_float(&mut buf, real, fmt, radix, to_upper, prefix, show_neg_zero);
buf.push(' ');
fmt_float(&mut buf, imag, fmt, radix, to_upper, prefix, show_neg_zero);
buf.push(')');
let count = buf.chars().count();
let padding = match fmt.width() {
Some(width) if width > count => width - count,
_ => return fmt.write_str(&buf),
};
let mut fill_buf = String::with_capacity(4);
fill_buf.push(fmt.fill());
for _ in 0..padding {
fmt.write_str(&fill_buf)?;
}
fmt.write_str(&buf)
}
fn fmt_float(
buf: &mut String,
flt: &Float,
fmt: &mut Formatter,
radix: i32,
to_upper: bool,
prefix: &str,
show_neg_zero: bool,
) {
let show_neg_zero = show_neg_zero || fmt.sign_plus();
let mut s = flt.to_string_radix(radix, fmt.precision());
let minus = s.starts_with('-') ||
(show_neg_zero && flt.is_zero() && flt.is_sign_negative());
if minus {
buf.push('-');
} else if fmt.sign_plus() {
buf.push('+');
}
if fmt.alternate() {
buf.push_str(prefix);
}
if to_upper && flt.is_finite() {
s.make_ascii_uppercase();
}
buf.push_str(if s.starts_with('-') { &s[1..] } else { &s });
}
#[derive(Clone, Debug)]
pub struct ValidComplex<'a> {
poss: ValidPoss<'a>,
}
#[derive(Clone, Debug)]
enum ValidPoss<'a> {
Real(ValidFloat<'a>),
Complex(ValidFloat<'a>, ValidFloat<'a>),
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct ParseComplexError {
kind: ParseErrorKind,
}
impl<'a> AssignRound<ValidComplex<'a>> for Complex {
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(&mut self, rhs: ValidComplex, round: Round2) -> Ordering2 {
match rhs.poss {
ValidPoss::Real(re) => {
let real_ord = self.mut_real().assign_round(re, round.0);
self.mut_imag().assign(Special::Zero);
(real_ord, Ordering::Equal)
}
ValidPoss::Complex(re, im) => {
let real_ord = self.mut_real().assign_round(re, round.0);
let imag_ord = self.mut_imag().assign_round(im, round.1);
(real_ord, imag_ord)
}
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum ParseErrorKind {
InvalidFloat(ParseFloatError),
InvalidRealFloat(ParseFloatError),
InvalidImagFloat(ParseFloatError),
MissingSpace,
MissingClose,
CloseNotLast,
}
impl Error for ParseComplexError {
fn description(&self) -> &str {
use self::ParseErrorKind::*;
match self.kind {
InvalidFloat(_) => "string is not a valid float",
InvalidRealFloat(_) => "real part of string is not a valid float",
InvalidImagFloat(_) => {
"imaginary part of string is not a valid float"
}
MissingSpace => "string has no space after opening bracket",
MissingClose => "string has no closing bracket",
CloseNotLast => "string has more characters after closing bracket",
}
}
}
impl Display for ParseComplexError {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Debug::fmt(self, f)
}
}
unsafe impl Send for Complex {}
unsafe impl Sync for Complex {}
#[inline]
fn rraw(round: Round) -> mpfr::rnd_t {
match round {
Round::Nearest => mpfr::rnd_t::RNDN,
Round::Zero => mpfr::rnd_t::RNDZ,
Round::Up => mpfr::rnd_t::RNDU,
Round::Down => mpfr::rnd_t::RNDD,
Round::AwayFromZero => mpfr::rnd_t::RNDA,
}
}
#[inline]
fn rraw2(round: Round2) -> mpc::rnd_t {
match (round.0, round.1) {
(Round::Nearest, Round::Nearest) => mpc::RNDNN,
(Round::Nearest, Round::Zero) => mpc::RNDNZ,
(Round::Nearest, Round::Up) => mpc::RNDNU,
(Round::Nearest, Round::Down) => mpc::RNDND,
(Round::Zero, Round::Nearest) => mpc::RNDZN,
(Round::Zero, Round::Zero) => mpc::RNDZZ,
(Round::Zero, Round::Up) => mpc::RNDZU,
(Round::Zero, Round::Down) => mpc::RNDZD,
(Round::Up, Round::Nearest) => mpc::RNDUN,
(Round::Up, Round::Zero) => mpc::RNDUZ,
(Round::Up, Round::Up) => mpc::RNDUU,
(Round::Up, Round::Down) => mpc::RNDUD,
(Round::Down, Round::Nearest) => mpc::RNDDN,
(Round::Down, Round::Zero) => mpc::RNDDZ,
(Round::Down, Round::Up) => mpc::RNDDU,
(Round::Down, Round::Down) => mpc::RNDDD,
(Round::AwayFromZero, _) | (_, Round::AwayFromZero) => unimplemented!(),
}
}
#[inline]
fn ordering1(ord: c_int) -> Ordering {
ord.cmp(&0)
}
#[inline]
fn ordering2(ord: c_int) -> Ordering2 {
let first = mpc::INEX_RE(ord).cmp(&0);
let second = mpc::INEX_IM(ord).cmp(&0);
(first, second)
}
#[inline]
fn ordering4(ord: c_int) -> (Ordering2, Ordering2) {
(ordering2(mpc::INEX1(ord)), ordering2(mpc::INEX2(ord)))
}
impl Inner for Complex {
type Output = mpc_t;
#[inline]
fn inner(&self) -> &mpc_t {
&self.inner
}
}
impl InnerMut for Complex {
#[inline]
unsafe fn inner_mut(&mut self) -> &mut mpc_t {
&mut self.inner
}
}