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