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