[go: up one dir, main page]

rug/complex/
mini.rs

1// Copyright © 2016–2025 Trevor Spiteri
2
3// This program is free software: you can redistribute it and/or modify it under
4// the terms of the GNU Lesser General Public License as published by the Free
5// Software Foundation, either version 3 of the License, or (at your option) any
6// later version.
7//
8// This program is distributed in the hope that it will be useful, but WITHOUT
9// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11// details.
12//
13// You should have received a copy of the GNU Lesser General Public License and
14// a copy of the GNU General Public License along with this program. If not, see
15// <https://www.gnu.org/licenses/>.
16
17use 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/**
43A small complex number that does not require any memory allocation.
44
45This can be useful when you have real and imaginary numbers that are primitive
46integers or floats and you need a reference to a [`Complex`].
47
48The `MiniComplex` will have a precision according to the types of the
49primitives used to set its real and imaginary parts. Note that if different
50types are used to set the parts, the parts can have different precisions.
51
52  * [`bool`]: the part will have the [minimum possible
53    precision][crate::float::prec_min].
54  * [`i8`], [`u8`]: the part will have eight bits of precision.
55  * [`i16`], [`u16`]: the part will have 16 bits of precision.
56  * [`i32`], [`u32`]: the part will have 32 bits of precision.
57  * [`i64`], [`u64`]: the part will have 64 bits of precision.
58  * [`i128`], [`u128`]: the part will have 128 bits of precision.
59  * [`isize`], [`usize`]: the part will have 32 or 64 bits of precision,
60    depending on the platform.
61  * [`f32`]: the part will have 24 bits of precision.
62  * [`f64`]: the part will have 53 bits of precision.
63  * [`Special`][crate::float::Special]: the part will have the [minimum possible
64    precision][crate::float::prec_min].
65
66The [`borrow`][Self::borrow] method returns an object that can be coerced to a
67[`Complex`], as it implements
68<code>[Deref]\<[Target][Deref::Target] = [Complex]></code>.
69
70# Examples
71
72```rust
73use rug::complex::MiniComplex;
74use rug::Complex;
75// `a` requires a heap allocation
76let mut a = Complex::with_val(53, (1, 2));
77// `b` can reside on the stack
78let b = MiniComplex::from((-10f64, -20.5f64));
79a += &*b.borrow();
80assert_eq!(*a.real(), -9);
81assert_eq!(*a.imag(), -18.5);
82```
83*/
84#[derive(Clone, Copy)]
85pub struct MiniComplex {
86    inner: mpc_t,
87    // real part is first in limbs if inner.re.d <= inner.im.d
88    first_limbs: Limbs,
89    last_limbs: Limbs,
90}
91
92static_assert!(mem::size_of::<Limbs>() == 16);
93
94// SAFETY: mpc_t is thread safe as guaranteed by the MPC library.
95unsafe 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    /// Creates a [`MiniComplex`] with value 0 and the [minimum possible
155    /// precision][crate::float::prec_min].
156    ///
157    /// # Examples
158    ///
159    /// ```rust
160    /// use rug::complex::MiniComplex;
161    /// let c = MiniComplex::new();
162    /// // Borrow c as if it were Complex.
163    /// assert_eq!(*c.borrow(), 0);
164    /// ```
165    #[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    /// Creates a [`MiniComplex`] from a [`MiniFloat`] real part.
189    ///
190    /// This is equivalent to `MiniComplex::from(real)`, but can also be used in
191    /// constant context. Unless required in constant context, use the [`From`]
192    /// trait instead.
193    ///
194    /// The precision of the imaginary part is set to the precision of the real
195    /// part.
196    ///
197    /// # Planned deprecation
198    ///
199    /// This method will be deprecated when the [`From`] trait is usable in
200    /// constant context.
201    ///
202    /// # Examples
203    ///
204    /// ```rust
205    /// use rug::complex::{BorrowComplex, MiniComplex};
206    /// use rug::float::MiniFloat;
207    /// use rug::Complex;
208    ///
209    /// const TWO_FLOAT: MiniFloat = MiniFloat::const_from_i8(2i8);
210    /// const TWO_MINI: MiniComplex = MiniComplex::const_from_real(TWO_FLOAT);
211    /// const TWO_BORROW: BorrowComplex = TWO_MINI.borrow();
212    /// const TWO: &Complex = BorrowComplex::const_deref(&TWO_BORROW);
213    /// assert_eq!(*TWO, 2);
214    /// assert_eq!(TWO.prec(), (i8::BITS, i8::BITS));
215    /// ```
216    #[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    /// Creates a [`MiniComplex`] from two [`MiniFloat`] parts.
235    ///
236    /// This is equivalent to `MiniComplex::from((real, imag))`, but can also be
237    /// used in constant context. Unless required in constant context, use the
238    /// [`From`] trait instead.
239    ///
240    /// # Planned deprecation
241    ///
242    /// This method will be deprecated when the [`From`] trait is usable in
243    /// constant context.
244    ///
245    /// # Examples
246    ///
247    /// ```rust
248    /// use rug::complex::{BorrowComplex, MiniComplex};
249    /// use rug::float::MiniFloat;
250    /// use rug::Complex;
251    ///
252    /// const TWO_FLOAT: MiniFloat = MiniFloat::const_from_i8(2i8);
253    /// const THOUSAND_FLOAT: MiniFloat = MiniFloat::const_from_i16(1000i16);
254    /// const TWO_1000I_MINI: MiniComplex =
255    ///     MiniComplex::const_from_parts(TWO_FLOAT, THOUSAND_FLOAT);
256    /// const TWO_1000I_BORROW: BorrowComplex = TWO_1000I_MINI.borrow();
257    /// const TWO_1000I: &Complex = BorrowComplex::const_deref(&TWO_1000I_BORROW);
258    /// assert_eq!(*TWO_1000I, (2, 1000));
259    /// assert_eq!(TWO_1000I.prec(), (i8::BITS, i16::BITS));
260    /// ```
261    #[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        // remove d pointer relation
273        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    /// Returns a mutable reference to a [`Complex`] number for simple
286    /// operations that do not need to change the precision of the real or
287    /// imaginary part.
288    ///
289    /// # Safety
290    ///
291    /// It is undefined behavior to modify the precision of the referenced
292    /// [`Complex`] number or to swap it with another number.
293    ///
294    /// # Examples
295    ///
296    /// ```rust
297    /// use rug::complex::MiniComplex;
298    /// let mut c = MiniComplex::from((1.0f32, 3.0f32));
299    /// // rotation does not change the precision
300    /// unsafe {
301    ///     c.as_nonreallocating_complex().mul_i_mut(false);
302    /// }
303    /// assert_eq!(*c.borrow(), (-3.0, 1.0));
304    /// ```
305    #[inline]
306    pub unsafe fn as_nonreallocating_complex(&mut self) -> &mut Complex {
307        // Update re.d and im.d to point to limbs.
308        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        // SAFETY: since inner.re.d and inner.im.d point to the limbs, it is
319        // in a consistent state.
320        unsafe { &mut *ptr }
321    }
322
323    /// Borrows the complex number.
324    ///
325    /// The returned object implements
326    /// <code>[Deref]\<[Target][Deref::Target] = [Complex]></code>.
327    ///
328    /// The borrow lasts until the returned object exits scope. Multiple borrows
329    /// can be taken at the same time.
330    ///
331    /// # Examples
332    ///
333    /// ```rust
334    /// use rug::complex::MiniComplex;
335    /// use rug::Complex;
336    /// let c = MiniComplex::from((-13f64, 5.5f64));
337    /// let b = c.borrow();
338    /// let conj = Complex::with_val(53, b.conj_ref());
339    /// assert_eq!(*conj.real(), -13);
340    /// assert_eq!(*conj.imag(), -5.5);
341    /// ```
342    #[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        // SAFETY: Since re_d and im_d point to the limbs, the mpc_t is in a
352        // consistent state. Also, the lifetime of the BorrowComplex is the
353        // lifetime of self, which covers the limbs.
354        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    /// Borrows the complex number exclusively.
373    ///
374    /// This is similar to the [`borrow`][Self::borrow] method, but it requires
375    /// exclusive access to the underlying [`MiniComplex`]; the returned
376    /// reference can however be shared. The exclusive access is required to
377    /// reduce the amount of housekeeping necessary, providing a more efficient
378    /// operation.
379    ///
380    /// # Examples
381    ///
382    /// ```rust
383    /// use rug::complex::MiniComplex;
384    /// use rug::Complex;
385    /// let mut c = MiniComplex::from((-13f64, 5.5f64));
386    /// let b = c.borrow_excl();
387    /// let conj = Complex::with_val(53, b.conj_ref());
388    /// assert_eq!(*conj.real(), -13);
389    /// assert_eq!(*conj.imag(), -5.5);
390    /// ```
391    #[inline]
392    pub fn borrow_excl(&mut self) -> &Complex {
393        // SAFETY: since the return is a const reference, there will be no reallocation
394        unsafe { &*self.as_nonreallocating_complex() }
395    }
396
397    #[inline]
398    const fn re_is_first(&self) -> bool {
399        // SAFETY: re.d and im.d were created either from the same dangling
400        // pointer, or from fields in the same struct
401        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        // make re is first
411        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        // make re is first
433        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        // make re is first
455        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        // make re is first
473        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        // make re is first
492        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}