[go: up one dir, main page]

rug/rational/
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::ext::xmpq;
18use crate::integer::{MiniInteger, ToMini};
19use crate::misc;
20use crate::rational::BorrowRational;
21use crate::{Assign, Rational};
22use az::Cast;
23use core::ffi::c_int;
24use core::fmt::{
25    Binary, Debug, Display, Formatter, LowerHex, Octal, Result as FmtResult, 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, mpq_t, mpz_t};
34
35const LIMBS_IN_SMALL: usize = (128 / gmp::LIMB_BITS) as usize;
36type Limbs = [MaybeUninit<limb_t>; LIMBS_IN_SMALL];
37
38/**
39A small rational number that does not require any memory allocation.
40
41This can be useful when you have a numerator and denominator that are primitive
42integer-types such as [`i64`] or [`u8`], and you need a reference to a
43[`Rational`].
44
45Although no allocation is required, setting the value of a `MiniRational` does
46require some computation, as the numerator and denominator need to be
47canonicalized.
48
49The [`borrow`][Self::borrow] method returns an object that can be coerced to a
50[`Rational`], as it implements
51<code>[Deref]\<[Target][Deref::Target] = [Rational]></code>.
52
53# Examples
54
55```rust
56use rug::rational::MiniRational;
57use rug::Rational;
58// `a` requires a heap allocation
59let mut a = Rational::from((100, 13));
60// `b` can reside on the stack
61let b = MiniRational::from((-100, 21));
62a /= &*b.borrow();
63assert_eq!(*a.numer(), -21);
64assert_eq!(*a.denom(), 13);
65```
66*/
67#[derive(Clone, Copy)]
68pub struct MiniRational {
69    inner: mpq_t,
70    // numerator is first in limbs if inner.num.d <= inner.den.d
71    first_limbs: Limbs,
72    last_limbs: Limbs,
73}
74
75static_assert!(mem::size_of::<Limbs>() == 16);
76
77// SAFETY: mpq_t is thread safe as guaranteed by the GMP library.
78unsafe impl Send for MiniRational {}
79unsafe impl Sync for MiniRational {}
80
81impl Default for MiniRational {
82    #[inline]
83    fn default() -> Self {
84        MiniRational::new()
85    }
86}
87
88impl Display for MiniRational {
89    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
90        Display::fmt(&*self.borrow(), f)
91    }
92}
93
94impl Debug for MiniRational {
95    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
96        Debug::fmt(&*self.borrow(), f)
97    }
98}
99
100impl Binary for MiniRational {
101    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
102        Binary::fmt(&*self.borrow(), f)
103    }
104}
105
106impl Octal for MiniRational {
107    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
108        Octal::fmt(&*self.borrow(), f)
109    }
110}
111
112impl LowerHex for MiniRational {
113    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
114        LowerHex::fmt(&*self.borrow(), f)
115    }
116}
117
118impl UpperHex for MiniRational {
119    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
120        UpperHex::fmt(&*self.borrow(), f)
121    }
122}
123
124impl MiniRational {
125    /// Creates a [`MiniRational`] with value 0.
126    ///
127    /// # Examples
128    ///
129    /// ```rust
130    /// use rug::rational::MiniRational;
131    /// let r = MiniRational::new();
132    /// let b = r.borrow();
133    /// // Use b as if it were Rational.
134    /// assert_eq!(*b.numer(), 0);
135    /// assert_eq!(*b.denom(), 1);
136    /// ```
137    #[inline]
138    pub const fn new() -> Self {
139        let d = NonNull::dangling();
140        MiniRational {
141            inner: mpq_t {
142                num: mpz_t {
143                    alloc: LIMBS_IN_SMALL as c_int,
144                    size: 0,
145                    d,
146                },
147                den: mpz_t {
148                    alloc: LIMBS_IN_SMALL as c_int,
149                    size: 1,
150                    d,
151                },
152            },
153            first_limbs: small_limbs![],
154            last_limbs: small_limbs![1],
155        }
156    }
157
158    /// Creates a [`MiniRational`] from a [`MiniInteger`].
159    ///
160    /// This is equivalent to `MiniRational::from(val)`, but can also be used in
161    /// constant context. Unless required in constant context, use the [`From`]
162    /// trait instead.
163    ///
164    /// # Planned deprecation
165    ///
166    /// This method will be deprecated when the [`From`] trait is usable in
167    /// constant context.
168    ///
169    /// # Examples
170    ///
171    /// ```rust
172    /// use rug::integer::MiniInteger;
173    /// use rug::rational::{BorrowRational, MiniRational};
174    /// use rug::Rational;
175    ///
176    /// const TWO_INT: MiniInteger = MiniInteger::const_from_i8(2i8);
177    /// const TWO_MINI: MiniRational = MiniRational::const_from_integer(TWO_INT);
178    /// const TWO_BORROW: BorrowRational = TWO_MINI.borrow();
179    /// const TWO: &Rational = BorrowRational::const_deref(&TWO_BORROW);
180    /// assert_eq!(*TWO, 2);
181    ///
182    /// const HALF_BORROW: BorrowRational = TWO.as_recip();
183    /// const HALF: &Rational = BorrowRational::const_deref(&HALF_BORROW);
184    /// assert_eq!(*HALF, MiniRational::from((1, 2)));
185    /// ```
186    #[inline]
187    pub const fn const_from_integer(val: MiniInteger) -> Self {
188        let MiniInteger {
189            inner: mut num_inner,
190            limbs: num_limbs,
191        } = val;
192        let MiniInteger {
193            inner: mut den_inner,
194            limbs: den_limbs,
195        } = MiniInteger::const_from_u8(1);
196        let d = NonNull::dangling();
197        // remove d pointer relation
198        num_inner.d = d;
199        den_inner.d = d;
200        MiniRational {
201            inner: mpq_t {
202                num: num_inner,
203                den: den_inner,
204            },
205            first_limbs: num_limbs,
206            last_limbs: den_limbs,
207        }
208    }
209
210    /// Returns a mutable reference to a [`Rational`] number for simple
211    /// operations that do not need to allocate more space for the numerator or
212    /// denominator.
213    ///
214    /// # Safety
215    ///
216    /// It is undefined behavior to perform operations that reallocate the
217    /// internal data of the referenced [`Rational`] number or to swap it with
218    /// another number, although it is allowed to swap the numerator and
219    /// denominator allocations, such as in the reciprocal operation
220    /// [`recip_mut`].
221    ///
222    /// Some GMP functions swap the allocations of their target operands;
223    /// calling such functions with the mutable reference returned by this
224    /// method can lead to undefined behavior.
225    ///
226    /// # Examples
227    ///
228    /// ```rust
229    /// use rug::rational::MiniRational;
230    /// let mut r = MiniRational::from((-15i32, 47i32));
231    /// let (num_capacity, den_capacity) = {
232    ///     let b = r.borrow();
233    ///     (b.numer().capacity(), b.denom().capacity())
234    /// };
235    /// // reciprocating this will not require reallocations
236    /// unsafe {
237    ///     r.as_nonreallocating_rational().recip_mut();
238    /// }
239    /// let after = r.borrow();
240    /// assert_eq!(*after, MiniRational::from((-47, 15)));
241    /// assert_eq!(after.numer().capacity(), num_capacity);
242    /// assert_eq!(after.denom().capacity(), den_capacity);
243    /// ```
244    ///
245    /// [`recip_mut`]: `Rational::recip_mut`
246    #[inline]
247    pub unsafe fn as_nonreallocating_rational(&mut self) -> &mut Rational {
248        // Update num.d and den.d to point to limbs.
249        let first = NonNull::<[MaybeUninit<limb_t>]>::from(&self.first_limbs[..]).cast();
250        let last = NonNull::<[MaybeUninit<limb_t>]>::from(&self.last_limbs[..]).cast();
251        let (num_d, den_d) = if self.num_is_first() {
252            (first, last)
253        } else {
254            (last, first)
255        };
256        self.inner.num.d = num_d;
257        self.inner.den.d = den_d;
258        let ptr = misc::cast_ptr_mut(&mut self.inner);
259        // SAFETY: since inner.num.d and inner.den.d point to the limbs, it is
260        // in a consistent state.
261        unsafe { &mut *ptr }
262    }
263
264    /// Borrows the rational number.
265    ///
266    /// The returned object implements
267    /// <code>[Deref]\<[Target][Deref::Target] = [Rational]></code>.
268    ///
269    /// The borrow lasts until the returned object exits scope. Multiple borrows
270    /// can be taken at the same time.
271    ///
272    /// # Examples
273    ///
274    /// ```rust
275    /// use rug::rational::MiniRational;
276    /// use rug::Rational;
277    /// let r = MiniRational::from((-13i32, 5i32));
278    /// let b = r.borrow();
279    /// let abs_ref = Rational::from(b.abs_ref());
280    /// assert_eq!(*abs_ref.numer(), 13);
281    /// assert_eq!(*abs_ref.denom(), 5);
282    /// ```
283    #[inline]
284    pub const fn borrow(&self) -> BorrowRational<'_> {
285        let first_d: *const Limbs = &self.first_limbs;
286        let last_d: *const Limbs = &self.last_limbs;
287        let (num_d, den_d) = if self.num_is_first() {
288            (first_d, last_d)
289        } else {
290            (last_d, first_d)
291        };
292        // SAFETY: Since num_d and den_d point to the limbs, the mpq_t is in a
293        // consistent state. Also, the lifetime of the BorrowRational is the
294        // lifetime of self, which covers the limbs.
295        unsafe {
296            BorrowRational::from_raw(mpq_t {
297                num: mpz_t {
298                    alloc: self.inner.num.alloc,
299                    size: self.inner.num.size,
300                    d: NonNull::new_unchecked(num_d.cast_mut().cast()),
301                },
302                den: mpz_t {
303                    alloc: self.inner.den.alloc,
304                    size: self.inner.den.size,
305                    d: NonNull::new_unchecked(den_d.cast_mut().cast()),
306                },
307            })
308        }
309    }
310
311    /// Borrows the rational number exclusively.
312    ///
313    /// This is similar to the [`borrow`][Self::borrow] method, but it requires
314    /// exclusive access to the underlying [`MiniRational`]; the returned
315    /// reference can however be shared. The exclusive access is required to
316    /// reduce the amount of housekeeping necessary, providing a more efficient
317    /// operation.
318    ///
319    /// # Examples
320    ///
321    /// ```rust
322    /// use rug::rational::MiniRational;
323    /// use rug::Rational;
324    /// let mut r = MiniRational::from((-13i32, 5i32));
325    /// let b = r.borrow_excl();
326    /// let abs_ref = Rational::from(b.abs_ref());
327    /// assert_eq!(*abs_ref.numer(), 13);
328    /// assert_eq!(*abs_ref.denom(), 5);
329    /// ```
330    #[inline]
331    pub fn borrow_excl(&mut self) -> &Rational {
332        // SAFETY: since the return is a const reference, there will be no reallocation
333        unsafe { &*self.as_nonreallocating_rational() }
334    }
335
336    /// Creates a [`MiniRational`] from a numerator and denominator, assuming
337    /// they are in canonical form.
338    ///
339    /// # Safety
340    ///
341    /// This method leads to undefined behavior if `den` is zero or if `num` and
342    /// `den` have common factors.
343    ///
344    /// # Examples
345    ///
346    /// ```rust
347    /// use rug::rational::MiniRational;
348    /// let from_unsafe = unsafe { MiniRational::from_canonical(-13, 10) };
349    /// // from_safe is canonicalized to the same form as from_unsafe
350    /// let from_safe = MiniRational::from((130, -100));
351    /// let unsafe_borrow = from_unsafe.borrow();
352    /// let safe_borrow = from_safe.borrow();
353    /// assert_eq!(unsafe_borrow.numer(), safe_borrow.numer());
354    /// assert_eq!(unsafe_borrow.denom(), safe_borrow.denom());
355    /// ```
356    pub unsafe fn from_canonical<Num: ToMini, Den: ToMini>(num: Num, den: Den) -> Self {
357        let mut num_size = 0;
358        let mut den_size = 0;
359        let mut num_limbs: Limbs = small_limbs![];
360        let mut den_limbs: Limbs = small_limbs![];
361        num.copy(&mut num_size, &mut num_limbs);
362        den.copy(&mut den_size, &mut den_limbs);
363        // since inner.num.d == inner.den.d, first_limbs are num_limbs
364        let d = NonNull::dangling();
365        MiniRational {
366            inner: mpq_t {
367                num: mpz_t {
368                    alloc: LIMBS_IN_SMALL.cast(),
369                    size: num_size,
370                    d,
371                },
372                den: mpz_t {
373                    alloc: LIMBS_IN_SMALL.cast(),
374                    size: den_size,
375                    d,
376                },
377            },
378            first_limbs: num_limbs,
379            last_limbs: den_limbs,
380        }
381    }
382
383    /// Assigns a numerator and denominator to a [`MiniRational`], assuming
384    /// they are in canonical form.
385    ///
386    /// # Safety
387    ///
388    /// This method leads to undefined behavior if `den` is zero or negative, or
389    /// if `num` and `den` have common factors.
390    ///
391    /// # Examples
392    ///
393    /// ```rust
394    /// use rug::rational::MiniRational;
395    /// use rug::Assign;
396    /// let mut a = MiniRational::new();
397    /// unsafe {
398    ///     a.assign_canonical(-13, 10);
399    /// }
400    /// // b is canonicalized to the same form as a
401    /// let mut b = MiniRational::new();
402    /// b.assign((130, -100));
403    /// let a_borrow = a.borrow();
404    /// let b_borrow = b.borrow();
405    /// assert_eq!(a_borrow.numer(), b_borrow.numer());
406    /// assert_eq!(a_borrow.denom(), b_borrow.denom());
407    /// ```
408    pub unsafe fn assign_canonical<Num: ToMini, Den: ToMini>(&mut self, num: Num, den: Den) {
409        // make num is first
410        self.inner.den.d = self.inner.num.d;
411        num.copy(&mut self.inner.num.size, &mut self.first_limbs);
412        den.copy(&mut self.inner.den.size, &mut self.last_limbs);
413    }
414
415    #[inline]
416    const fn num_is_first(&self) -> bool {
417        // SAFETY: num.d and den.d were created either from the same dangling
418        // pointer, or from fields in the same struct
419        let num_ptr = self.inner.num.d.as_ptr();
420        let den_ptr = self.inner.den.d.as_ptr();
421        unsafe { num_ptr.offset_from(den_ptr) <= 0 }
422    }
423}
424
425impl Assign<MiniInteger> for MiniRational {
426    #[inline]
427    fn assign(&mut self, src: MiniInteger) {
428        // make num is first
429        self.inner.den.d = self.inner.num.d;
430        self.inner.num.size = src.inner.size;
431        self.first_limbs = src.limbs;
432        self.inner.den.size = 1;
433        self.last_limbs[0] = MaybeUninit::new(1);
434    }
435}
436
437impl From<MiniInteger> for MiniRational {
438    #[inline]
439    fn from(src: MiniInteger) -> Self {
440        MiniRational::const_from_integer(src)
441    }
442}
443
444impl<Num: ToMini> Assign<Num> for MiniRational {
445    #[inline]
446    fn assign(&mut self, src: Num) {
447        // make num is first
448        self.inner.den.d = self.inner.num.d;
449        src.copy(&mut self.inner.num.size, &mut self.first_limbs);
450        self.inner.den.size = 1;
451        self.last_limbs[0] = MaybeUninit::new(1);
452    }
453}
454
455impl<Num: ToMini> From<Num> for MiniRational {
456    fn from(src: Num) -> Self {
457        let mut num_size = 0;
458        let mut num_limbs = small_limbs![];
459        src.copy(&mut num_size, &mut num_limbs);
460        // since inner.num.d == inner.den.d, first_limbs are num_limbs
461        let d = NonNull::dangling();
462        MiniRational {
463            inner: mpq_t {
464                num: mpz_t {
465                    alloc: LIMBS_IN_SMALL.cast(),
466                    size: num_size,
467                    d,
468                },
469                den: mpz_t {
470                    alloc: LIMBS_IN_SMALL.cast(),
471                    size: 1,
472                    d,
473                },
474            },
475            first_limbs: num_limbs,
476            last_limbs: small_limbs![1],
477        }
478    }
479}
480
481impl<Num: ToMini, Den: ToMini> Assign<(Num, Den)> for MiniRational {
482    fn assign(&mut self, src: (Num, Den)) {
483        assert!(!src.1.is_zero(), "division by zero");
484        // make num is first
485        self.inner.den.d = self.inner.num.d;
486        src.0.copy(&mut self.inner.num.size, &mut self.first_limbs);
487        src.1.copy(&mut self.inner.den.size, &mut self.last_limbs);
488        // SAFETY: canonicalization will never need to make a number larger.
489        xmpq::canonicalize(unsafe { self.as_nonreallocating_rational() });
490    }
491}
492
493impl<Num: ToMini, Den: ToMini> From<(Num, Den)> for MiniRational {
494    fn from(src: (Num, Den)) -> Self {
495        assert!(!src.1.is_zero(), "division by zero");
496        let d = NonNull::dangling();
497        let mut ret = MiniRational {
498            inner: mpq_t {
499                num: mpz_t {
500                    alloc: LIMBS_IN_SMALL.cast(),
501                    size: 0,
502                    d,
503                },
504                den: mpz_t {
505                    alloc: LIMBS_IN_SMALL.cast(),
506                    size: 0,
507                    d,
508                },
509            },
510            first_limbs: small_limbs![],
511            last_limbs: small_limbs![],
512        };
513        src.0.copy(&mut ret.inner.num.size, &mut ret.first_limbs);
514        src.1.copy(&mut ret.inner.den.size, &mut ret.last_limbs);
515        // SAFETY: canonicalization will never need to make a number larger.
516        xmpq::canonicalize(unsafe { ret.as_nonreallocating_rational() });
517        ret
518    }
519}
520
521impl Assign<&Self> for MiniRational {
522    #[inline]
523    fn assign(&mut self, other: &Self) {
524        self.clone_from(other);
525    }
526}
527
528impl Assign for MiniRational {
529    #[inline]
530    fn assign(&mut self, other: Self) {
531        *self = other;
532    }
533}
534
535#[cfg(test)]
536mod tests {
537    use crate::integer::MiniInteger;
538    use crate::rational::MiniRational;
539    use crate::{Assign, Rational};
540
541    #[test]
542    fn check_assign() {
543        let mut r = MiniRational::from((1, 2));
544        assert_eq!(*r.borrow_excl(), MiniRational::from((1, 2)));
545        r.assign(3);
546        assert_eq!(*r.borrow_excl(), 3);
547        let other = MiniRational::from((4, 5));
548        r.assign(&other);
549        assert_eq!(*r.borrow_excl(), MiniRational::from((4, 5)));
550        r.assign((6, 7));
551        assert_eq!(*r.borrow_excl(), MiniRational::from((6, 7)));
552        r.assign(other);
553        assert_eq!(*r.borrow_excl(), MiniRational::from((4, 5)));
554    }
555
556    fn swapped_parts(small: &MiniRational) -> bool {
557        unsafe {
558            let borrow = small.borrow();
559            let num = (*borrow.numer().as_raw()).d;
560            let den = (*borrow.denom().as_raw()).d;
561            num > den
562        }
563    }
564
565    #[test]
566    fn check_swapped_parts() {
567        let mut r = MiniRational::from((2, 3));
568        assert_eq!(*r.borrow_excl(), MiniRational::from((2, 3)));
569        assert_eq!(*r.clone().borrow_excl(), r);
570        let mut orig_swapped_parts = swapped_parts(&r);
571        unsafe {
572            r.as_nonreallocating_rational().recip_mut();
573        }
574        assert_eq!(*r.borrow_excl(), MiniRational::from((3, 2)));
575        assert_eq!(*r.clone().borrow_excl(), r);
576        assert!(swapped_parts(&r) != orig_swapped_parts);
577
578        unsafe {
579            r.assign_canonical(5, 7);
580        }
581        assert_eq!(*r.borrow_excl(), MiniRational::from((5, 7)));
582        assert_eq!(*r.clone().borrow_excl(), r);
583        orig_swapped_parts = swapped_parts(&r);
584        unsafe {
585            r.as_nonreallocating_rational().recip_mut();
586        }
587        assert_eq!(*r.borrow_excl(), MiniRational::from((7, 5)));
588        assert_eq!(*r.clone().borrow_excl(), r);
589        assert!(swapped_parts(&r) != orig_swapped_parts);
590
591        r.assign(2);
592        assert_eq!(*r.borrow_excl(), 2);
593        assert_eq!(*r.clone().borrow_excl(), r);
594        orig_swapped_parts = swapped_parts(&r);
595        unsafe {
596            r.as_nonreallocating_rational().recip_mut();
597        }
598        assert_eq!(*r.borrow_excl(), MiniRational::from((1, 2)));
599        assert_eq!(*r.clone().borrow_excl(), r);
600        assert!(swapped_parts(&r) != orig_swapped_parts);
601
602        r.assign((3, -5));
603        assert_eq!(*r.borrow_excl(), MiniRational::from((-3, 5)));
604        assert_eq!(*r.clone().borrow_excl(), r);
605        orig_swapped_parts = swapped_parts(&r);
606        unsafe {
607            r.as_nonreallocating_rational().recip_mut();
608        }
609        assert_eq!(*r.borrow_excl(), MiniRational::from((-5, 3)));
610        assert_eq!(*r.clone().borrow_excl(), r);
611        assert!(swapped_parts(&r) != orig_swapped_parts);
612    }
613
614    #[test]
615    fn check_traits() {
616        assert!(MiniRational::default().borrow_excl().is_zero());
617
618        let mini = MiniRational::from((14, -10));
619        let check = Rational::from((14, -10));
620        assert_eq!(format!("{mini}"), format!("{check}"));
621        assert_eq!(format!("{mini:?}"), format!("{check:?}"));
622        assert_eq!(format!("{mini:b}"), format!("{check:b}"));
623        assert_eq!(format!("{mini:o}"), format!("{check:o}"));
624        assert_eq!(format!("{mini:x}"), format!("{check:x}"));
625        assert_eq!(format!("{mini:X}"), format!("{check:X}"));
626    }
627
628    macro_rules! compare_conv {
629        ($T:ident, [$($val:expr),+] $( as $U:ident)?) => {
630            for &val in &[$($val),+] {
631                let integer = MiniInteger::from(val);
632                let a = MiniRational::from(integer);
633                let b = MiniRational::const_from_integer(integer);
634                let mut c = MiniInteger::new();
635                c.assign(integer);
636                assert_eq!(*a.borrow(), val $(as $U)?);
637                assert_eq!(*b.borrow(), val $(as $U)?);
638                assert_eq!(*c.borrow(), val $(as $U)?);
639            }
640        };
641    }
642
643    #[test]
644    fn check_equiv_convs() {
645        compare_conv!(bool, [false, true] as u8);
646        compare_conv!(i8, [i8::MIN, 0, i8::MAX]);
647        compare_conv!(i16, [i16::MIN, 0, i16::MAX]);
648        compare_conv!(i32, [i32::MIN, 0, i32::MAX]);
649        compare_conv!(i64, [i64::MIN, 0, i64::MAX]);
650        compare_conv!(i128, [i128::MIN, 0, i128::MAX]);
651        compare_conv!(isize, [isize::MIN, 0, isize::MAX]);
652        compare_conv!(u8, [0, u8::MAX]);
653        compare_conv!(u16, [0, u16::MAX]);
654        compare_conv!(u32, [0, u32::MAX]);
655        compare_conv!(u64, [0, u64::MAX]);
656        compare_conv!(u128, [0, u128::MAX]);
657        compare_conv!(usize, [0, usize::MAX]);
658    }
659}