#[cfg(feature = "rand")]
use crate::rand::MutRandState;
use crate::{
complex::{
arith::{AddMulIncomplete, SubMulFromIncomplete},
OrdComplex, Prec,
},
ext::{
xmpc::{self, ordering2, raw_round2, Ordering2, Round2, NEAREST2},
xmpfr::raw_round,
},
float::{
self,
big::{
self as big_float, ExpFormat, Format as FloatFormat,
ParseIncomplete as FloatParseIncomplete,
},
ParseFloatError, Round, Special,
},
misc::{self, AsOrPanic},
ops::{AddAssignRound, AssignRound, NegAssign},
Assign, Float,
};
use core::{
cmp::{self, Ordering},
fmt::{Display, Formatter, Result as FmtResult},
marker::PhantomData,
mem::{self, ManuallyDrop, MaybeUninit},
ops::{Add, AddAssign, Deref},
slice,
};
use gmp_mpfr_sys::{
mpc::{self, mpc_t},
mpfr::{self, mpfr_t},
};
use libc::c_int;
use std::error::Error;
#[repr(transparent)]
pub struct Complex {
inner: mpc_t,
}
static_assert_same_layout!(Complex, mpc_t);
static_assert_same_layout!(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, NEAREST2 => Ordering2;
$func;
$(#[$attr_ref])*
struct $Incomplete { $($param: $T),* }
}
};
}
macro_rules! ref_math_op1_complex {
(
$func:path;
$(#[$attr_ref:meta])*
struct $Incomplete:ident { $($param:ident: $T:ty),* }
) => {
ref_math_op1_round! {
Complex, Round2, NEAREST2 => Ordering2;
$func;
$(#[$attr_ref])*
struct $Incomplete { $($param: $T),* }
}
};
}
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, NEAREST2 => (Ordering2, Ordering2);
$func;
$(#[$attr_ref])*
struct $Incomplete { $($param: $T),* }
}
};
}
impl Complex {
#[inline]
pub(crate) fn new_nan<P: Prec>(prec: P) -> Self {
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 dst = MaybeUninit::uninit();
let inner_ptr = cast_ptr_mut!(dst.as_mut_ptr(), mpc_t);
mpc::init3(inner_ptr, p.0.as_or_panic(), p.1.as_or_panic());
dst.assume_init()
}
}
#[inline]
pub fn new<P: Prec>(prec: P) -> Self {
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: Prec>(&mut self, prec: P) {
self.set_prec_round(prec, NEAREST2);
}
#[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 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
}
#[inline]
pub fn parse<S: AsRef<[u8]>>(src: S) -> Result<ParseIncomplete, ParseComplexError> {
parse(src.as_ref(), 10)
}
#[inline]
pub fn parse_radix<S: AsRef<[u8]>>(
src: S,
radix: i32,
) -> Result<ParseIncomplete, ParseComplexError> {
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, NEAREST2)
}
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 raw = self.inner;
raw.re.sign = -raw.re.sign;
raw.im.sign = -raw.im.sign;
if self.real().is_nan() || self.imag().is_nan() {
unsafe {
mpfr::set_nanflag();
}
}
unsafe { BorrowComplex::from_raw(raw) }
}
pub fn as_conj(&self) -> BorrowComplex<'_> {
let mut raw = self.inner;
raw.im.sign = -raw.im.sign;
if self.imag().is_nan() {
unsafe {
mpfr::set_nanflag();
}
}
unsafe { BorrowComplex::from_raw(raw) }
}
pub fn as_mul_i(&self, negative: bool) -> BorrowComplex<'_> {
let mut raw = mpc_t {
re: self.inner.im,
im: self.inner.re,
};
if negative {
raw.im.sign = -raw.im.sign;
} else {
raw.re.sign = -raw.re.sign;
}
if self.real().is_nan() || self.imag().is_nan() {
unsafe {
mpfr::set_nanflag();
}
}
unsafe { BorrowComplex::from_raw(raw) }
}
#[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 }
}
#[inline]
pub fn mul_add(mut self, mul: &Self, add: &Self) -> Self {
self.mul_add_round(mul, add, NEAREST2);
self
}
#[inline]
pub fn mul_add_mut(&mut self, mul: &Self, add: &Self) {
self.mul_add_round(mul, add, NEAREST2);
}
#[inline]
pub fn mul_add_round(&mut self, mul: &Self, add: &Self, round: Round2) -> Ordering2 {
xmpc::fma(self, None, Some(mul), Some(add), round)
}
#[inline]
pub fn mul_add_ref<'a>(&'a self, mul: &'a Self, add: &'a Self) -> AddMulIncomplete<'a> {
self * mul + add
}
#[inline]
pub fn mul_sub(mut self, mul: &Self, sub: &Self) -> Self {
self.mul_sub_round(mul, sub, NEAREST2);
self
}
#[inline]
pub fn mul_sub_mut(&mut self, mul: &Self, sub: &Self) {
self.mul_sub_round(mul, sub, NEAREST2);
}
#[inline]
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)
}
#[inline]
pub fn mul_sub_ref<'a>(&'a self, mul: &'a Self, sub: &'a Self) -> SubMulFromIncomplete<'a> {
self * mul - sub
}
#[inline]
pub fn proj(mut self) -> Self {
self.proj_mut();
self
}
#[inline]
pub fn proj_mut(&mut self) {
xmpc::proj(self, None, NEAREST2);
}
#[inline]
pub fn proj_ref(&self) -> ProjIncomplete<'_> {
ProjIncomplete { ref_self: self }
}
#[inline]
pub fn square(mut self) -> Self {
self.square_round(NEAREST2);
self
}
#[inline]
pub fn square_mut(&mut self) {
self.square_round(NEAREST2);
}
#[inline]
pub fn square_round(&mut self, round: Round2) -> Ordering2 {
xmpc::sqr(self, None, round)
}
#[inline]
pub fn square_ref(&self) -> SquareIncomplete<'_> {
SquareIncomplete { ref_self: self }
}
#[inline]
pub fn sqrt(mut self) -> Self {
self.sqrt_round(NEAREST2);
self
}
#[inline]
pub fn sqrt_mut(&mut self) {
self.sqrt_round(NEAREST2);
}
#[inline]
pub fn sqrt_round(&mut self, round: Round2) -> Ordering2 {
xmpc::sqrt(self, None, round)
}
#[inline]
pub fn sqrt_ref(&self) -> SqrtIncomplete<'_> {
SqrtIncomplete { ref_self: self }
}
#[inline]
pub fn conj(mut self) -> Self {
self.conj_mut();
self
}
#[inline]
pub fn conj_mut(&mut self) {
xmpc::conj(self, None, NEAREST2);
}
#[inline]
pub fn conj_ref(&self) -> ConjIncomplete<'_> {
ConjIncomplete { ref_self: self }
}
#[inline]
pub fn abs(mut self) -> Complex {
self.abs_mut();
self
}
#[inline]
pub fn abs_mut(&mut self) {
self.abs_round(NEAREST2);
}
#[inline]
pub fn abs_round(&mut self, round: Round2) -> Ordering2 {
let (real, imag) = self.as_mut_real_imag();
let dir_re = real.hypot_round(imag, round.0);
let dir_im = imag.assign_round(Special::Zero, round.1);
(dir_re, dir_im)
}
#[inline]
pub fn abs_ref(&self) -> AbsIncomplete<'_> {
AbsIncomplete { ref_self: self }
}
#[inline]
pub fn arg(mut self) -> Complex {
self.arg_round(NEAREST2);
self
}
#[inline]
pub fn arg_mut(&mut self) {
self.arg_round(NEAREST2);
}
#[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 }
}
#[inline]
pub fn mul_i(mut self, negative: bool) -> Self {
self.mul_i_round(negative, NEAREST2);
self
}
#[inline]
pub fn mul_i_mut(&mut self, negative: bool) {
self.mul_i_round(negative, NEAREST2);
}
#[inline]
pub fn mul_i_round(&mut self, negative: bool, round: Round2) -> Ordering2 {
xmpc::mul_i(self, None, negative, round)
}
#[inline]
pub fn mul_i_ref(&self, negative: bool) -> MulIIncomplete<'_> {
MulIIncomplete {
ref_self: self,
negative,
}
}
#[inline]
pub fn recip(mut self) -> Self {
self.recip_round(NEAREST2);
self
}
#[inline]
pub fn recip_mut(&mut self) {
self.recip_round(NEAREST2);
}
#[inline]
pub fn recip_round(&mut self, round: Round2) -> Ordering2 {
xmpc::recip(self, None, round)
}
#[inline]
pub fn recip_ref(&self) -> RecipIncomplete<'_> {
RecipIncomplete { ref_self: self }
}
#[inline]
pub fn norm(mut self) -> Complex {
self.norm_round(NEAREST2);
self
}
#[inline]
pub fn norm_mut(&mut self) {
self.norm_round(NEAREST2);
}
#[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 }
}
#[inline]
pub fn ln(mut self) -> Self {
self.ln_round(NEAREST2);
self
}
#[inline]
pub fn ln_mut(&mut self) {
self.ln_round(NEAREST2);
}
#[inline]
pub fn ln_round(&mut self, round: Round2) -> Ordering2 {
xmpc::log(self, None, round)
}
#[inline]
pub fn ln_ref(&self) -> LnIncomplete<'_> {
LnIncomplete { ref_self: self }
}
#[inline]
pub fn log10(mut self) -> Self {
self.log10_round(NEAREST2);
self
}
#[inline]
pub fn log10_mut(&mut self) {
self.log10_round(NEAREST2);
}
#[inline]
pub fn log10_round(&mut self, round: Round2) -> Ordering2 {
xmpc::log10(self, None, round)
}
#[inline]
pub fn log10_ref(&self) -> Log10Incomplete<'_> {
Log10Incomplete { ref_self: self }
}
#[inline]
pub fn root_of_unity(n: u32, k: u32) -> RootOfUnityIncomplete {
RootOfUnityIncomplete { n, k }
}
#[inline]
pub fn exp(mut self) -> Self {
self.exp_round(NEAREST2);
self
}
#[inline]
pub fn exp_mut(&mut self) {
self.exp_round(NEAREST2);
}
#[inline]
pub fn exp_round(&mut self, round: Round2) -> Ordering2 {
xmpc::exp(self, None, round)
}
#[inline]
pub fn exp_ref(&self) -> ExpIncomplete<'_> {
ExpIncomplete { ref_self: self }
}
#[inline]
pub fn sin(mut self) -> Self {
self.sin_round(NEAREST2);
self
}
#[inline]
pub fn sin_mut(&mut self) {
self.sin_round(NEAREST2);
}
#[inline]
pub fn sin_round(&mut self, round: Round2) -> Ordering2 {
xmpc::sin(self, None, round)
}
#[inline]
pub fn sin_ref(&self) -> SinIncomplete<'_> {
SinIncomplete { ref_self: self }
}
#[inline]
pub fn cos(mut self) -> Self {
self.cos_round(NEAREST2);
self
}
#[inline]
pub fn cos_mut(&mut self) {
self.cos_round(NEAREST2);
}
#[inline]
pub fn cos_round(&mut self, round: Round2) -> Ordering2 {
xmpc::cos(self, None, round)
}
#[inline]
pub fn cos_ref(&self) -> CosIncomplete<'_> {
CosIncomplete { ref_self: self }
}
#[inline]
pub fn sin_cos(mut self, mut cos: Self) -> (Self, Self) {
self.sin_cos_round(&mut cos, NEAREST2);
(self, cos)
}
#[inline]
pub fn sin_cos_mut(&mut self, cos: &mut Self) {
self.sin_cos_round(cos, NEAREST2);
}
#[inline]
pub fn sin_cos_round(&mut self, cos: &mut Self, round: Round2) -> (Ordering2, Ordering2) {
xmpc::sin_cos(self, cos, None, round)
}
#[inline]
pub fn sin_cos_ref(&self) -> SinCosIncomplete<'_> {
SinCosIncomplete { ref_self: self }
}
#[inline]
pub fn tan(mut self) -> Self {
self.tan_round(NEAREST2);
self
}
#[inline]
pub fn tan_mut(&mut self) {
self.tan_round(NEAREST2);
}
#[inline]
pub fn tan_round(&mut self, round: Round2) -> Ordering2 {
xmpc::tan(self, None, round)
}
#[inline]
pub fn tan_ref(&self) -> TanIncomplete<'_> {
TanIncomplete { ref_self: self }
}
#[inline]
pub fn sinh(mut self) -> Self {
self.sinh_round(NEAREST2);
self
}
#[inline]
pub fn sinh_mut(&mut self) {
self.sinh_round(NEAREST2);
}
#[inline]
pub fn sinh_round(&mut self, round: Round2) -> Ordering2 {
xmpc::sinh(self, None, round)
}
#[inline]
pub fn sinh_ref(&self) -> SinhIncomplete<'_> {
SinhIncomplete { ref_self: self }
}
#[inline]
pub fn cosh(mut self) -> Self {
self.cosh_round(NEAREST2);
self
}
#[inline]
pub fn cosh_mut(&mut self) {
self.cosh_round(NEAREST2);
}
#[inline]
pub fn cosh_round(&mut self, round: Round2) -> Ordering2 {
xmpc::cosh(self, None, round)
}
#[inline]
pub fn cosh_ref(&self) -> CoshIncomplete<'_> {
CoshIncomplete { ref_self: self }
}
#[inline]
pub fn tanh(mut self) -> Self {
self.tanh_round(NEAREST2);
self
}
#[inline]
pub fn tanh_mut(&mut self) {
self.tanh_round(NEAREST2);
}
#[inline]
pub fn tanh_round(&mut self, round: Round2) -> Ordering2 {
xmpc::tanh(self, None, round)
}
#[inline]
pub fn tanh_ref(&self) -> TanhIncomplete<'_> {
TanhIncomplete { ref_self: self }
}
#[inline]
pub fn asin(mut self) -> Self {
self.asin_round(NEAREST2);
self
}
#[inline]
pub fn asin_mut(&mut self) {
self.asin_round(NEAREST2);
}
#[inline]
pub fn asin_round(&mut self, round: Round2) -> Ordering2 {
xmpc::asin(self, None, round)
}
#[inline]
pub fn asin_ref(&self) -> AsinIncomplete<'_> {
AsinIncomplete { ref_self: self }
}
#[inline]
pub fn acos(mut self) -> Self {
self.acos_round(NEAREST2);
self
}
#[inline]
pub fn acos_mut(&mut self) {
self.acos_round(NEAREST2);
}
#[inline]
pub fn acos_round(&mut self, round: Round2) -> Ordering2 {
xmpc::acos(self, None, round)
}
#[inline]
pub fn acos_ref(&self) -> AcosIncomplete<'_> {
AcosIncomplete { ref_self: self }
}
#[inline]
pub fn atan(mut self) -> Self {
self.atan_round(NEAREST2);
self
}
#[inline]
pub fn atan_mut(&mut self) {
self.atan_round(NEAREST2);
}
#[inline]
pub fn atan_round(&mut self, round: Round2) -> Ordering2 {
xmpc::atan(self, None, round)
}
#[inline]
pub fn atan_ref(&self) -> AtanIncomplete<'_> {
AtanIncomplete { ref_self: self }
}
#[inline]
pub fn asinh(mut self) -> Self {
self.asinh_round(NEAREST2);
self
}
#[inline]
pub fn asinh_mut(&mut self) {
self.asinh_round(NEAREST2);
}
#[inline]
pub fn asinh_round(&mut self, round: Round2) -> Ordering2 {
xmpc::asinh(self, None, round)
}
#[inline]
pub fn asinh_ref(&self) -> AsinhIncomplete<'_> {
AsinhIncomplete { ref_self: self }
}
#[inline]
pub fn acosh(mut self) -> Self {
self.acosh_round(NEAREST2);
self
}
#[inline]
pub fn acosh_mut(&mut self) {
self.acosh_round(NEAREST2);
}
#[inline]
pub fn acosh_round(&mut self, round: Round2) -> Ordering2 {
xmpc::acosh(self, None, round)
}
#[inline]
pub fn acosh_ref(&self) -> AcoshIncomplete<'_> {
AcoshIncomplete { ref_self: self }
}
#[inline]
pub fn atanh(mut self) -> Self {
self.atanh_round(NEAREST2);
self
}
#[inline]
pub fn atanh_mut(&mut self) {
self.atanh_round(NEAREST2);
}
#[inline]
pub fn atanh_round(&mut self, round: Round2) -> Ordering2 {
xmpc::atanh(self, None, round)
}
#[inline]
pub fn atanh_ref(&self) -> AtanhIncomplete<'_> {
AtanhIncomplete { ref_self: self }
}
#[cfg(feature = "rand")]
#[inline]
pub fn random_bits(rng: &mut dyn MutRandState) -> RandomBitsIncomplete {
RandomBitsIncomplete { rng }
}
#[cfg(feature = "rand")]
#[inline]
pub fn random_cont(rng: &mut dyn MutRandState) -> RandomContIncomplete {
RandomContIncomplete { 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_t>::with_capacity(capacity);
let mut imags = Vec::<*const 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_t);
let tab_imag = cast_ptr!(imags.as_ptr(), *mut mpfr_t);
let n = reals.len().as_or_panic();
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, NEAREST2);
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, NEAREST2);
}
}
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_t>::with_capacity(capacity);
let mut imags = Vec::<*const 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_t);
let tab_imag = cast_ptr!(imags.as_ptr(), *mut mpfr_t);
let n = reals.len().as_or_panic();
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(), (arp + brp).as_or_panic());
}
r.assign(ar * br);
prods.push(r);
r = Float::new(aip.checked_add(bp).expect("overflow"));
unsafe {
mpfr::set_prec(r.as_raw_mut(), (aip + bip).as_or_panic());
}
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(), (arp + bip).as_or_panic());
}
prods[i].assign(ar * bi);
i += 1;
unsafe {
mpfr::set_prec(prods[i].as_raw_mut(), (aip + brp).as_or_panic());
}
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, NEAREST2);
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, NEAREST2);
}
}
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> {
rng: &'a mut dyn MutRandState,
}
#[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 RandomContIncomplete<'a> {
rng: &'a mut dyn MutRandState,
}
#[cfg(feature = "rand")]
impl AssignRound<RandomContIncomplete<'_>> for Complex {
type Round = Round2;
type Ordering = Ordering2;
#[inline]
fn assign_round(&mut self, src: RandomContIncomplete, 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: ManuallyDrop<Complex>,
phantom: PhantomData<&'a Complex>,
}
impl BorrowComplex<'_> {
unsafe fn from_raw<'a>(raw: mpc_t) -> BorrowComplex<'a> {
BorrowComplex {
inner: ManuallyDrop::new(Complex::from_raw(raw)),
phantom: PhantomData,
}
}
}
impl Deref for BorrowComplex<'_> {
type Target = Complex;
#[inline]
fn deref(&self) -> &Complex {
&*self.inner
}
}
#[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 {
#[inline]
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();
let extra = 3
+ if re_plus { 1 } else { 0 }
+ if im_plus { 1 } else { 0 }
+ if re_prefix { f.prefix.len() } else { 0 }
+ if im_prefix { f.prefix.len() } else { 0 };
let ff = FloatFormat {
radix: f.radix,
precision: f.precision,
round: f.round.0,
to_upper: f.to_upper,
exp: f.exp,
};
let cap = big_float::req_chars(re, ff, extra);
let cap = big_float::req_chars(im, ff, cap);
s.reserve(cap);
let reserved_ptr = s.as_ptr();
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();
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(')');
debug_assert_eq!(reserved_ptr, s.as_ptr());
#[cfg(not(debug_assertions))]
{
let _ = reserved_ptr;
}
}
#[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() {
return parse_error!(ParseErrorKind::NoDigits);
}
if let Some((inside, remainder)) = misc::matched_brackets(bytes) {
if !misc::trim_start(remainder).is_empty() {
return 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() {
return parse_error!(ParseErrorKind::NoRealDigits);
}
let imag = misc::trim_start(&bytes[comma + 1..]);
if imag.is_empty() {
return parse_error!(ParseErrorKind::NoImagDigits);
}
if misc::find_outside_brackets(imag, b',').is_some() {
return 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() {
return parse_error!(ParseErrorKind::MultipleSeparators);
}
(real, imag)
} else {
return parse_error!(ParseErrorKind::MissingSeparator);
};
let re = match Float::parse_radix(real, radix) {
Ok(re) => re,
Err(e) => return parse_error!(ParseErrorKind::InvalidRealFloat(e)),
};
let im = match Float::parse_radix(imag, radix) {
Ok(im) => im,
Err(e) => return 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",
}
}
}
impl Display for ParseComplexError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
use self::ParseErrorKind::*;
match &self.kind {
NoDigits => Display::fmt("string has no digits", f),
NoRealDigits => Display::fmt("string has no real digits", f),
NoImagDigits => Display::fmt("string has no imaginary digits", f),
InvalidFloat(e) => {
Display::fmt("string is not a valid float: ", f)?;
Display::fmt(e, f)
}
InvalidRealFloat(e) => {
Display::fmt("real part of string is not a valid float: ", f)?;
Display::fmt(e, f)
}
InvalidImagFloat(e) => {
Display::fmt("imaginary part of string is not a valid float: ", f)?;
Display::fmt(e, f)
}
MissingSeparator => Display::fmt("string has no separator inside brackets", f),
MultipleSeparators => {
Display::fmt("string has more than one separator inside brackets", f)
}
CloseNotLast => Display::fmt("string has more characters after closing bracket", f),
}
}
}
#[inline]
fn ordering1(ord: c_int) -> Ordering {
ord.cmp(&0)
}