1use crate::complex::BorrowComplex;
18use crate::ext::xmpfr;
19use crate::float;
20use crate::float::{MiniFloat, ToMini};
21use crate::misc;
22use crate::{Assign, Complex};
23use core::fmt::{
24 Binary, Debug, Display, Formatter, LowerExp, LowerHex, Octal, Result as FmtResult, UpperExp,
25 UpperHex,
26};
27use core::mem;
28use core::mem::MaybeUninit;
29#[allow(unused_imports)]
30use core::ops::Deref;
31use core::ptr::NonNull;
32use gmp_mpfr_sys::gmp;
33use gmp_mpfr_sys::gmp::limb_t;
34use gmp_mpfr_sys::mpc::mpc_t;
35use gmp_mpfr_sys::mpfr::{mpfr_t, prec_t};
36#[cfg(feature = "num-complex")]
37use num_complex::Complex as NumComplex;
38
39const LIMBS_IN_SMALL: usize = (128 / gmp::LIMB_BITS) as usize;
40type Limbs = [MaybeUninit<limb_t>; LIMBS_IN_SMALL];
41
42#[derive(Clone, Copy)]
85pub struct MiniComplex {
86 inner: mpc_t,
87 first_limbs: Limbs,
89 last_limbs: Limbs,
90}
91
92static_assert!(mem::size_of::<Limbs>() == 16);
93
94unsafe impl Send for MiniComplex {}
96unsafe impl Sync for MiniComplex {}
97
98impl Default for MiniComplex {
99 #[inline]
100 fn default() -> Self {
101 MiniComplex::new()
102 }
103}
104
105impl Display for MiniComplex {
106 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
107 Display::fmt(&*self.borrow(), f)
108 }
109}
110
111impl Debug for MiniComplex {
112 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
113 Debug::fmt(&*self.borrow(), f)
114 }
115}
116
117impl LowerExp for MiniComplex {
118 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
119 LowerExp::fmt(&*self.borrow(), f)
120 }
121}
122
123impl UpperExp for MiniComplex {
124 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
125 UpperExp::fmt(&*self.borrow(), f)
126 }
127}
128
129impl Binary for MiniComplex {
130 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
131 Binary::fmt(&*self.borrow(), f)
132 }
133}
134
135impl Octal for MiniComplex {
136 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
137 Octal::fmt(&*self.borrow(), f)
138 }
139}
140
141impl LowerHex for MiniComplex {
142 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
143 LowerHex::fmt(&*self.borrow(), f)
144 }
145}
146
147impl UpperHex for MiniComplex {
148 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
149 UpperHex::fmt(&*self.borrow(), f)
150 }
151}
152
153impl MiniComplex {
154 #[inline]
166 pub const fn new() -> Self {
167 let d = NonNull::dangling();
168 MiniComplex {
169 inner: mpc_t {
170 re: mpfr_t {
171 prec: float::prec_min() as prec_t,
172 sign: 1,
173 exp: xmpfr::EXP_ZERO,
174 d,
175 },
176 im: mpfr_t {
177 prec: float::prec_min() as prec_t,
178 sign: 1,
179 exp: xmpfr::EXP_ZERO,
180 d,
181 },
182 },
183 first_limbs: small_limbs![],
184 last_limbs: small_limbs![],
185 }
186 }
187
188 #[inline]
217 pub const fn const_from_real(real: MiniFloat) -> Self {
218 let MiniFloat { inner, limbs } = real;
219 MiniComplex {
220 inner: mpc_t {
221 re: inner,
222 im: mpfr_t {
223 prec: inner.prec,
224 sign: 1,
225 exp: xmpfr::EXP_ZERO,
226 d: inner.d,
227 },
228 },
229 first_limbs: limbs,
230 last_limbs: small_limbs![],
231 }
232 }
233
234 #[inline]
262 pub const fn const_from_parts(real: MiniFloat, imag: MiniFloat) -> Self {
263 let MiniFloat {
264 inner: mut re_inner,
265 limbs: re_limbs,
266 } = real;
267 let MiniFloat {
268 inner: mut im_inner,
269 limbs: im_limbs,
270 } = imag;
271 let d = NonNull::dangling();
272 re_inner.d = d;
274 im_inner.d = d;
275 MiniComplex {
276 inner: mpc_t {
277 re: re_inner,
278 im: im_inner,
279 },
280 first_limbs: re_limbs,
281 last_limbs: im_limbs,
282 }
283 }
284
285 #[inline]
306 pub unsafe fn as_nonreallocating_complex(&mut self) -> &mut Complex {
307 let first = NonNull::<[MaybeUninit<limb_t>]>::from(&self.first_limbs[..]).cast();
309 let last = NonNull::<[MaybeUninit<limb_t>]>::from(&self.last_limbs[..]).cast();
310 let (re_d, im_d) = if self.re_is_first() {
311 (first, last)
312 } else {
313 (last, first)
314 };
315 self.inner.re.d = re_d;
316 self.inner.im.d = im_d;
317 let ptr = misc::cast_ptr_mut(&mut self.inner);
318 unsafe { &mut *ptr }
321 }
322
323 #[inline]
343 pub const fn borrow(&self) -> BorrowComplex<'_> {
344 let first_d: *const Limbs = &self.first_limbs;
345 let last_d: *const Limbs = &self.last_limbs;
346 let (re_d, im_d) = if self.re_is_first() {
347 (first_d, last_d)
348 } else {
349 (last_d, first_d)
350 };
351 unsafe {
355 BorrowComplex::from_raw(mpc_t {
356 re: mpfr_t {
357 prec: self.inner.re.prec,
358 sign: self.inner.re.sign,
359 exp: self.inner.re.exp,
360 d: NonNull::new_unchecked(re_d.cast_mut().cast()),
361 },
362 im: mpfr_t {
363 prec: self.inner.im.prec,
364 sign: self.inner.im.sign,
365 exp: self.inner.im.exp,
366 d: NonNull::new_unchecked(im_d.cast_mut().cast()),
367 },
368 })
369 }
370 }
371
372 #[inline]
392 pub fn borrow_excl(&mut self) -> &Complex {
393 unsafe { &*self.as_nonreallocating_complex() }
395 }
396
397 #[inline]
398 const fn re_is_first(&self) -> bool {
399 let re_ptr = self.inner.re.d.as_ptr();
402 let im_ptr = self.inner.im.d.as_ptr();
403 unsafe { re_ptr.offset_from(im_ptr) <= 0 }
404 }
405}
406
407impl Assign<MiniFloat> for MiniComplex {
408 #[inline]
409 fn assign(&mut self, src: MiniFloat) {
410 self.inner.im.d = self.inner.re.d;
412 self.inner.re.prec = src.inner.prec;
413 self.inner.re.sign = src.inner.sign;
414 self.inner.re.exp = src.inner.exp;
415 self.inner.im.prec = src.inner.prec;
416 self.inner.im.sign = 1;
417 self.inner.im.exp = xmpfr::EXP_ZERO;
418 self.first_limbs = src.limbs;
419 }
420}
421
422impl From<MiniFloat> for MiniComplex {
423 #[inline]
424 fn from(src: MiniFloat) -> Self {
425 MiniComplex::const_from_real(src)
426 }
427}
428
429impl Assign<(MiniFloat, MiniFloat)> for MiniComplex {
430 #[inline]
431 fn assign(&mut self, src: (MiniFloat, MiniFloat)) {
432 self.inner.im.d = self.inner.re.d;
434 self.inner.re.prec = src.0.inner.prec;
435 self.inner.re.sign = src.0.inner.sign;
436 self.inner.re.exp = src.0.inner.exp;
437 self.inner.im.prec = src.1.inner.prec;
438 self.inner.im.sign = src.1.inner.sign;
439 self.inner.im.exp = src.1.inner.exp;
440 self.first_limbs = src.0.limbs;
441 self.last_limbs = src.1.limbs;
442 }
443}
444
445impl From<(MiniFloat, MiniFloat)> for MiniComplex {
446 #[inline]
447 fn from(src: (MiniFloat, MiniFloat)) -> Self {
448 MiniComplex::const_from_parts(src.0, src.1)
449 }
450}
451
452impl<Re: ToMini> Assign<Re> for MiniComplex {
453 fn assign(&mut self, src: Re) {
454 self.inner.im.d = self.inner.re.d;
456 src.copy(&mut self.inner.re, &mut self.first_limbs);
457 self.inner.im.prec = self.inner.re.prec;
458 self.inner.im.sign = 1;
459 self.inner.im.exp = xmpfr::EXP_ZERO;
460 }
461}
462
463impl<Re: ToMini> From<Re> for MiniComplex {
464 fn from(src: Re) -> Self {
465 let re = MiniFloat::from(src);
466 MiniComplex::const_from_real(re)
467 }
468}
469
470impl<Re: ToMini, Im: ToMini> Assign<(Re, Im)> for MiniComplex {
471 fn assign(&mut self, src: (Re, Im)) {
472 self.inner.im.d = self.inner.re.d;
474 src.0.copy(&mut self.inner.re, &mut self.first_limbs);
475 src.1.copy(&mut self.inner.im, &mut self.last_limbs);
476 }
477}
478
479impl<Re: ToMini, Im: ToMini> From<(Re, Im)> for MiniComplex {
480 #[inline]
481 fn from(src: (Re, Im)) -> Self {
482 let re = MiniFloat::from(src.0);
483 let im = MiniFloat::from(src.1);
484 MiniComplex::const_from_parts(re, im)
485 }
486}
487
488#[cfg(feature = "num-complex")]
489impl<T: ToMini> Assign<NumComplex<T>> for MiniComplex {
490 fn assign(&mut self, src: NumComplex<T>) {
491 self.inner.im.d = self.inner.re.d;
493 src.re.copy(&mut self.inner.re, &mut self.first_limbs);
494 src.im.copy(&mut self.inner.im, &mut self.last_limbs);
495 }
496}
497
498#[cfg(feature = "num-complex")]
499impl<T: ToMini> From<NumComplex<T>> for MiniComplex {
500 #[inline]
501 fn from(src: NumComplex<T>) -> Self {
502 let re = MiniFloat::from(src.re);
503 let im = MiniFloat::from(src.im);
504 MiniComplex::const_from_parts(re, im)
505 }
506}
507
508impl Assign<&Self> for MiniComplex {
509 #[inline]
510 fn assign(&mut self, other: &Self) {
511 self.clone_from(other);
512 }
513}
514
515impl Assign for MiniComplex {
516 #[inline]
517 fn assign(&mut self, other: Self) {
518 *self = other;
519 }
520}
521
522#[cfg(test)]
523mod tests {
524 use crate::complex::MiniComplex;
525 use crate::float;
526 use crate::float::{FreeCache, MiniFloat, Special};
527 use crate::{Assign, Complex};
528
529 #[test]
530 fn check_assign() {
531 let mut c = MiniComplex::from((1.0, 2.0));
532 assert_eq!(*c.borrow_excl(), (1.0, 2.0));
533 c.assign(3.0);
534 assert_eq!(*c.borrow_excl(), (3.0, 0.0));
535 let other = MiniComplex::from((4.0, 5.0));
536 c.assign(&other);
537 assert_eq!(*c.borrow_excl(), (4.0, 5.0));
538 c.assign((6.0, 7.0));
539 assert_eq!(*c.borrow_excl(), (6.0, 7.0));
540 c.assign(other);
541 assert_eq!(*c.borrow_excl(), (4.0, 5.0));
542
543 float::free_cache(FreeCache::All);
544 }
545
546 fn swapped_parts(small: &MiniComplex) -> bool {
547 unsafe {
548 let borrow = small.borrow();
549 let re = (*borrow.real().as_raw()).d;
550 let im = (*borrow.imag().as_raw()).d;
551 re > im
552 }
553 }
554
555 #[test]
556 fn check_swapped_parts() {
557 let mut c = MiniComplex::from((1, 2));
558 assert_eq!(*c.borrow_excl(), (1, 2));
559 assert_eq!(*c.clone().borrow_excl(), c);
560 let mut orig_swapped_parts = swapped_parts(&c);
561 unsafe {
562 assert_eq!(c.borrow_excl().real().prec(), c.borrow_excl().imag().prec());
563 c.as_nonreallocating_complex().mul_i_mut(false);
564 }
565 assert_eq!(*c.borrow_excl(), (-2, 1));
566 assert_eq!(*c.clone().borrow_excl(), c);
567 assert!(swapped_parts(&c) != orig_swapped_parts);
568
569 c.assign(12);
570 assert_eq!(*c.borrow_excl(), 12);
571 assert_eq!(*c.clone().borrow_excl(), c);
572 orig_swapped_parts = swapped_parts(&c);
573 unsafe {
574 assert_eq!(c.borrow_excl().real().prec(), c.borrow_excl().imag().prec());
575 c.as_nonreallocating_complex().mul_i_mut(false);
576 }
577 assert_eq!(*c.borrow_excl(), (0, 12));
578 assert_eq!(*c.clone().borrow_excl(), c);
579 assert!(swapped_parts(&c) != orig_swapped_parts);
580
581 c.assign((4, 5));
582 assert_eq!(*c.borrow_excl(), (4, 5));
583 assert_eq!(*c.clone().borrow_excl(), c);
584 orig_swapped_parts = swapped_parts(&c);
585 unsafe {
586 assert_eq!(c.borrow_excl().real().prec(), c.borrow_excl().imag().prec());
587 c.as_nonreallocating_complex().mul_i_mut(false);
588 }
589 assert_eq!(*c.borrow_excl(), (-5, 4));
590 assert_eq!(*c.clone().borrow_excl(), c);
591 assert!(swapped_parts(&c) != orig_swapped_parts);
592 }
593
594 #[test]
595 fn check_traits() {
596 assert!(MiniComplex::default().borrow_excl().is_zero());
597
598 let mini = MiniComplex::from((-5.2f64, 4u128));
599 let check = Complex::with_val((53, 128), (-5.2f64, 4u128));
600 assert_eq!(format!("{mini}"), format!("{check}"));
601 assert_eq!(format!("{mini:?}"), format!("{check:?}"));
602 assert_eq!(format!("{mini:e}"), format!("{check:e}"));
603 assert_eq!(format!("{mini:E}"), format!("{check:E}"));
604 assert_eq!(format!("{mini:b}"), format!("{check:b}"));
605 assert_eq!(format!("{mini:o}"), format!("{check:o}"));
606 assert_eq!(format!("{mini:x}"), format!("{check:x}"));
607 assert_eq!(format!("{mini:X}"), format!("{check:X}"));
608 }
609
610 macro_rules! compare_conv {
611 ($T:ident, $prec:expr, [$($val:expr),+] $( as $U:ident)?) => {
612 for &val in &[$($val),+] {
613 let float = MiniFloat::from(val);
614 let a = MiniComplex::from(float);
615 let b = MiniComplex::const_from_real(float);
616 let mut c = MiniComplex::new();
617 c.assign(float);
618 assert_eq!(*a.borrow(), val $(as $U)?);
619 assert_eq!(*b.borrow(), val $(as $U)?);
620 assert_eq!(*c.borrow(), val $(as $U)?);
621 assert_eq!(a.borrow().prec(), ($prec, $prec));
622 assert_eq!(b.borrow().prec(), ($prec, $prec));
623 assert_eq!(c.borrow().prec(), ($prec, $prec));
624
625 let class="bool-val">true);
626 let a = MiniComplex::from((float, one));
627 let b = MiniComplex::const_from_parts(float, one);
628 let mut c = MiniComplex::new();
629 c.assign((float, one));
630 assert_eq!(*a.borrow(), (val $(as $U)?, 1));
631 assert_eq!(*b.borrow(), (val $(as $U)?, 1));
632 assert_eq!(*c.borrow(), (val $(as $U)?, 1));
633 assert_eq!(a.borrow().prec(), ($prec, 1));
634 assert_eq!(b.borrow().prec(), ($prec, 1));
635 assert_eq!(c.borrow().prec(), ($prec, 1));
636
637 let a = MiniComplex::from((one, float));
638 let b = MiniComplex::const_from_parts(one, float);
639 let mut c = MiniComplex::new();
640 c.assign((one, float));
641 assert_eq!(*a.borrow(), (1, val $(as $U)?));
642 assert_eq!(*b.borrow(), (1, val $(as $U)?));
643 assert_eq!(*c.borrow(), (1, val $(as $U)?));
644 assert_eq!(a.borrow().prec(), (1, $prec));
645 assert_eq!(b.borrow().prec(), (1, $prec));
646 assert_eq!(c.borrow().prec(), (1, $prec));
647 }
648 };
649 }
650
651 #[test]
652 fn check_equiv_convs() {
653 compare_conv!(bool, 1, [false, true] as u8);
654 compare_conv!(i8, i8::BITS, [i8::MIN, 0, i8::MAX]);
655 compare_conv!(i16, i16::BITS, [i16::MIN, 0, i16::MAX]);
656 compare_conv!(i32, i32::BITS, [i32::MIN, 0, i32::MAX]);
657 compare_conv!(i64, i64::BITS, [i64::MIN, 0, i64::MAX]);
658 compare_conv!(i128, i128::BITS, [i128::MIN, 0, i128::MAX]);
659 compare_conv!(isize, isize::BITS, [isize::MIN, 0, isize::MAX]);
660 compare_conv!(u8, u8::BITS, [0, u8::MAX]);
661 compare_conv!(u16, u16::BITS, [0, u16::MAX]);
662 compare_conv!(u32, u32::BITS, [0, u32::MAX]);
663 compare_conv!(u64, u64::BITS, [0, u64::MAX]);
664 compare_conv!(u128, u128::BITS, [0, u128::MAX]);
665 compare_conv!(usize, usize::BITS, [0, usize::MAX]);
666 compare_conv!(
667 f32,
668 f32::MANTISSA_DIGITS,
669 [f32::MIN, 0.0, f32::MAX, f32::INFINITY]
670 );
671 compare_conv!(
672 f64,
673 f64::MANTISSA_DIGITS,
674 [f64::MIN, 0.0, f64::MAX, f64::INFINITY]
675 );
676 compare_conv!(Special, 1, [Special::NegZero, Special::Infinity]);
677 }
678}