use super::xmpc;
use float::{self, Constant, Float, ParseFloatError, Round, Special, ValidFloat};
use gmp_mpfr_sys::mpc::{self, mpc_t};
use gmp_mpfr_sys::mpfr;
use inner::{Inner, InnerMut};
use integer::Integer;
use ops::{AddRound, Assign, AssignRound, DivFromAssign, DivRound, FromRound,
MulRound, NegAssign, Pow, PowAssign, PowFromAssign, PowRound,
SubFromAssign, SubRound};
use rand::RandState;
#[cfg(feature = "rational")]
use rational::Rational;
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::mem;
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Shl,
ShlAssign, Shr, ShrAssign, Sub, SubAssign};
use std::os::raw::c_int;
use std::ptr;
type Round2 = (Round, Round);
pub trait Prec {
fn prec(self) -> (u32, u32);
}
impl Prec for u32 {
fn prec(self) -> (u32, u32) {
(self, self)
}
}
impl Prec for (u32, u32) {
fn prec(self) -> (u32, u32) {
self
}
}
type Ordering2 = (Ordering, Ordering);
pub struct Complex {
inner: mpc_t,
}
impl Clone for Complex {
fn clone(&self) -> Complex {
let prec = self.prec();
let mut ret = Complex::new(prec);
ret.assign(self);
ret
}
fn clone_from(&mut self, source: &Complex) {
self.assign(source);
}
}
impl Drop for Complex {
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_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_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_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_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 {
pub fn new<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 inner: mpc_t = mem::uninitialized();
mpc::init3(&mut inner, p.0 as mpfr::prec_t, p.1 as mpfr::prec_t);
let real = mpc::realref(&mut inner);
let imag = mpc::imagref(&mut inner);
mpfr::set_zero(real, 0);
mpfr::set_zero(imag, 0);
Complex { inner: inner }
}
}
pub fn prec(&self) -> (u32, u32) {
(self.real().prec(), self.imag().prec())
}
pub fn set_prec<P: Prec>(&mut self, prec: P) {
self.set_prec_round(prec, Default::default());
}
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),
)
}
pub fn from_str<P: Prec>(
src: &str,
prec: P,
) -> Result<Complex, ParseComplexError> {
let mut val = Complex::new(prec);
val.assign_str(src)?;
Ok(val)
}
pub fn from_str_round<P: Prec>(
src: &str,
prec: P,
round: Round2,
) -> Result<(Complex, Ordering2), ParseComplexError> {
let mut val = Complex::new(prec);
let ord = val.assign_str_round(src, round)?;
Ok((val, ord))
}
pub fn from_str_radix<P: Prec>(
src: &str,
radix: i32,
prec: P,
) -> Result<Complex, ParseComplexError> {
let mut val = Complex::new(prec);
val.assign_str_radix(src, radix)?;
Ok(val)
}
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(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 })
}
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
}
pub fn assign_str(&mut self, src: &str) -> Result<(), ParseComplexError> {
self.assign_str_radix(src, 10)
}
pub fn assign_str_round(
&mut self,
src: &str,
round: Round2,
) -> Result<Ordering2, ParseComplexError> {
self.assign_str_radix_round(src, 10, round)
}
pub fn assign_str_radix(
&mut self,
src: &str,
radix: i32,
) -> Result<(), ParseComplexError> {
self.assign_str_radix_round(src, radix, Default::default())
.map(|_| ())
}
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,
))
}
pub fn real(&self) -> &Float {
unsafe {
let ptr = mpc::realref_const(self.inner());
&*(ptr as *const Float)
}
}
pub fn imag(&self) -> &Float {
unsafe {
let ptr = mpc::imagref_const(self.inner());
&*(ptr as *const Float)
}
}
pub fn mut_real(&mut self) -> &mut Float {
unsafe {
let ptr = mpc::realref(self.inner_mut());
&mut *(ptr as *mut Float)
}
}
pub fn mut_imag(&mut self) -> &mut Float {
unsafe {
let ptr = mpc::imagref(self.inner_mut());
&mut *(ptr as *mut Float)
}
}
pub fn as_real_imag(&self) -> (&Float, &Float) {
(self.real(), self.imag())
}
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),
)
}
}
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)
}
math_op1_complex! {
mpc::proj;
fn proj();
fn proj_round;
fn proj_ref -> ProjRef;
}
math_op1_complex! {
mpc::sqr;
fn square();
fn square_round;
fn square_ref -> SquareRef;
}
math_op1_complex! {
mpc::sqrt;
fn sqrt();
fn sqrt_round;
fn sqrt_ref -> SqrtRef;
}
math_op1_complex! {
mpc::conj;
fn conjugate();
fn conjugate_round;
fn conjugate_ref -> ConjugateRef;
}
pub fn abs_ref(&self) -> AbsRef {
AbsRef { ref_self: self }
}
pub fn arg_ref(&self) -> ArgRef {
ArgRef { ref_self: self }
}
math_op1_complex! {
xmpc::mul_i;
fn mul_i(negative: bool);
fn mul_i_round;
fn mul_i_ref -> MulIRef;
}
math_op1_complex! {
xmpc::recip;
fn recip();
fn recip_round;
fn recip_ref -> RecipRef;
}
pub fn norm_ref(&self) -> NormRef {
NormRef { ref_self: self }
}
math_op1_complex! {
mpc::log;
fn ln();
fn ln_round;
fn ln_ref -> LnRef;
}
math_op1_complex! {
mpc::log10;
fn log10();
fn log10_round;
fn log10_ref -> Log10Ref;
}
math_op1_complex! {
mpc::exp;
fn exp();
fn exp_round;
fn exp_ref -> ExpRef;
}
math_op1_complex! {
mpc::sin;
fn sin();
fn sin_round;
fn sin_ref -> SinRef;
}
math_op1_complex! {
mpc::cos;
fn cos();
fn cos_round;
fn cos_ref -> CosRef;
}
math_op1_2_complex! {
mpc::sin_cos;
fn sin_cos(cos);
fn sin_cos_round;
fn sin_cos_ref -> SinCosRef;
}
math_op1_complex! {
mpc::tan;
fn tan();
fn tan_round;
fn tan_ref -> TanRef;
}
math_op1_complex! {
mpc::sinh;
fn sinh();
fn sinh_round;
fn sinh_ref -> SinhRef;
}
math_op1_complex! {
mpc::cosh;
fn cosh();
fn cosh_round;
fn cosh_ref -> CoshRef;
}
math_op1_complex! {
mpc::tanh;
fn tanh();
fn tanh_round;
fn tanh_ref -> TanhRef;
}
math_op1_complex! {
mpc::asin;
fn asin();
fn asin_round;
fn asin_ref -> AsinRef;
}
math_op1_complex! {
mpc::acos;
fn acos();
fn acos_round;
fn acos_ref -> AcosRef;
}
math_op1_complex! {
mpc::atan;
fn atan();
fn atan_round;
fn atan_ref -> AtanRef;
}
math_op1_complex! {
mpc::asinh;
fn asinh();
fn asinh_round;
fn asinh_ref -> AsinhRef;
}
math_op1_complex! {
mpc::acosh;
fn acosh();
fn acosh_round;
fn acosh_ref -> AcoshRef;
}
math_op1_complex! {
mpc::atanh;
fn atanh();
fn atanh_round;
fn atanh_ref -> AtanhRef;
}
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)
}
pub fn assign_random_cont(&mut self, rng: &mut RandState) {
self.assign_random_cont_round(rng, Default::default());
}
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 {
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<T, P: Prec> From<(T, P)> for Complex
where
Complex: FromRound<T, P, Round = Round2>,
{
fn from((t, prec): (T, P)) -> Complex {
Complex::from_round(t, prec, Default::default()).0
}
}
impl<T, P: Prec> FromRound<T, P> for Complex
where
Complex: AssignRound<
T,
Round = Round2,
Ordering = Ordering2,
>,
{
type Round = Round2;
type Ordering = Ordering2;
fn from_round(t: T, prec: P, round: Round2) -> (Complex, Ordering2) {
let mut ret = Complex::new(prec);
let ord = ret.assign_round(t, round);
(ret, ord)
}
}
impl Display for Complex {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 10, false, "", false)
}
}
impl Debug for Complex {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 10, false, "", true)
}
}
impl LowerExp for Complex {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 10, false, "", false)
}
}
impl UpperExp for Complex {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 10, true, "", false)
}
}
impl Binary for Complex {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 2, false, "0b", false)
}
}
impl Octal for Complex {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 8, false, "0o", false)
}
}
impl LowerHex for Complex {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
fmt_radix(self, f, 16, false, "0x", false)
}
}
impl UpperHex for Complex {
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,
>,
{
fn assign(&mut self, other: T) {
self.assign_round(other, Default::default());
}
}
impl AssignRound<Complex> for Complex {
type Round = Round2;
type Ordering = Ordering2;
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;
fn assign_round(&mut self, other: &Complex, round: Round2) -> Ordering2 {
let mpc_ret =
unsafe { mpc::set(self.inner_mut(), other.inner(), rraw2(round)) };
ordering2(mpc_ret)
}
}
macro_rules! assign_ref {
{ $T:ty } => {
impl<'a> AssignRound<&'a $T> for Complex {
type Round = Round2;
type Ordering = Ordering2;
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;
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)
}
}
};
}
assign_ref! { Integer }
#[cfg(feature = "rational")]
assign_ref! { Rational }
assign_ref! { Float }
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;
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;
fn assign_round(&mut self, src: AbsRef<'a>, round: Round) -> Ordering {
let mpc_ret = unsafe {
mpc::abs(self.inner_mut(), src.ref_self.inner(), rraw(round))
};
mpc_ret.cmp(&0)
}
}
pub struct ArgRef<'a> {
ref_self: &'a Complex,
}
impl<'a> AssignRound<ArgRef<'a>> for Float {
type Round = Round;
type Ordering = Ordering;
fn assign_round(&mut self, src: ArgRef<'a>, round: Round) -> Ordering {
let mpc_ret = unsafe {
mpc::arg(self.inner_mut(), src.ref_self.inner(), rraw(round))
};
mpc_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;
fn assign_round(&mut self, src: NormRef<'a>, round: Round) -> Ordering {
let mpc_ret = unsafe {
mpc::norm(self.inner_mut(), src.ref_self.inner(), rraw(round))
};
mpc_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 {} }
impl Neg for Complex {
type Output = Complex;
fn neg(mut self) -> Complex {
self.neg_assign();
self
}
}
impl NegAssign for Complex {
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>;
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;
fn assign_round(&mut self, src: NegRef<'a>, round: Round2) -> Ordering2 {
let mpc_ret = unsafe {
mpc::neg(self.inner_mut(), src.val.inner(), rraw2(round))
};
ordering2(mpc_ret)
}
}
macro_rules! arith_commut_self_complex {
{
$func:path;
$Imp:ident $method:ident;
$ImpRound:ident $method_round:ident;
$ImpAssign:ident $method_assign:ident;
$Ref:ident $RefOwn:ident
} => {
arith_commut_self_round! {
Complex, Round2 => Ordering2;
$func, rraw2 => ordering2;
$Imp $method;
$ImpRound $method_round;
$ImpAssign $method_assign;
$Ref $RefOwn
}
}
}
macro_rules! arith_noncommut_self_complex {
{
$func:path;
$Imp:ident $method:ident;
$ImpRound:ident $method_round:ident;
$ImpAssign:ident $method_assign:ident;
$ImpFromAssign:ident $method_from_assign:ident;
$Ref:ident $RefOwn:ident
} => {
arith_noncommut_self_round! {
Complex, Round2 => Ordering2;
$func, rraw2 => ordering2;
$Imp $method;
$ImpRound $method_round;
$ImpAssign $method_assign;
$ImpFromAssign $method_from_assign;
$Ref $RefOwn
}
}
}
macro_rules! arith_forward_complex {
{
$func:path;
$Imp:ident $method:ident;
$ImpRound:ident $method_round:ident;
$ImpAssign:ident $method_assign:ident;
$T:ty;
$Ref:ident $RefOwn:ident
} => {
arith_forward_round! {
Complex, Round2 => Ordering2;
$func, rraw2 => ordering2;
$Imp $method;
$ImpRound $method_round;
$ImpAssign $method_assign;
$T;
$Ref $RefOwn
}
}
}
macro_rules! arith_commut_complex {
{
$func:path;
$Imp:ident $method:ident;
$ImpRound:ident $method_round:ident;
$ImpAssign:ident $method_assign:ident;
$T:ty;
$Ref:ident $RefOwn:ident
} => {
arith_commut_round! {
Complex, Round2 => Ordering2;
$func, rraw2 => ordering2;
$Imp $method;
$ImpRound $method_round;
$ImpAssign $method_assign;
$T;
$Ref $RefOwn
}
}
}
macro_rules! arith_noncommut_complex {
{
$func:path, $func_from:path;
$Imp:ident $method:ident;
$ImpRound:ident $method_round:ident;
$ImpAssign:ident $method_assign:ident;
$ImpFromAssign:ident $method_from_assign:ident;
$T:ty;
$Ref:ident $RefFrom:ident $RefOwn:ident $RefFromOwn:ident
} => {
arith_noncommut_round! {
Complex, Round2 => Ordering2;
$func, $func_from, rraw2 => ordering2;
$Imp $method;
$ImpRound $method_round;
$ImpAssign $method_assign;
$ImpFromAssign $method_from_assign;
$T;
$Ref $RefFrom $RefOwn $RefFromOwn
}
}
}
arith_commut_self_complex! {
mpc::add;
Add add;
AddRound add_round;
AddAssign add_assign;
AddRef AddRefOwn
}
arith_noncommut_self_complex! {
mpc::sub;
Sub sub;
SubRound sub_round;
SubAssign sub_assign;
SubFromAssign sub_from_assign;
SubRef SubRefOwn
}
arith_commut_self_complex! {
mpc::mul;
Mul mul;
MulRound mul_round;
MulAssign mul_assign;
MulRef MulRefOwn
}
arith_noncommut_self_complex! {
mpc::div;
Div div;
DivRound div_round;
DivAssign div_assign;
DivFromAssign div_from_assign;
DivRef DivRefOwn
}
arith_noncommut_self_complex! {
mpc::pow;
Pow pow;
PowRound pow_round;
PowAssign pow_assign;
PowFromAssign pow_from_assign;
PowRef PowRefOwn
}
arith_commut_complex! {
mpc::add_fr;
Add add;
AddRound add_round;
AddAssign add_assign;
Float;
AddRefFloat AddRefFloatOwn
}
arith_noncommut_complex! {
mpc::sub_fr, mpc::fr_sub;
Sub sub;
SubRound sub_round;
SubAssign sub_assign;
SubFromAssign sub_from_assign;
Float;
SubRefFloat SubFromRefFloat SubRefFloatOwn SubFromRefFloatOwn
}
arith_commut_complex! {
mpc::mul_fr;
Mul mul;
MulRound mul_round;
MulAssign mul_assign;
Float;
MulRefFloat MulRefFloatOwn
}
arith_noncommut_complex! {
mpc::div_fr, mpc::fr_div;
Div div;
DivRound div_round;
DivAssign div_assign;
DivFromAssign div_from_assign;
Float;
DivRefFloat DivFromRefFloat DivRefFloatOwn DivFromRefFloatOwn
}
arith_forward_complex! {
mpc::pow_fr;
Pow pow;
PowRound pow_round;
PowAssign pow_assign;
Float;
PowRefFloat PowRefFloatOwn
}
arith_forward_complex! {
mpc::pow_z;
Pow pow;
PowRound pow_round;
PowAssign pow_assign;
Integer;
PowRefInteger PowRefIntegerOwn
}
macro_rules! arith_prim_complex {
{
$func:path;
$Imp:ident $method:ident;
$ImpRound:ident $method_round:ident;
$ImpAssign:ident $method_assign:ident;
$T:ty;
$Ref:ident
} => {
arith_prim_round! {
Complex, Round2 => Ordering2;
$func, rraw2 => ordering2;
$Imp $method;
$ImpRound $method_round;
$ImpAssign $method_assign;
$T;
$Ref
}
}
}
macro_rules! arith_prim_shift_complex {
{
$func:path;
$Imp:ident $method:ident;
$ImpAssign:ident $method_assign:ident;
$T:ty;
$Ref:ident
} => {
arith_prim_shift_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;
$ImpRound:ident $method_round:ident;
$ImpAssign:ident $method_assign:ident;
$T:ty;
$Ref:ident
} => {
arith_prim_commut_round! {
Complex, Round2 => Ordering2;
$func, rraw2 => ordering2;
$Imp $method;
$ImpRound $method_round;
$ImpAssign $method_assign;
$T;
$Ref
}
}
}
macro_rules! arith_prim_noncommut_complex {
{
$func:path, $func_from:path;
$Imp:ident $method:ident;
$ImpRound:ident $method_round:ident;
$ImpAssign:ident $method_assign:ident;
$ImpFromAssign:ident $method_from_assign:ident;
$T:ty;
$Ref:ident $RefFrom:ident
} => {
arith_prim_noncommut_round! {
Complex, Round2 => Ordering2;
$func, $func_from, rraw2 => ordering2;
$Imp $method;
$ImpRound $method_round;
$ImpAssign $method_assign;
$ImpFromAssign $method_from_assign;
$T;
$Ref $RefFrom
}
}
}
arith_prim_commut_complex! {
mpc::add_ui;
Add add;
AddRound add_round;
AddAssign add_assign;
u32;
AddRefU32
}
arith_prim_noncommut_complex! {
mpc::sub_ui, xmpc::ui_sub;
Sub sub;
SubRound sub_round;
SubAssign sub_assign;
SubFromAssign sub_from_assign;
u32;
SubRefU32 SubFromRefU32
}
arith_prim_commut_complex! {
mpc::mul_ui;
Mul mul;
MulRound mul_round;
MulAssign mul_assign;
u32;
MulRefU32
}
arith_prim_noncommut_complex! {
mpc::div_ui, xmpc::ui_div;
Div div;
DivRound div_round;
DivAssign div_assign;
DivFromAssign div_from_assign;
u32;
DivRefU32 DivFromRefU32
}
arith_prim_commut_complex! {
xmpc::add_si;
Add add;
AddRound add_round;
AddAssign add_assign;
i32;
AddRefI32
}
arith_prim_noncommut_complex! {
xmpc::sub_si, xmpc::si_sub;
Sub sub;
SubRound sub_round;
SubAssign sub_assign;
SubFromAssign sub_from_assign;
i32;
SubRefI32 SubFromRefI32
}
arith_prim_commut_complex! {
mpc::mul_si;
Mul mul;
MulRound mul_round;
MulAssign mul_assign;
i32;
MulRefI32
}
arith_prim_noncommut_complex! {
xmpc::div_si, xmpc::si_div;
Div div;
DivRound div_round;
DivAssign div_assign;
DivFromAssign div_from_assign;
i32;
DivRefI32 DivFromRefI32
}
arith_prim_shift_complex! {
mpc::mul_2ui;
Shl shl;
ShlAssign shl_assign;
u32;
ShlRefU32
}
arith_prim_shift_complex! {
mpc::div_2ui;
Shr shr;
ShrAssign shr_assign;
u32;
ShrRefU32
}
arith_prim_complex! {
mpc::pow_ui;
Pow pow;
PowRound pow_round;
PowAssign pow_assign;
u32;
PowRefU32
}
arith_prim_shift_complex! {
mpc::mul_2si;
Shl shl;
ShlAssign shl_assign;
i32;
ShlRefI32
}
arith_prim_shift_complex! {
mpc::div_2si;
Shr shr;
ShrAssign shr_assign;
i32;
ShrRefI32
}
arith_prim_complex! {
mpc::pow_si;
Pow pow;
PowRound pow_round;
PowAssign pow_assign;
i32;
PowRefI32
}
arith_prim_complex! {
mpc::pow_d;
Pow pow;
PowRound pow_round;
PowAssign pow_assign;
f64;
PowRefF64
}
arith_prim_complex! {
xmpc::pow_f32;
Pow pow;
PowRound pow_round;
PowAssign pow_assign;
f32;
PowRefF32
}
impl<'a> Add<MulRef<'a>> for Complex {
type Output = Complex;
fn add(self, rhs: MulRef) -> Complex {
self.add_round(rhs, Default::default()).0
}
}
impl<'a> AddRound<MulRef<'a>> for Complex {
type Round = Round2;
type Ordering = Ordering2;
type Output = Complex;
fn add_round(mut self, rhs: MulRef, round: Round2) -> (Complex, Ordering2) {
let mpc_ret = unsafe {
mpc::fma(
self.inner_mut(),
rhs.lhs.inner(),
rhs.rhs.inner(),
self.inner(),
rraw2(round),
)
};
(self, ordering2(mpc_ret))
}
}
impl<'a> AddAssign<MulRef<'a>> for Complex {
fn add_assign(&mut self, rhs: MulRef) {
unsafe {
mpc::fma(
self.inner_mut(),
rhs.lhs.inner(),
rhs.rhs.inner(),
self.inner(),
rraw2(Default::default()),
);
}
}
}
impl PartialEq for Complex {
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>,
{
fn eq(&self, other: &(T, U)) -> bool {
self.real().eq(&other.0) && self.imag().eq(&other.1)
}
}
macro_rules! partial_eq {
{ $T:ty } => {
impl PartialEq<$T> for Complex {
fn eq(&self, other: &$T) -> bool {
self.real().eq(other) && self.imag().is_zero()
}
}
}
}
partial_eq! { Integer }
#[cfg(feature = "rational")]
partial_eq! { Rational }
partial_eq! { Float }
partial_eq! { u32 }
partial_eq! { i32 }
partial_eq! { f64 }
partial_eq! { f32 }
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.get_sign());
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, Debug, Eq, PartialEq)]
pub struct ParseComplexError {
kind: ParseErrorKind,
}
impl<'a> AssignRound<ValidComplex<'a>> for Complex {
type Round = Round2;
type Ordering = Ordering2;
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, Debug, Eq, PartialEq)]
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 {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Debug::fmt(self, f)
}
}
unsafe impl Send for Complex {}
unsafe impl Sync for Complex {}
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,
}
}
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!(),
}
}
fn ordering2(ord: c_int) -> Ordering2 {
let first = mpc::INEX_RE(ord).cmp(&0);
let second = mpc::INEX_IM(ord).cmp(&0);
(first, second)
}
fn ordering4(ord: c_int) -> (Ordering2, Ordering2) {
(ordering2(mpc::INEX1(ord)), ordering2(mpc::INEX2(ord)))
}
impl Inner for Complex {
type Output = mpc_t;
fn inner(&self) -> &mpc_t {
&self.inner
}
}
impl InnerMut for Complex {
unsafe fn inner_mut(&mut self) -> &mut mpc_t {
&mut self.inner
}
}