use crate::cast::cast;
use crate::complex::arith::{AddMulIncomplete, SubMulFromIncomplete};
use crate::complex::{OrdComplex, Prec};
use crate::ext::xmpc::{self, ordering2, raw_round2, Ordering2, Round2};
use crate::ext::xmpfr::raw_round;
use crate::float::big::{
self as big_float, ExpFormat, Format as FloatFormat,
ParseIncomplete as FloatParseIncomplete,
};
use crate::float::{self, ParseFloatError, Round, Special};
use crate::misc;
use crate::ops::{AddAssignRound, AssignRound, NegAssign};
#[cfg(feature = "rand")]
use crate::rand::RandState;
use crate::{Assign, Float};
use gmp_mpfr_sys::mpc::{self, mpc_t};
use gmp_mpfr_sys::mpfr;
use std::cmp::{self, Ordering};
use std::error::Error;
use std::marker::PhantomData;
use std::mem;
use std::ops::{Add, AddAssign, Deref};
use std::os::raw::c_int;
use std::slice;
#[repr(transparent)]
pub struct Complex {
inner: mpc_t,
}
fn _static_assertions() {
static_assert_size!(Complex, mpc_t);
static_assert_size!(BorrowComplex<'_>, mpc_t);
}
macro_rules! ref_math_op0_complex {
(
$func:path;
$(#[$attr_ref:meta])*
struct $Incomplete:ident { $($param:ident: $T:ty),* }
) => {
ref_math_op0_round! {
Complex, Round2 => Ordering2;
$func;
$(#[$attr_ref])*
struct $Incomplete { $($param: $T),* }
}
};
}
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 -> $Incomplete:ident;
) => {
math_op1_round! {
Round2 => Ordering2;
$func;
$(#[$attr])*
fn $method($($param: $T),*);
$(#[$attr_mut])*
fn $method_mut;
$(#[$attr_round])*
fn $method_round;
$(#[$attr_ref])*
fn $method_ref -> $Incomplete;
}
};
}
macro_rules! ref_math_op1_complex {
(
$func:path;
$(#[$attr_ref:meta])*
struct $Incomplete:ident { $($param:ident: $T:ty),* }
) => {
ref_math_op1_round! {
Complex, Round2 => Ordering2;
$func;
$(#[$attr_ref])*
struct $Incomplete { $($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 -> $Incomplete:ident;
) => {
math_op1_2_round! {
Round2 => (Ordering2, Ordering2);
$func;
$(#[$attr])*
fn $method($rop $(, $param: $T)*);
$(#[$attr_mut])*
fn $method_mut;
$(#[$attr_round])*
fn $method_round;
$(#[$attr_ref])*
fn $method_ref -> $Incomplete;
}
};
}
macro_rules! ref_math_op1_2_complex {
(
$func:path;
$(#[$attr_ref:meta])*
struct $Incomplete:ident { $($param:ident: $T:ty),* }
) => {
ref_math_op1_2_round! {
Complex, Round2 => (Ordering2, Ordering2);
$func;
$(#[$attr_ref])*
struct $Incomplete { $($param: $T),* }
}
};
}
impl Complex {
#[inline]
fn new_nan<P>(prec: P) -> Self
where
P: Prec,
{
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.as_raw_mut(), cast(p.0), cast(p.1));
c
}
}
#[inline]
pub fn new<P>(prec: P) -> Self
where
P: Prec,
{
Self::with_val(prec, (Special::Zero, Special::Zero))
}
#[inline]
pub fn with_val<P, T>(prec: P, val: T) -> Self
where
Self: Assign<T>,
P: Prec,
{
let mut ret = Complex::new_nan(prec);
ret.assign(val);
ret
}
#[inline]
pub fn with_val_round<P, T>(
prec: P,
val: T,
round: Round2,
) -> (Self, Ordering2)
where
Self: AssignRound<T, Round = Round2, Ordering = Ordering2>,
P: Prec,
{
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>(&mut self, prec: P)
where
P: Prec,
{
self.set_prec_round(prec, Default::default());
}
#[inline]
pub fn set_prec_round<P>(&mut self, prec: P, round: Round2) -> Ordering2
where
P: Prec,
{
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 unsafe fn from_raw(raw: mpc_t) -> Self {
Complex { inner: raw }
}
#[inline]
pub fn into_raw(self) -> mpc_t {
let ret = self.inner;
mem::forget(self);
ret
}
#[inline]
pub fn as_raw(&self) -> *const mpc_t {
&self.inner
}
#[inline]
pub fn as_raw_mut(&mut self) -> *mut mpc_t {
&mut self.inner
}
pub fn parse<S>(src: S) -> Result<ParseIncomplete, ParseComplexError>
where
S: AsRef<[u8]>,
{
parse(src.as_ref(), 10)
}
pub fn parse_radix<S>(
src: S,
radix: i32,
) -> Result<ParseIncomplete, ParseComplexError>
where
S: AsRef<[u8]>,
{
parse(src.as_ref(), radix)
}
#[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 s = String::new();
let format = Format {
radix,
precision: num_digits,
round,
to_upper: false,
sign_plus: false,
prefix: "",
exp: ExpFormat::ExpOrPoint,
};
append_to_string(&mut s, self, format);
s
}
#[inline]
pub fn real(&self) -> &Float {
unsafe { &*cast_ptr!(mpc::realref_const(self.as_raw()), Float) }
}
#[inline]
pub fn imag(&self) -> &Float {
unsafe { &*cast_ptr!(mpc::imagref_const(self.as_raw()), Float) }
}
#[inline]
pub fn mut_real(&mut self) -> &mut Float {
unsafe { &mut *cast_ptr_mut!(mpc::realref(self.as_raw_mut()), Float) }
}
#[inline]
pub fn mut_imag(&mut self) -> &mut Float {
unsafe { &mut *cast_ptr_mut!(mpc::imagref(self.as_raw_mut()), Float) }
}
#[inline]
pub fn as_mut_real_imag(&mut self) -> (&mut Float, &mut Float) {
unsafe {
(
&mut *cast_ptr_mut!(mpc::realref(self.as_raw_mut()), Float),
&mut *cast_ptr_mut!(mpc::imagref(self.as_raw_mut()), Float),
)
}
}
#[inline]
pub fn into_real_imag(self) -> (Float, Float) {
let raw = self.into_raw();
unsafe {
let real = mpc::realref_const(&raw).read();
let imag = mpc::imagref_const(&raw).read();
(Float::from_raw(real), Float::from_raw(imag))
}
}
pub fn as_neg(&self) -> BorrowComplex<'_> {
let mut ret = BorrowComplex { inner: self.inner, phantom: PhantomData };
unsafe {
NegAssign::neg_assign(&mut (*mpc::realref(&mut ret.inner)).sign);
NegAssign::neg_assign(&mut (*mpc::imagref(&mut ret.inner)).sign);
if self.real().is_nan() || self.imag().is_nan() {
mpfr::set_nanflag();
}
}
ret
}
pub fn as_conj(&self) -> BorrowComplex<'_> {
let mut ret = BorrowComplex { inner: self.inner, phantom: PhantomData };
unsafe {
NegAssign::neg_assign(&mut (*mpc::imagref(&mut ret.inner)).sign);
if self.imag().is_nan() {
mpfr::set_nanflag();
}
}
ret
}
pub fn as_mul_i(&self, negative: bool) -> BorrowComplex<'_> {
let mut inner: mpc_t = unsafe { mem::uninitialized() };
unsafe {
let mut dst_re = self.imag().as_raw().read();
let mut dst_im = self.real().as_raw().read();
if negative {
NegAssign::neg_assign(&mut dst_im.sign);
} else {
NegAssign::neg_assign(&mut dst_re.sign);
}
mpc::realref(&mut inner).write(dst_re);
mpc::imagref(&mut inner).write(dst_im);
}
if self.real().is_nan() || self.imag().is_nan() {
unsafe {
mpfr::set_nanflag();
}
}
BorrowComplex { inner, phantom: PhantomData }
}
#[inline]
pub fn as_ord(&self) -> &OrdComplex {
unsafe { &*cast_ptr!(self, OrdComplex) }
}
#[inline]
pub fn eq0(&self) -> bool {
self.real().cmp0() == Some(Ordering::Equal)
&& self.imag().cmp0() == Some(Ordering::Equal)
}
#[inline]
pub fn cmp_abs(&self, other: &Self) -> Option<Ordering> {
if self.real().is_nan()
|| self.imag().is_nan()
|| other.real().is_nan()
|| other.imag().is_nan()
{
None
} else {
unsafe {
Some(ordering1(mpc::cmp_abs(self.as_raw(), other.as_raw())))
}
}
}
#[inline]
pub fn sum<'a, I>(values: I) -> SumIncomplete<'a, I>
where
I: Iterator<Item = &'a Self>,
{
SumIncomplete { values }
}
#[inline]
pub fn dot<'a, I>(values: I) -> DotIncomplete<'a, I>
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
DotIncomplete { values }
}
pub fn mul_add(mut self, mul: &Self, add: &Self) -> Self {
self.mul_add_round(mul, add, Default::default());
self
}
pub fn mul_add_mut(&mut self, mul: &Self, add: &Self) {
self.mul_add_round(mul, add, Default::default());
}
pub fn mul_add_round(
&mut self,
mul: &Self,
add: &Self,
round: Round2,
) -> Ordering2 {
xmpc::fma(self, None, Some(mul), Some(add), round)
}
pub fn mul_add_ref<'a>(
&'a self,
mul: &'a Self,
add: &'a Self,
) -> AddMulIncomplete<'a> {
self * mul + add
}
pub fn mul_sub(mut self, mul: &Self, sub: &Self) -> Self {
self.mul_sub_round(mul, sub, Default::default());
self
}
pub fn mul_sub_mut(&mut self, mul: &Self, sub: &Self) {
self.mul_sub_round(mul, sub, Default::default());
}
pub fn mul_sub_round(
&mut self,
mul: &Self,
sub: &Self,
round: Round2,
) -> Ordering2 {
let ret = unsafe {
xmpc::mulsub(
self.as_raw_mut(),
(self.as_raw(), mul.as_raw()),
sub.as_raw(),
raw_round2(round),
)
};
ordering2(ret)
}
pub fn mul_sub_ref<'a>(
&'a self,
mul: &'a Self,
sub: &'a Self,
) -> SubMulFromIncomplete<'a> {
self * mul - sub
}
math_op1_no_round! {
xmpc::proj;
fn proj();
fn proj_mut;
fn proj_ref -> ProjIncomplete;
}
math_op1_complex! {
xmpc::sqr;
fn square();
fn square_mut;
fn square_round;
fn square_ref -> SquareIncomplete;
}
math_op1_complex! {
xmpc::sqrt;
fn sqrt();
fn sqrt_mut;
fn sqrt_round;
fn sqrt_ref -> SqrtIncomplete;
}
math_op1_no_round! {
xmpc::conj;
fn conj();
fn conj_mut;
fn conj_ref -> ConjIncomplete;
}
#[inline]
pub fn abs(mut self) -> Complex {
self.abs_mut();
self
}
#[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) -> AbsIncomplete<'_> {
AbsIncomplete { ref_self: self }
}
#[inline]
pub fn arg(mut self) -> Complex {
self.arg_round(Default::default());
self
}
#[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.as_raw_mut(),
im.as_raw(),
re.as_raw(),
raw_round(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) -> ArgIncomplete<'_> {
ArgIncomplete { 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 -> MulIIncomplete;
}
math_op1_complex! {
xmpc::recip;
fn recip();
fn recip_mut;
fn recip_round;
fn recip_ref -> RecipIncomplete;
}
#[inline]
pub fn norm(mut self) -> Complex {
self.norm_round(Default::default());
self
}
#[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) -> NormIncomplete<'_> {
NormIncomplete { ref_self: self }
}
math_op1_complex! {
xmpc::log;
fn ln();
fn ln_mut;
fn ln_round;
fn ln_ref -> LnIncomplete;
}
math_op1_complex! {
xmpc::log10;
fn log10();
fn log10_mut;
fn log10_round;
fn log10_ref -> Log10Incomplete;
}
math_op0! {
fn root_of_unity(n: u32, k: u32) -> RootOfUnityIncomplete;
}
math_op1_complex! {
xmpc::exp;
fn exp();
fn exp_mut;
fn exp_round;
fn exp_ref -> ExpIncomplete;
}
math_op1_complex! {
xmpc::sin;
fn sin();
fn sin_mut;
fn sin_round;
fn sin_ref -> SinIncomplete;
}
math_op1_complex! {
xmpc::cos;
fn cos();
fn cos_mut;
fn cos_round;
fn cos_ref -> CosIncomplete;
}
math_op1_2_complex! {
xmpc::sin_cos;
fn sin_cos(cos);
fn sin_cos_mut;
fn sin_cos_round;
fn sin_cos_ref -> SinCosIncomplete;
}
math_op1_complex! {
xmpc::tan;
fn tan();
fn tan_mut;
fn tan_round;
fn tan_ref -> TanIncomplete;
}
math_op1_complex! {
xmpc::sinh;
fn sinh();
fn sinh_mut;
fn sinh_round;
fn sinh_ref -> SinhIncomplete;
}
math_op1_complex! {
xmpc::cosh;
fn cosh();
fn cosh_mut;
fn cosh_round;
fn cosh_ref -> CoshIncomplete;
}
math_op1_complex! {
xmpc::tanh;
fn tanh();
fn tanh_mut;
fn tanh_round;
fn tanh_ref -> TanhIncomplete;
}
math_op1_complex! {
xmpc::asin;
fn asin();
fn asin_mut;
fn asin_round;
fn asin_ref -> AsinIncomplete;
}
math_op1_complex! {
xmpc::acos;
fn acos();
fn acos_mut;
fn acos_round;
fn acos_ref -> AcosIncomplete;
}
math_op1_complex! {
xmpc::atan;
fn atan();
fn atan_mut;
fn atan_round;
fn atan_ref -> AtanIncomplete;
}
math_op1_complex! {
xmpc::asinh;
fn asinh();
fn asinh_mut;
fn asinh_round;
fn asinh_ref -> AsinhIncomplete;
}
math_op1_complex! {
xmpc::acosh;
fn acosh();
fn acosh_mut;
fn acosh_round;
fn acosh_ref -> AcoshIncomplete;
}
math_op1_complex! {
xmpc::atanh;
fn atanh();
fn atanh_mut;
fn atanh_round;
fn atanh_ref -> AtanhIncomplete;
}
#[cfg(feature = "rand")]
#[inline]
pub fn random_bits<'a, 'b>(
rng: &'a mut RandState<'b>,
) -> RandomBitsIncomplete<'a, 'b>
where
'b: 'a,
{
RandomBitsIncomplete { rng }
}
#[cfg(feature = "rand")]
#[inline]
pub fn random_cont<'a, 'b>(rng: &'a mut RandState<'b>) -> RandomCont<'a, 'b>
where
'b: 'a,
{
RandomCont { rng }
}
}
#[derive(Debug)]
pub struct SumIncomplete<'a, I>
where
I: Iterator<Item = &'a Complex>,
{
values: I,
}
impl<'a, I> AssignRound<SumIncomplete<'a, I>> for Complex
where
I: Iterator<Item = &'a Self>,
{
type Round = Round2;
type Ordering = Ordering2;
fn assign_round(
&mut self,
src: SumIncomplete<'a, I>,
round: Round2,
) -> Ordering2 {
let capacity = match src.values.size_hint() {
(lower, None) => lower,
(_, Some(upper)) => upper,
};
let mut reals = Vec::<*const mpfr::mpfr_t>::with_capacity(capacity);
let mut imags = Vec::<*const mpfr::mpfr_t>::with_capacity(capacity);
for value in src.values {
reals.push(value.real().as_raw());
imags.push(value.imag().as_raw());
}
let tab_real = cast_ptr!(reals.as_ptr(), *mut mpfr::mpfr_t);
let tab_imag = cast_ptr!(imags.as_ptr(), *mut mpfr::mpfr_t);
let n = cast(reals.len());
let (ord_real, ord_imag) = unsafe {
let (real, imag) = self.as_mut_real_imag();
(
mpfr::sum(real.as_raw_mut(), tab_real, n, raw_round(round.0)),
mpfr::sum(imag.as_raw_mut(), tab_imag, n, raw_round(round.1)),
)
};
(ordering1(ord_real), ordering1(ord_imag))
}
}
impl<'a, I> Add<SumIncomplete<'a, I>> for Complex
where
I: Iterator<Item = &'a Self>,
{
type Output = Self;
#[inline]
fn add(mut self, rhs: SumIncomplete<'a, I>) -> Self {
self.add_assign_round(rhs, Default::default());
self
}
}
impl<'a, I> AddAssign<SumIncomplete<'a, I>> for Complex
where
I: Iterator<Item = &'a Self>,
{
#[inline]
fn add_assign(&mut self, rhs: SumIncomplete<'a, I>) {
self.add_assign_round(rhs, Default::default());
}
}
impl<'a, I> AddAssignRound<SumIncomplete<'a, I>> for Complex
where
I: Iterator<Item = &'a Self>,
{
type Round = Round2;
type Ordering = Ordering2;
fn add_assign_round(
&mut self,
src: SumIncomplete<'a, I>,
round: Round2,
) -> Ordering2 {
let capacity = match src.values.size_hint() {
(lower, None) => lower + 1,
(_, Some(upper)) => upper + 1,
};
let mut reals = Vec::<*const mpfr::mpfr_t>::with_capacity(capacity);
let mut imags = Vec::<*const mpfr::mpfr_t>::with_capacity(capacity);
reals.push(self.real().as_raw());
imags.push(self.imag().as_raw());
for value in src.values {
reals.push(value.real().as_raw());
imags.push(value.imag().as_raw());
}
let tab_real = cast_ptr!(reals.as_ptr(), *mut mpfr::mpfr_t);
let tab_imag = cast_ptr!(imags.as_ptr(), *mut mpfr::mpfr_t);
let n = cast(reals.len());
let (ord_real, ord_imag) = unsafe {
let (real, imag) = self.as_mut_real_imag();
(
mpfr::sum(real.as_raw_mut(), tab_real, n, raw_round(round.0)),
mpfr::sum(imag.as_raw_mut(), tab_imag, n, raw_round(round.1)),
)
};
(ordering1(ord_real), ordering1(ord_imag))
}
}
#[derive(Debug)]
pub struct DotIncomplete<'a, I>
where
I: Iterator<Item = (&'a Complex, &'a Complex)>,
{
values: I,
}
fn prods_real(pairs: &[(&Complex, &Complex)]) -> Vec<Float> {
let mut prods = Vec::with_capacity(pairs.len() * 2);
for &(a, b) in pairs {
let (ar, ai) = (a.real(), a.imag());
let (br, bi) = (b.real(), b.imag());
let (arp, aip) = (ar.prec(), ai.prec());
let (brp, bip) = (br.prec(), bi.prec());
let bp = cmp::max(brp, bip);
let mut r = Float::new(arp.checked_add(bp).expect("overflow"));
unsafe {
mpfr::set_prec(r.as_raw_mut(), cast(arp + brp));
}
r.assign(ar * br);
prods.push(r);
r = Float::new(aip.checked_add(bp).expect("overflow"));
unsafe {
mpfr::set_prec(r.as_raw_mut(), cast(aip + bip));
}
r.assign(ai * bi);
r.neg_assign();
prods.push(r);
}
prods
}
fn prods_imag(prods: &mut Vec<Float>, pairs: &[(&Complex, &Complex)]) {
let mut i = 0;
for &(a, b) in pairs {
let (ar, ai) = (a.real(), a.imag());
let (br, bi) = (b.real(), b.imag());
let (arp, aip) = (ar.prec(), ai.prec());
let (brp, bip) = (br.prec(), bi.prec());
unsafe {
mpfr::set_prec(prods[i].as_raw_mut(), cast(arp + bip));
}
prods[i].assign(ar * bi);
i += 1;
unsafe {
mpfr::set_prec(prods[i].as_raw_mut(), cast(aip + brp));
}
prods[i].assign(ai * br);
i += 1;
}
}
impl<'a, I> AssignRound<DotIncomplete<'a, I>> for Complex
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
type Round = Round2;
type Ordering = Ordering2;
fn assign_round(
&mut self,
src: DotIncomplete<'a, I>,
round: Round2,
) -> Ordering2 {
let pairs = src.values.collect::<Vec<_>>();
let mut prods = prods_real(&pairs);
let ret_real =
self.mut_real().assign_round(Float::sum(prods.iter()), round.0);
prods_imag(&mut prods, &pairs);
let ret_imag =
self.mut_imag().assign_round(Float::sum(prods.iter()), round.1);
(ret_real, ret_imag)
}
}
impl<'a, I> Add<DotIncomplete<'a, I>> for Complex
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
type Output = Self;
#[inline]
fn add(mut self, rhs: DotIncomplete<'a, I>) -> Self {
self.add_assign_round(rhs, Default::default());
self
}
}
impl<'a, I> AddAssign<DotIncomplete<'a, I>> for Complex
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
#[inline]
fn add_assign(&mut self, rhs: DotIncomplete<'a, I>) {
self.add_assign_round(rhs, Default::default());
}
}
impl<'a, I> AddAssignRound<DotIncomplete<'a, I>> for Complex
where
I: Iterator<Item = (&'a Self, &'a Self)>,
{
type Round = Round2;
type Ordering = Ordering2;
fn add_assign_round(
&mut self,
src: DotIncomplete<'a, I>,
round: Round2,
) -> Ordering2 {
let pairs = src.values.collect::<Vec<_>>();
let mut prods = prods_real(&pairs);
let ret_real =
self.mut_real().add_assign_round(Float::sum(prods.iter()), round.0);
prods_imag(&mut prods, &pairs);
let ret_imag =
self.mut_imag().add_assign_round(Float::sum(prods.iter()), round.1);
(ret_real, ret_imag)
}
}
ref_math_op1_complex! { xmpc::proj; struct ProjIncomplete {} }
ref_math_op1_complex! { xmpc::sqr; struct SquareIncomplete {} }
ref_math_op1_complex! { xmpc::sqrt; struct SqrtIncomplete {} }
ref_math_op1_complex! { xmpc::conj; struct ConjIncomplete {} }
#[derive(Debug)]
pub struct AbsIncomplete<'a> {
ref_self: &'a Complex,
}
impl AssignRound<AbsIncomplete<'_>> for Float {
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(
&mut self,
src: AbsIncomplete<'_>,
round: Round,
) -> Ordering {
let ret = unsafe {
mpc::abs(self.as_raw_mut(), src.ref_self.as_raw(), raw_round(round))
};
ret.cmp(&0)
}
}
#[derive(Debug)]
pub struct ArgIncomplete<'a> {
ref_self: &'a Complex,
}
impl AssignRound<ArgIncomplete<'_>> for Float {
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(
&mut self,
src: ArgIncomplete<'_>,
round: Round,
) -> Ordering {
let ret = unsafe {
mpc::arg(self.as_raw_mut(), src.ref_self.as_raw(), raw_round(round))
};
ret.cmp(&0)
}
}
ref_math_op1_complex! { xmpc::mul_i; struct MulIIncomplete { negative: bool } }
ref_math_op1_complex! { xmpc::recip; struct RecipIncomplete {} }
#[derive(Debug)]
pub struct NormIncomplete<'a> {
ref_self: &'a Complex,
}
impl AssignRound<NormIncomplete<'_>> for Float {
type Round = Round;
type Ordering = Ordering;
#[inline]
fn assign_round(
&mut self,
src: NormIncomplete<'_>,
round: Round,
) -> Ordering {
let ret = unsafe {
mpc::norm(
self.as_raw_mut(),
src.ref_self.as_raw(),
raw_round(round),
)
};
ret.cmp(&0)
}
}
ref_math_op1_complex! { xmpc::log; struct LnIncomplete {} }
ref_math_op1_complex! { xmpc::log10; struct Log10Incomplete {} }
ref_math_op0_complex! {
xmpc::rootofunity; struct RootOfUnityIncomplete { n: u32, k: u32 }
}
ref_math_op1_complex! { xmpc::exp; struct ExpIncomplete {} }
ref_math_op1_complex! { xmpc::sin; struct SinIncomplete {} }
ref_math_op1_complex! { xmpc::cos; struct CosIncomplete {} }
ref_math_op1_2_complex! { xmpc::sin_cos; struct SinCosIncomplete {} }
ref_math_op1_complex! { xmpc::tan; struct TanIncomplete {} }
ref_math_op1_complex! { xmpc::sinh; struct SinhIncomplete {} }
ref_math_op1_complex! { xmpc::cosh; struct CoshIncomplete {} }
ref_math_op1_complex! { xmpc::tanh; struct TanhIncomplete {} }
ref_math_op1_complex! { xmpc::asin; struct AsinIncomplete {} }
ref_math_op1_complex! { xmpc::acos; struct AcosIncomplete {} }
ref_math_op1_complex! { xmpc::atan; struct AtanIncomplete {} }
ref_math_op1_complex! { xmpc::asinh; struct AsinhIncomplete {} }
ref_math_op1_complex! { xmpc::acosh; struct AcoshIncomplete {} }
ref_math_op1_complex! { xmpc::atanh; struct AtanhIncomplete {} }
#[cfg(feature = "rand")]
pub struct RandomBitsIncomplete<'a, 'b>
where
'b: 'a,
{
rng: &'a mut RandState<'b>,
}
#[cfg(feature = "rand")]
impl Assign<RandomBitsIncomplete<'_, '_>> for Complex {
#[inline]
fn assign(&mut self, src: RandomBitsIncomplete<'_, '_>) {
self.mut_real().assign(Float::random_bits(src.rng));
self.mut_imag().assign(Float::random_bits(src.rng));
}
}
#[cfg(feature = "rand")]
pub struct RandomCont<'a, 'b>
where
'b: 'a,
{
rng: &'a mut RandState<'b>,
}
#[cfg(feature = "rand")]
impl AssignRound<RandomCont<'_, '_>> for Complex {
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(
&mut self,
src: RandomCont<'_, '_>,
round: Round2,
) -> Ordering2 {
let real_dir =
self.mut_real().assign_round(Float::random_cont(src.rng), round.0);
let imag_dir =
self.mut_imag().assign_round(Float::random_cont(src.rng), round.1);
(real_dir, imag_dir)
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct BorrowComplex<'a> {
inner: mpc_t,
phantom: PhantomData<&'a Complex>,
}
impl Deref for BorrowComplex<'_> {
type Target = Complex;
#[inline]
fn deref(&self) -> &Complex {
let ptr = cast_ptr!(&self.inner, Complex);
unsafe { &*ptr }
}
}
#[derive(Clone, Copy)]
pub(crate) struct Format {
pub radix: i32,
pub precision: Option<usize>,
pub round: Round2,
pub to_upper: bool,
pub sign_plus: bool,
pub prefix: &'static str,
pub exp: ExpFormat,
}
impl Default for Format {
fn default() -> Format {
Format {
radix: 10,
precision: None,
round: Round2::default(),
to_upper: false,
sign_plus: false,
prefix: "",
exp: ExpFormat::ExpOrPoint,
}
}
}
pub(crate) fn append_to_string(s: &mut String, c: &Complex, f: Format) {
let (re, im) = (c.real(), c.imag());
let re_plus = f.sign_plus && re.is_sign_positive();
let im_plus = f.sign_plus && im.is_sign_positive();
let re_prefix = !f.prefix.is_empty() && re.is_finite();
let im_prefix = !f.prefix.is_empty() && im.is_finite();
s.push('(');
if re_plus {
s.push('+');
}
let prefix_start = s.len();
if re_prefix {
s.push_str(f.prefix);
}
let prefix_end = s.len();
let ff = FloatFormat {
radix: f.radix,
precision: f.precision,
round: f.round.0,
to_upper: f.to_upper,
exp: f.exp,
};
big_float::append_to_string(s, re, ff);
if re_prefix && s.as_bytes()[prefix_end] == b'-' {
unsafe {
let bytes =
slice::from_raw_parts_mut(s.as_ptr() as *mut u8, s.len());
bytes[prefix_start] = b'-';
bytes[prefix_start + 1..=prefix_end]
.copy_from_slice(f.prefix.as_bytes());
}
}
s.push(' ');
if im_plus {
s.push('+');
}
let prefix_start = s.len();
if im_prefix {
s.push_str(f.prefix);
}
let prefix_end = s.len();
let ff = FloatFormat { round: f.round.1, ..ff };
big_float::append_to_string(s, im, ff);
if im_prefix && s.as_bytes()[prefix_end] == b'-' {
unsafe {
let bytes =
slice::from_raw_parts_mut(s.as_ptr() as *mut u8, s.len());
bytes[prefix_start] = b'-';
bytes[prefix_start + 1..=prefix_end]
.copy_from_slice(f.prefix.as_bytes());
}
}
s.push(')');
}
#[derive(Debug)]
pub enum ParseIncomplete {
Real(FloatParseIncomplete),
Complex(FloatParseIncomplete, FloatParseIncomplete),
}
impl AssignRound<ParseIncomplete> for Complex {
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(
&mut self,
src: ParseIncomplete,
round: Round2,
) -> Ordering2 {
match src {
ParseIncomplete::Real(re) => {
let real_ord = self.mut_real().assign_round(re, round.0);
self.mut_imag().assign(Special::Zero);
(real_ord, Ordering::Equal)
}
ParseIncomplete::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)
}
}
}
}
macro_rules! parse_error {
($kind:expr) => {
Err(ParseComplexError { kind: $kind })
};
}
fn parse(
mut bytes: &[u8],
radix: i32,
) -> Result<ParseIncomplete, ParseComplexError> {
bytes = misc::trim_start(bytes);
bytes = misc::trim_end(bytes);
if bytes.is_empty() {
parse_error!(ParseErrorKind::NoDigits)?;
}
if let Some((inside, remainder)) = misc::matched_brackets(bytes) {
if !misc::trim_start(remainder).is_empty() {
parse_error!(ParseErrorKind::CloseNotLast)?;
}
bytes = misc::trim_start(inside);
bytes = misc::trim_end(bytes);
} else {
return match Float::parse_radix(&bytes, radix) {
Ok(re) => Ok(ParseIncomplete::Real(re)),
Err(e) => parse_error!(ParseErrorKind::InvalidFloat(e)),
};
};
let (real, imag) =
if let Some(comma) = misc::find_outside_brackets(bytes, b',') {
let real = misc::trim_end(&bytes[..comma]);
if real.is_empty() {
parse_error!(ParseErrorKind::NoRealDigits)?;
}
let imag = misc::trim_start(&bytes[comma + 1..]);
if imag.is_empty() {
parse_error!(ParseErrorKind::NoImagDigits)?;
}
if misc::find_outside_brackets(imag, b',').is_some() {
parse_error!(ParseErrorKind::MultipleSeparators)?;
}
(real, imag)
} else if let Some(space) = misc::find_space_outside_brackets(bytes) {
let real = &bytes[..space];
assert!(!real.is_empty());
let imag = misc::trim_start(&bytes[space + 1..]);
assert!(!imag.is_empty());
if misc::find_space_outside_brackets(imag).is_some() {
parse_error!(ParseErrorKind::MultipleSeparators)?;
}
(real, imag)
} else {
parse_error!(ParseErrorKind::MissingSeparator)?
};
let re = match Float::parse_radix(real, radix) {
Ok(re) => re,
Err(e) => parse_error!(ParseErrorKind::InvalidRealFloat(e))?,
};
let im = match Float::parse_radix(imag, radix) {
Ok(im) => im,
Err(e) => parse_error!(ParseErrorKind::InvalidImagFloat(e))?,
};
Ok(ParseIncomplete::Complex(re, im))
}
#[derive(Debug)]
pub struct ParseComplexError {
kind: ParseErrorKind,
}
#[derive(Debug)]
enum ParseErrorKind {
NoDigits,
NoRealDigits,
NoImagDigits,
InvalidFloat(ParseFloatError),
InvalidRealFloat(ParseFloatError),
InvalidImagFloat(ParseFloatError),
MissingSeparator,
MultipleSeparators,
CloseNotLast,
}
impl Error for ParseComplexError {
fn description(&self) -> &str {
use self::ParseErrorKind::*;
match self.kind {
NoDigits => "string has no digits",
NoRealDigits => "string has no real digits",
NoImagDigits => "string has no imaginary digits",
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"
}
MissingSeparator => "string has no separator inside brackets",
MultipleSeparators => {
"string has more than one separator inside brackets"
}
CloseNotLast => "string has more characters after closing bracket",
}
}
}
#[inline]
fn ordering1(ord: c_int) -> Ordering {
ord.cmp(&0)
}