Skip to main content

relp_num/rational/big/
io.rs

1use std::{fmt, mem};
2use std::cmp::{min, Ordering};
3use std::convert::TryFrom;
4use std::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
5use std::num::{NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
6use std::str::FromStr;
7
8use num_traits::{FromPrimitive, One, ToPrimitive, Zero};
9use smallvec::{smallvec, SmallVec};
10
11use crate::{NonZero, NonZeroSign, Ubig};
12use crate::integer::big::{BITS_PER_WORD, NonZeroUbig};
13use crate::integer::big::io::{highest_word, words_to_u128};
14use crate::integer::big::ops::div::div;
15use crate::integer::big::ops::non_zero::is_one_non_zero;
16use crate::integer::big::ops::normalize::{gcd_scalar, simplify_fraction_without_info};
17use crate::integer::big::properties::cmp;
18use crate::rational::big::{Big, NonZeroBig};
19use crate::rational::{Rational128, RationalUsize};
20use crate::rational::small::ops::building_blocks::{simplify128, simplify16, simplify32, simplify64, simplify8, simplify_usize};
21use crate::sign::Sign;
22use crate::sign::Signed;
23
24impl<const S: usize> Big<S> {
25    pub fn new(numerator: i64, denominator: u64) -> Option<Self> {
26        if 0 != denominator {
27            Some({
28                let mut numerator_abs = numerator.unsigned_abs() as usize;
29                let mut denominator = denominator as usize;
30                if numerator == 0 {
31                    Self::zero()
32                } else if numerator_abs == denominator {
33                    Self {
34                        sign: Signed::signum(&numerator),
35                        numerator: Ubig::one(),
36                        denominator: NonZeroUbig::one(),
37                    }
38                } else {
39                    if numerator_abs != 1 && denominator != 1 {
40                        let gcd = gcd_scalar(numerator_abs, denominator);
41
42                        numerator_abs /= gcd;
43                        denominator /= gcd;
44                    }
45
46                    Self {
47                        sign: Signed::signum(&numerator),
48                        numerator: Ubig::new(numerator_abs),
49                        denominator: unsafe { NonZeroUbig::new_unchecked(denominator) },
50                    }
51                }
52            })
53        } else {
54            None
55        }
56    }
57}
58
59impl<const S: usize> Default for Big<S> {
60    fn default() -> Self {
61        Self::zero()
62    }
63}
64
65impl<const S: usize> fmt::Debug for Big<S> {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        // The same representation as `Display`, such that it round trips through `FromStr`
68        fmt::Display::fmt(self, f)
69    }
70}
71
72macro_rules! forwards {
73    ($ty:ty) => {
74        impl<const S: usize> From<&$ty> for Big<S> {
75            fn from(other: &$ty) -> Self {
76                From::from(*other)
77            }
78        }
79    }
80}
81
82forwards!(u8);
83forwards!(u16);
84forwards!(u32);
85forwards!(u64);
86forwards!(NonZeroU8);
87forwards!(NonZeroU16);
88forwards!(NonZeroU32);
89forwards!(NonZeroU64);
90forwards!(i8);
91forwards!(i16);
92forwards!(i32);
93forwards!(i64);
94forwards!(NonZeroI8);
95forwards!(NonZeroI16);
96forwards!(NonZeroI32);
97forwards!(NonZeroI64);
98
99macro_rules! from_integer_unsigned {
100    ($ty:ty) => {
101        impl<const S: usize> From<$ty> for Big<S> {
102            fn from(value: $ty) -> Self {
103                Self {
104                    sign: Signed::signum(&value),
105                    numerator: Ubig::from(value as usize),
106                    denominator: NonZeroUbig::one(),
107                }
108            }
109        }
110    }
111}
112
113from_integer_unsigned!(u8);
114from_integer_unsigned!(u16);
115from_integer_unsigned!(u32);
116from_integer_unsigned!(u64);
117from_integer_unsigned!(usize);
118
119macro_rules! from_integer_unsigned_non_zero {
120    ($ty:ty) => {
121        impl<const S: usize> From<$ty> for Big<S> {
122            fn from(value: $ty) -> Self {
123                Self {
124                    sign: Signed::signum(&value),
125                    numerator: Ubig::from(value.get() as usize),
126                    denominator: NonZeroUbig::one(),
127                }
128            }
129        }
130    }
131}
132
133from_integer_unsigned_non_zero!(NonZeroU8);
134from_integer_unsigned_non_zero!(NonZeroU16);
135from_integer_unsigned_non_zero!(NonZeroU32);
136from_integer_unsigned_non_zero!(NonZeroU64);
137from_integer_unsigned_non_zero!(NonZeroUsize);
138
139macro_rules! from_integer_signed {
140    ($ty:ty) => {
141        impl<const S: usize> From<$ty> for Big<S> {
142            fn from(value: $ty) -> Self {
143                Self {
144                    sign: Signed::signum(&value),
145                    numerator: Ubig::new(value.unsigned_abs() as usize),
146                    denominator: NonZeroUbig::one(),
147                }
148            }
149        }
150    }
151}
152
153from_integer_signed!(i8);
154from_integer_signed!(i16);
155from_integer_signed!(i32);
156from_integer_signed!(i64);
157from_integer_signed!(isize);
158
159macro_rules! from_integer_signed_non_zero {
160    ($ty:ty) => {
161        impl<const S: usize> From<$ty> for Big<S> {
162            fn from(value: $ty) -> Self {
163                Self {
164                    sign: Signed::signum(&value),
165                    numerator: Ubig::from(value.get().unsigned_abs() as usize),
166                    denominator: NonZeroUbig::one(),
167                }
168            }
169        }
170    }
171}
172
173from_integer_signed_non_zero!(NonZeroI8);
174from_integer_signed_non_zero!(NonZeroI16);
175from_integer_signed_non_zero!(NonZeroI32);
176from_integer_signed_non_zero!(NonZeroI64);
177from_integer_signed_non_zero!(NonZeroIsize);
178
179macro_rules! impl_from_iu {
180    ($numerator:ty, $denominator:ty, $simplify:ident) => {
181        impl<const S: usize> From<($numerator, $denominator)> for Big<S> {
182            #[inline]
183            fn from((numerator, denominator): ($numerator, $denominator)) -> Self {
184                // This is for tests only at the moment, do a run time assert
185                assert!(denominator.is_not_zero());
186
187                if mem::size_of::<$numerator>() > mem::size_of::<usize>() {
188                    debug_assert!(numerator.abs() <= usize::MAX as $numerator);
189                }
190                if mem::size_of::<$denominator>() > mem::size_of::<usize>() {
191                    debug_assert!(denominator <= usize::MAX as $denominator);
192                }
193
194                if numerator == 0 {
195                    <Self as num_traits::Zero>::zero()
196                } else {
197                    let sign = <$numerator as Signed>::signum(&numerator);
198                    let (numerator, denominator) = $simplify(numerator.unsigned_abs(), denominator);
199
200                    Self {
201                        sign,
202                        numerator: Ubig::new(numerator as usize),
203                        denominator: NonZeroUbig::new(denominator as usize).unwrap(),
204                    }
205                }
206            }
207        }
208    }
209}
210
211impl_from_iu!(i8, u8, simplify8);
212impl_from_iu!(i16, u16, simplify16);
213impl_from_iu!(i32, u32, simplify32);
214impl_from_iu!(i64, u64, simplify64);
215impl_from_iu!(i128, u128, simplify128);
216
217macro_rules! impl_from_ii {
218    ($ty:ty, $simplify:ident) => {
219        impl<const S: usize> From<($ty, $ty)> for Big<S> {
220            #[inline]
221            fn from((numerator, denominator): ($ty, $ty)) -> Self {
222                // This is for tests only at the moment, do a run time assert
223                assert!(denominator.is_not_zero());
224
225                if mem::size_of::<$ty>() > mem::size_of::<usize>() {
226                    debug_assert!(numerator.unsigned_abs() as u128 <= usize::MAX as u128);
227                    debug_assert!(denominator.unsigned_abs() as u128 <= usize::MAX as u128);
228                }
229
230                if numerator == 0 {
231                    <Self as num_traits::Zero>::zero()
232                } else {
233                    let sign = <$ty as Signed>::signum(&numerator) * <$ty as Signed>::signum(&denominator);
234                    debug_assert_ne!(sign, Sign::Zero);
235
236                    let (numerator, denominator) = $simplify(
237                        numerator.unsigned_abs(), denominator.unsigned_abs(),
238                    );
239
240                    Self {
241                        sign,
242                        numerator: Ubig::new(numerator as usize),
243                        denominator: NonZeroUbig::new(denominator as usize).unwrap(),
244                    }
245                }
246            }
247        }
248    }
249}
250
251impl_from_ii!(i8, simplify8);
252impl_from_ii!(i16, simplify16);
253impl_from_ii!(i32, simplify32);
254impl_from_ii!(i64, simplify64);
255impl_from_ii!(i128, simplify128);
256impl_from_ii!(isize, simplify_usize);
257
258/// Conversion from a fixed size ratio that doesn't fit in a single word.
259///
260/// The equivalents for the smaller fixed size ratios are in the `with_small_rational` module; those
261/// can cast their numerator and denominator into a single word, these can't.
262macro_rules! from_small_rational {
263    ($small:ident, $new_numerator:path, $new_denominator_unchecked:path) => {
264        impl<const S: usize> From<$small> for Big<S> {
265            #[inline]
266            fn from(value: $small) -> Self {
267                match value.sign {
268                    Sign::Zero => {
269                        debug_assert_eq!(value.numerator, 0);
270
271                        <Self as num_traits::Zero>::zero()
272                    }
273                    Sign::Positive | Sign::Negative => Self {
274                        sign: value.sign,
275                        // The input is in lowest terms already, so no simplification is needed
276                        numerator: $new_numerator(value.numerator),
277                        denominator: unsafe {
278                            // SAFETY: Input denominator is nonzero
279                            $new_denominator_unchecked(value.denominator)
280                        },
281                    },
282                }
283            }
284        }
285
286        impl<const S: usize> From<&$small> for Big<S> {
287            #[inline]
288            fn from(value: &$small) -> Self {
289                From::from(*value)
290            }
291        }
292    }
293}
294
295from_small_rational!(Rational128, Ubig::new_u128, NonZeroUbig::new_u128_unchecked);
296from_small_rational!(RationalUsize, Ubig::new, NonZeroUbig::new_unchecked);
297
298const ONES_32: u32 = (1 << 8) - 1;
299const ONES_64: u64 = (1 << 11) - 1;
300
301impl<const S: usize> FromPrimitive for Big<S> {
302    fn from_i64(n: i64) -> Option<Self> {
303        Some(Self {
304            sign: Signed::signum(&n),
305            numerator: Ubig::new(n.unsigned_abs() as usize),
306            denominator: NonZeroUbig::one(),
307        })
308    }
309
310    fn from_u64(n: u64) -> Option<Self> {
311        Some(Self {
312            sign: if n != 0 { Sign::Positive } else { Sign::Zero },
313            numerator: Ubig::new(n as usize),
314            denominator: NonZeroUbig::one(),
315        })
316    }
317
318    fn from_f32(n: f32) -> Option<Self> {
319        Self::from_float_kind(f32_kind(n))
320    }
321
322    fn from_f64(n: f64) -> Option<Self> {
323        Self::from_float_kind(f64_kind(n))
324    }
325}
326
327/// See also the `std::num::FpCategory`.
328pub enum FloatKind {
329    Zero,
330    Subnormal(FloatAsRatio),
331    Infinity,
332    NaN,
333    Normal(FloatAsRatio),
334}
335
336pub struct FloatAsRatio {
337    pub sign: u64,
338    pub exponent: i32,
339    pub fraction: NonZeroU64,
340}
341
342pub fn f32_kind(n: f32) -> FloatKind {
343    let n = n.to_bits();
344    let sign = (n & 0b1000_0000_0000_0000_0000_0000_0000_0000) >> (32 - 1);
345    let exponent = (n & 0b0111_1111_1000_0000_0000_0000_0000_0000) >> (32 - 1 - 8);
346    let fraction = n & 0b0000_0000_0111_1111_1111_1111_1111_1111;
347
348    match (exponent, fraction) {
349        (0, 0) => FloatKind::Zero,
350        (0, _) => FloatKind::Subnormal(FloatAsRatio {
351            sign: sign as u64,
352            exponent: 1 - 127 - 23,
353            fraction: unsafe {
354                // SAFETY: Zero would have matched earlier branch
355                NonZeroU64::new_unchecked(fraction as u64)
356            },
357        }),
358        (ONES_32, 0) => FloatKind::Infinity,
359        (ONES_32, _) => FloatKind::NaN,
360        _ => FloatKind::Normal(FloatAsRatio {
361            sign: sign as u64,
362            exponent: exponent as i32 - 127 - 23,
363            fraction: unsafe {
364                // SAFETY: A constant is always added
365                NonZeroU64::new_unchecked((fraction + (1 << 23)) as u64)
366                // SAFETY: A constant is always added
367            },
368        }),
369    }
370}
371
372pub fn f64_kind(n: f64) -> FloatKind {
373    let n = n.to_bits();
374    let sign = (n & 0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000) >> (64 - 1);
375    let exponent = (n & 0b0111_1111_1111_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000) >> (64 - 1 - 11);
376    let fraction = n & 0b0000_0000_0000_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111;
377
378    assert_eq!(mem::size_of::<usize>(), mem::size_of::<u64>());
379
380    match (exponent, fraction) {
381        (0, 0) => FloatKind::Zero,
382        (0, _) => FloatKind::Subnormal(FloatAsRatio {
383            sign,
384            exponent: 1 - 1023 - 52,
385            fraction: unsafe {
386                // SAFETY: Zero would have matched earlier branch
387                NonZeroU64::new_unchecked(fraction)
388            },
389        }),
390        (ONES_64, 0) => FloatKind::Infinity,
391        (ONES_64, _) => FloatKind::NaN,
392        _ => FloatKind::Normal(FloatAsRatio {
393            sign,
394            exponent: exponent as i32 - 1023 - 52,
395            fraction: unsafe {
396                // SAFETY: A constant is always added
397                NonZeroU64::new_unchecked(fraction + (1 << 52))
398            },
399        }),
400    }
401}
402
403impl<const S: usize> Big<S> {
404    fn from_float_kind(kind: FloatKind) -> Option<Self> {
405        match kind {
406            FloatKind::Subnormal(as_ratio) | FloatKind::Normal(as_ratio) => {
407                let (numerator, denominator) = from_float_helper(as_ratio.exponent, as_ratio.fraction);
408
409                Some(Self {
410                    sign: if as_ratio.sign > 0 { Sign::Negative } else { Sign::Positive },
411                    numerator,
412                    denominator,
413                })
414            }
415            FloatKind::Zero => Some(Self::zero()),
416            _ => None,
417        }
418    }
419}
420
421pub fn from_float_helper<const S: usize>(power: i32, fraction: NonZeroU64) -> (Ubig<S>, NonZeroUbig<S>) {
422    match power.cmp(&0) {
423        Ordering::Less => {
424            let numerator_zeros = fraction.trailing_zeros();
425            let shift = power.unsigned_abs();
426
427            let numerator_shift = min(numerator_zeros, shift);
428            let denominator_shift = shift - numerator_shift;
429
430            let words_shift = denominator_shift / BITS_PER_WORD;
431            let bits_shift = denominator_shift % BITS_PER_WORD;
432            let size = words_shift + 1;
433            let mut denominator = SmallVec::with_capacity(size as usize);
434
435            denominator.extend(std::iter::repeat_n(0, words_shift as usize));
436            denominator.push(1 << bits_shift);
437
438            let numerator = unsafe {
439                // SAFETY: Fraction is non zero
440                Ubig::from_inner_unchecked(smallvec![fraction.get() as usize >> numerator_shift])
441            };
442
443            (numerator, unsafe { NonZeroUbig::from_inner_unchecked(denominator) })
444        }
445        Ordering::Equal => {
446            (unsafe {
447                // SAFETY: Fraction is non zero
448                Ubig::from_inner_unchecked(smallvec![fraction.get() as usize])
449            }, NonZeroUbig::one())
450        }
451        Ordering::Greater => {
452            let shift = power.unsigned_abs();
453            let words_shift = shift / BITS_PER_WORD;
454            let bits_shift = shift % BITS_PER_WORD;
455
456            let overflows = fraction.leading_zeros() < bits_shift;
457            let size = 1 + words_shift + if overflows { 1 } else { 0 };
458            let mut numerator = SmallVec::with_capacity(size as usize);
459
460            numerator.extend(std::iter::repeat_n(0, words_shift as usize));
461
462            numerator.push((fraction.get() as usize) << bits_shift);
463            if overflows {
464                numerator.push(fraction.get() as usize >> (BITS_PER_WORD - bits_shift));
465            }
466
467            (
468                unsafe {
469                    // SAFETY: last value is not zero
470                    Ubig::from_inner_unchecked(numerator)
471                },
472                NonZeroUbig::one(),
473            )
474        }
475    }
476}
477
478impl<const S: usize> Big<S> {
479    /// Build a ratio from raw limbs, without reducing it.
480    ///
481    /// Only for tests that need a value which is deliberately not in lowest terms, such as the
482    /// input to a reduction routine or a `Display` of the stored components. Every other way in is
483    /// expected to reduce, because a stored ratio has to be coprime for `PartialEq` and `Ord` to
484    /// agree and for the arithmetic kernels to hold their precondition.
485    #[cfg(test)]
486    pub(crate) fn from_raw_limbs<const I1: usize, const I2: usize>(
487        sign: Sign,
488        numerator: [usize; I1],
489        denominator: [usize; I2],
490    ) -> Self {
491        let numerator = Ubig::try_from(numerator).expect("well formed numerator");
492        let denominator = NonZeroUbig::try_from(denominator).expect("well formed denominator");
493        debug_assert_eq!(sign == Sign::Zero, numerator.is_zero());
494
495        Self { sign, numerator, denominator }
496    }
497}
498
499impl<const S: usize, const I1: usize, const I2: usize> TryFrom<(Sign, [usize; I1], [usize; I2])> for Big<S> {
500    // TODO
501    type Error = ();
502
503    fn try_from((sign, numerator, denominator): (Sign, [usize; I1], [usize; I2])) -> Result<Self, Self::Error> {
504        match (sign, Ubig::try_from(numerator), NonZeroUbig::try_from(denominator)) {
505            (Sign::Positive | Sign::Negative, Ok(numerator), Ok(denominator)) if !numerator.is_zero() => {
506                // The limbs are taken as given, so they need not be coprime. Storing them that
507                // way would break the type's invariant: `PartialEq` compares the components while
508                // `Ord` cross multiplies, so the two would disagree, and the arithmetic kernels
509                // are written against the coprimality precondition. `Self::new` reduces its
510                // arguments for the same reason, so this does too.
511                let mut numerator = numerator;
512                let mut denominator = denominator;
513
514                // SAFETY: `Ubig::try_from` and `NonZeroUbig::try_from` only accept well formed
515                // arrays, the numerator was just tested to be non zero and the denominator cannot
516                // be zero by its type.
517                unsafe {
518                    simplify_fraction_without_info(numerator.inner_mut(), denominator.inner_mut());
519                }
520
521                Ok(Self { sign, numerator, denominator })
522            }
523            (Sign::Zero, Ok(numerator), Ok(_)) if numerator.is_zero() => Ok(Self::zero()),
524            _ => Err(()),
525        }
526    }
527}
528
529impl<const S: usize> From<&Big<S>> for Big<S> {
530    fn from(reference: &Big<S>) -> Self {
531        reference.clone()
532    }
533}
534
535impl<const S: usize> num_traits::Zero for Big<S> {
536    fn zero() -> Self {
537        Self {
538            sign: Sign::Zero,
539            numerator: Ubig::zero(),
540            denominator: NonZeroUbig::one(),
541        }
542    }
543
544    fn set_zero(&mut self) {
545        self.sign = Sign::Zero;
546        self.numerator.set_zero();
547        self.denominator.set_one();
548    }
549
550    fn is_zero(&self) -> bool {
551        self.sign == Sign::Zero
552    }
553}
554
555impl<const S: usize> num_traits::One for Big<S> {
556    fn one() -> Self {
557        Self {
558            sign: Sign::Positive,
559            numerator: Ubig::one(),
560            denominator: NonZeroUbig::one(),
561        }
562    }
563
564    fn set_one(&mut self) {
565        self.sign = Sign::Positive;
566        self.numerator.set_one();
567        self.denominator.set_one();
568    }
569
570    fn is_one(&self) -> bool {
571        self.sign == Sign::Positive &&
572            self.denominator[0] == 1 && self.numerator.len() == 1 &&
573            self.numerator[0] == 1 && self.denominator.len() == 1
574    }
575}
576
577impl<const S: usize> num_traits::One for NonZeroBig<S> {
578    fn one() -> Self {
579        Self {
580            sign: NonZeroSign::Positive,
581            numerator: NonZeroUbig::one(),
582            denominator: NonZeroUbig::one(),
583        }
584    }
585
586    fn set_one(&mut self) {
587        self.sign = NonZeroSign::Positive;
588        self.numerator.set_one();
589        self.denominator.set_one();
590    }
591
592    fn is_one(&self) -> bool {
593        self.sign == NonZeroSign::Positive &&
594            self.numerator[0] == 1 && self.denominator[0] == 1 &&
595            self.numerator.len() == 1 && self.denominator.len() == 1
596    }
597}
598
599impl<const S: usize> Big<S> {
600    pub fn new_signed<T: Into<Sign>>(sign: T, numerator: u64, denominator: u64) -> Option<Self> {
601        if denominator != 0 {
602            let sign = sign.into();
603
604            match (sign, numerator) {
605                (Sign::Positive | Sign::Negative, n) if n != 0 => {
606                    let (numerator, denominator) = simplify64(numerator, denominator);
607
608                    Some(Self {
609                        sign,
610                        numerator: Ubig::new(numerator as usize),
611                        denominator: unsafe { NonZeroUbig::new_unchecked(denominator as usize) },
612                    })
613                }
614                (Sign::Zero, 0) => Some(Self::zero()),
615                _ => None,
616            }
617        } else {
618            None
619        }
620    }
621}
622
623impl<const S: usize> FromStr for Big<S> {
624    type Err = &'static str;
625
626    fn from_str(s: &str) -> Result<Self, Self::Err> {
627        let _radix = 10;
628
629        if s.contains('.') || s.contains(',') {
630            return Err("Decimal separators are not supported");
631        }
632
633        match s.len() {
634            0 => Err("Empty string"),
635            _ => {
636                // Match on the first byte; the string doesn't have to start on an ASCII character,
637                // so slicing at index one is not necessarily on a character boundary
638                let (sign, s) = match s.as_bytes().first() {
639                    Some(b'+') => (Sign::Positive, &s[1..]),
640                    Some(b'-') => (Sign::Negative, &s[1..]),
641                    _ => (Sign::Positive, s),
642                };
643
644                match s.find('/') {
645                    None => {
646                        let numerator = Ubig::from_str(s)?;
647
648                        Ok(Big {
649                            sign: if numerator.is_not_zero() { sign } else { Sign::Zero },
650                            numerator,
651                            denominator: NonZeroUbig::one(),
652                        })
653                    }
654                    Some(index) => {
655                        // The number is a ratio between two others
656                        let (numerator_text, denominator_text) = (&s[..index], &s[(index + 1)..]);
657                        let mut numerator = Ubig::from_str(numerator_text)?;
658                        let mut denominator = NonZeroUbig::from_str(denominator_text)
659                            .map_err(|value| {
660                                match value {
661                                    "Zero value" => "Zero division",
662                                    other => other,
663                                }
664                            })?;
665
666                        Ok(if numerator.is_not_zero() {
667                            unsafe {
668                                // SAFETY: Are well-formed and non zero
669                                simplify_fraction_without_info(numerator.inner_mut(), denominator.inner_mut());
670                            }
671
672                            Big {
673                                sign,
674                                numerator,
675                                denominator,
676                            }
677                        } else {
678                            Zero::zero()
679                        })
680                    }
681                }
682            }
683        }
684    }
685}
686
687impl<const S: usize> fmt::Display for Big<S> {
688    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
689        match self.sign {
690            Sign::Positive => {}
691            Sign::Zero => return f.write_str("0"),
692            Sign::Negative => f.write_str("-")?,
693        }
694
695        fmt::Display::fmt(&self.numerator, f)?;
696
697        if !self.denominator.is_one() {
698            f.write_str("/")?;
699            fmt::Display::fmt(&self.denominator, f)?;
700        }
701
702        fmt::Result::Ok(())
703    }
704}
705
706/// The magnitude of the integer part of a ratio, truncated towards zero.
707///
708/// # Return value
709///
710/// `None` if the magnitude doesn't fit a `u128`, the magnitude otherwise.
711macro_rules! integer_magnitude {
712    ($value:expr) => {
713        {
714            if unsafe { !is_one_non_zero(&$value.denominator) } {
715                match cmp(&$value.numerator, &$value.denominator) {
716                    Ordering::Less => Some(0_u128),
717                    Ordering::Equal => Some(1_u128),
718                    Ordering::Greater => {
719                        let result = unsafe {
720                            // SAFETY: Denominator is not zero
721                            div::<S>(&$value.numerator, &$value.denominator)
722                        };
723
724                        words_to_u128(&result)
725                    }
726                }
727            } else {
728                words_to_u128(&$value.numerator)
729            }
730        }
731    }
732}
733
734macro_rules! signed_small {
735    ($value:expr, $target:ty, $unsigned:ty) => {
736        match $value.sign {
737            Sign::Zero => Some(0),
738            Sign::Positive => integer_magnitude!($value)
739                .and_then(|magnitude| <$target>::try_from(magnitude).ok()),
740            Sign::Negative => integer_magnitude!($value)
741                .and_then(|magnitude| {
742                    // Negating the magnitude in the target type would overflow for the most
743                    // negative value, so the negation is done in the unsigned domain
744                    if magnitude <= <$target>::MIN.unsigned_abs() as u128 {
745                        Some((magnitude as $unsigned).wrapping_neg() as $target)
746                    } else {
747                        None
748                    }
749                }),
750        }
751    }
752}
753
754macro_rules! unsigned_small {
755    ($value:expr, $target:ty) => {
756        match $value.sign {
757            Sign::Zero => Some(0),
758            Sign::Negative => None,
759            Sign::Positive => integer_magnitude!($value)
760                .and_then(|magnitude| <$target>::try_from(magnitude).ok()),
761        }
762    }
763}
764
765/// The ratio between the numerator and the denominator, as a float.
766///
767/// The value should not be zero.
768macro_rules! ratio_to_float {
769    ($value:expr, $target:ty, $to_float:ident) => {
770        {
771            let numerator = $value.numerator.$to_float().unwrap();
772            let denominator = $value.denominator.$to_float().unwrap();
773
774            if numerator.is_finite() && denominator.is_finite() {
775                numerator / denominator
776            } else {
777                // At least one of the two doesn't fit the target on its own, while their ratio
778                // might very well do so. Divide the highest words and account for the bits that
779                // were dropped below them with the exponent.
780                //
781                // Note that this keeps only a single word of each side, so the result can be off
782                // by an ulp; it is the best that can be done without a full length division.
783                let (numerator, numerator_shift) = highest_word(&$value.numerator);
784                let (denominator, denominator_shift) = highest_word(&$value.denominator);
785
786                let exponent = numerator_shift as i32 - denominator_shift as i32;
787                // Applying the exponent in two steps, because a single step can overflow the
788                // target while the result doesn't
789                let half = exponent / 2;
790
791                (numerator as $target / denominator as $target)
792                    * (2 as $target).powi(half)
793                    * (2 as $target).powi(exponent - half)
794            }
795        }
796    }
797}
798
799impl<const S: usize> ToPrimitive for Big<S> {
800    fn to_isize(&self) -> Option<isize> {
801        signed_small!(self, isize, usize)
802    }
803
804    fn to_i8(&self) -> Option<i8> {
805        signed_small!(self, i8, u8)
806    }
807
808    fn to_i16(&self) -> Option<i16> {
809        signed_small!(self, i16, u16)
810    }
811
812    fn to_i32(&self) -> Option<i32> {
813        signed_small!(self, i32, u32)
814    }
815
816    fn to_i64(&self) -> Option<i64> {
817        signed_small!(self, i64, u64)
818    }
819
820    fn to_i128(&self) -> Option<i128> {
821        signed_small!(self, i128, u128)
822    }
823
824    fn to_usize(&self) -> Option<usize> {
825        unsigned_small!(self, usize)
826    }
827
828    fn to_u8(&self) -> Option<u8> {
829        unsigned_small!(self, u8)
830    }
831
832    fn to_u16(&self) -> Option<u16> {
833        unsigned_small!(self, u16)
834    }
835
836    fn to_u32(&self) -> Option<u32> {
837        unsigned_small!(self, u32)
838    }
839
840    fn to_u64(&self) -> Option<u64> {
841        unsigned_small!(self, u64)
842    }
843
844    fn to_u128(&self) -> Option<u128> {
845        unsigned_small!(self, u128)
846    }
847
848    fn to_f32(&self) -> Option<f32> {
849        Some(match self.sign {
850            Sign::Zero => 0_f32,
851            Sign::Positive => ratio_to_float!(self, f32, to_f32),
852            Sign::Negative => -ratio_to_float!(self, f32, to_f32),
853        })
854    }
855
856    fn to_f64(&self) -> Option<f64> {
857        Some(match self.sign {
858            Sign::Zero => 0_f64,
859            Sign::Positive => ratio_to_float!(self, f64, to_f64),
860            Sign::Negative => -ratio_to_float!(self, f64, to_f64),
861        })
862    }
863}
864
865#[cfg(test)]
866mod test {
867    use std::cmp::Ordering;
868    use std::str::FromStr;
869
870    use num_traits::{One, ToPrimitive, Zero};
871    use smallvec::{smallvec, SmallVec};
872
873    use crate::{Abs, NonZeroSign, Rational128, Rational64, RationalBig, RationalUsize, Sign, Ubig};
874    use crate::integer::big::{BITS_PER_WORD, NonZeroUbig};
875    use crate::integer::big::io::from_str_radix;
876    use crate::integer::big::ops::normalize::simplify_fraction_without_info;
877    use crate::rational::big::{Big, Big8, NonZeroBig8};
878    use crate::RB;
879
880    #[test]
881    fn from() {
882        let x = Rational64::new(4, 3).unwrap();
883        let y = Big8::from(x);
884        let z = RB!(4, 3);
885        assert_eq!(y, z);
886
887        let x = <Big8 as num_traits::FromPrimitive>::from_f32(0_f32).unwrap();
888        assert_eq!(x, RB!(0, 1));
889
890        let x = <Big8 as num_traits::FromPrimitive>::from_f32(1_f32).unwrap();
891        assert_eq!(x, RB!(1, 1));
892
893        let x = <Big8 as num_traits::FromPrimitive>::from_f32(0.5).unwrap();
894        assert_eq!(x, RB!(1, 2));
895
896        let x = <Big8 as num_traits::FromPrimitive>::from_f32(2_f32).unwrap();
897        assert_eq!(x, RB!(2, 1));
898
899        let x = <Big8 as num_traits::FromPrimitive>::from_f32(1.5_f32).unwrap();
900        assert_eq!(x, RB!(3, 2));
901        let x = <Big8 as num_traits::FromPrimitive>::from_f64(0_f64).unwrap();
902        assert_eq!(x, RB!(0, 1));
903
904        let x = <Big8 as num_traits::FromPrimitive>::from_f64(1_f64).unwrap();
905        assert_eq!(x, RB!(1, 1));
906
907        let x = <Big8 as num_traits::FromPrimitive>::from_f64(0.5).unwrap();
908        assert_eq!(x, RB!(1, 2));
909
910        let x = <Big8 as num_traits::FromPrimitive>::from_f64(2_f64).unwrap();
911        assert_eq!(x, RB!(2, 1));
912
913        let x = <Big8 as num_traits::FromPrimitive>::from_f64(1.5_f64).unwrap();
914        assert_eq!(x, RB!(3, 2));
915
916        let x = <Big8 as num_traits::FromPrimitive>::from_f64(f64::MIN_POSITIVE).unwrap();
917        let (words, bits) = (1022 / BITS_PER_WORD, 1022 % BITS_PER_WORD);
918        let mut denominator = smallvec![0; words as usize];
919        denominator.push(1 << bits);
920        let expected = Big8 {
921            sign: Sign::Positive,
922            numerator: Ubig::one(),
923            denominator: unsafe { NonZeroUbig::from_inner_unchecked(denominator) },
924        };
925        assert_eq!(x, expected);
926
927        let x = <Big8 as num_traits::FromPrimitive>::from_f64(f64::MAX).unwrap();
928        let total_shift = (1 << (11 - 1)) - 1 - 52;
929        let (words, bits) = (total_shift / BITS_PER_WORD, total_shift % BITS_PER_WORD);
930        let mut numerator = smallvec![0; words as usize];
931        numerator.push(((1 << (52 + 1)) - 1) << bits); // Doesn't overflow, fits exactly in this last word
932        let expected = Big8 {
933            sign: Sign::Positive,
934            numerator: unsafe { Ubig::from_inner_unchecked(numerator) },
935            denominator: NonZeroUbig::one(),
936        };
937        assert_eq!(x, expected);
938
939        let y = <Big8 as num_traits::FromPrimitive>::from_f64(4f64 / 3f64).unwrap();
940        let z = RB!(4, 3);
941        assert!((y - z).abs() < Big8::new(1, 2 << 10).unwrap());
942
943        // 2 ** 543
944        assert_eq!(
945            RB!(28793048285076456849987446449190283896766061557132266451844835664715760516297522370041860391064901485759493828054533728788532902755163518009654497157537048672862208_f64),
946            RationalBig {
947                sign: Sign::Positive,
948                numerator: unsafe { Ubig::from_inner_unchecked(smallvec![0, 0, 0, 0, 0, 0, 0, 0, 1 << 31]) },
949                denominator: NonZeroUbig::one(),
950            }
951        );
952
953        assert_eq!(<Big8 as num_traits::FromPrimitive>::from_i64(0), Some(RB!(0)));
954        assert_eq!(<Big8 as num_traits::FromPrimitive>::from_i64(1), Some(RB!(1)));
955        assert_eq!(<Big8 as num_traits::FromPrimitive>::from_i64(-1), Some(-RB!(1)));
956        assert_eq!(<Big8 as num_traits::FromPrimitive>::from_u64(0), Some(RB!(0)));
957        assert_eq!(<Big8 as num_traits::FromPrimitive>::from_u64(1), Some(RB!(1)));
958        assert_eq!(<Big8 as num_traits::FromPrimitive>::from_f32(f32::NAN), None);
959        assert_eq!(<Big8 as num_traits::FromPrimitive>::from_f32(f32::INFINITY), None);
960        assert_eq!(<Big8 as num_traits::FromPrimitive>::from_f32(f32::NEG_INFINITY), None);
961        assert_eq!(<Big8 as num_traits::FromPrimitive>::from_f32(2_i64.pow(22) as f32), Some(RB!(2_i64.pow(22), 1)));
962        assert_eq!(<Big8 as num_traits::FromPrimitive>::from_f32(2_i64.pow(23) as f32), Some(RB!(2_i64.pow(23), 1)));
963        assert_eq!(<Big8 as num_traits::FromPrimitive>::from_f64(f64::NAN), None);
964        assert_eq!(<Big8 as num_traits::FromPrimitive>::from_f64(f64::INFINITY), None);
965        assert_eq!(<Big8 as num_traits::FromPrimitive>::from_f64(f64::NEG_INFINITY), None);
966        assert_eq!(<Big8 as num_traits::FromPrimitive>::from_f64(2_i64.pow(52) as f64), Some(RB!(2_i64.pow(52), 1)));
967        assert_eq!(<Big8 as num_traits::FromPrimitive>::from_f64(2_i64.pow(53) as f64), Some(RB!(2_i64.pow(53), 1)));
968    }
969
970    #[test]
971    fn test_one() {
972        let mut x = RB!(132);
973        x.set_one();
974        assert_eq!(x, RB!(1));
975        assert_eq!(RB!(1), Big::one());
976    }
977
978    #[test]
979    fn test_one_respects_sign() {
980        assert!(RB!(1).is_one());
981        assert!(!RB!(-1).is_one());
982        assert!(!RB!(0).is_one());
983        assert!(!RB!(2).is_one());
984        assert!(!RB!(1, 2).is_one());
985
986        // Setting a negative value to one makes it positive
987        let mut negative = RB!(-5, 6);
988        negative.set_one();
989        assert_eq!(negative.sign, Sign::Positive);
990        assert!(negative.is_one());
991        assert_eq!(negative, RB!(1));
992
993        // Setting the zero value to one doesn't leave the sign at zero
994        let mut zero = RB!(0);
995        zero.set_one();
996        assert_eq!(zero.sign, Sign::Positive);
997        assert!(zero.is_one());
998        assert_eq!(zero, RB!(1));
999
1000        // The same holds for the non zero variant
1001        let mut non_zero = NonZeroBig8 {
1002            sign: NonZeroSign::Negative,
1003            numerator: NonZeroUbig::one(),
1004            denominator: NonZeroUbig::one(),
1005        };
1006        assert!(!non_zero.is_one());
1007        non_zero.set_one();
1008        assert_eq!(non_zero.sign, NonZeroSign::Positive);
1009        assert!(non_zero.is_one());
1010        // `NonZeroBig` doesn't implement `Debug`, so this can't be an `assert_eq`
1011        assert!(non_zero == NonZeroBig8::one());
1012    }
1013
1014    #[test]
1015    fn test_signed() {
1016        assert_eq!(Big::new_signed(Sign::Positive, 1, 2).unwrap(), RB!(1, 2));
1017        assert_eq!(Big::new_signed(Sign::Zero, 0, 1).unwrap(), RB!(0));
1018        assert_eq!(Big::new_signed(Sign::Negative, 1, 3).unwrap(), RB!(-1, 3));
1019    }
1020
1021    #[test]
1022    fn test_new() {
1023        assert_eq!(RB!(3, 3), RB!(1));
1024    }
1025
1026    #[test]
1027    fn from_int() {
1028        assert_eq!(Big::from(0_i32), RB!(0));
1029        assert_eq!(Big::from(0_u32), RB!(0));
1030        assert_eq!(Big::from(1_i64), RB!(1));
1031        assert_eq!(Big::from(19_u8), RB!(19));
1032        assert_eq!(Big::from(-1_i16), RB!(-1));
1033    }
1034
1035    #[test]
1036    fn from_large_small_rational() {
1037        // The zero value is the canonical zero
1038        let zero = Big8::from(Rational128::zero());
1039        assert_eq!(zero.sign, Sign::Zero);
1040        assert!(zero.numerator.is_zero());
1041        assert!(zero.denominator.is_one());
1042        assert_eq!(zero, RB!(0));
1043        assert_eq!(Big8::from(RationalUsize::zero()), RB!(0));
1044
1045        assert_eq!(Big8::from(Rational128::one()), RB!(1));
1046        assert_eq!(Big8::from(RationalUsize::one()), RB!(1));
1047
1048        assert_eq!(Big8::from(Rational128::new(-1, 1).unwrap()), RB!(-1));
1049        assert_eq!(Big8::from(Rational128::new(-3, 2).unwrap()), RB!(-3, 2));
1050        assert_eq!(Big8::from(RationalUsize::new(-1, 1).unwrap()), RB!(-1));
1051        assert_eq!(Big8::from(RationalUsize::new(-3, 2).unwrap()), RB!(-3, 2));
1052
1053        // The input is in lowest terms, and stays that way
1054        assert_eq!(Big8::from(Rational128::new(4, 6).unwrap()), RB!(2, 3));
1055        assert_eq!(Big8::from(RationalUsize::new(-4, 6).unwrap()), RB!(-2, 3));
1056
1057        // References convert to the same value
1058        for value in [Rational128::zero(), Rational128::one(), Rational128::new(-3, 2).unwrap()] {
1059            assert_eq!(Big8::from(&value), Big8::from(value));
1060        }
1061        for value in [RationalUsize::zero(), RationalUsize::one(), RationalUsize::new(-3, 2).unwrap()] {
1062            assert_eq!(Big8::from(&value), Big8::from(value));
1063        }
1064
1065        assert_eq!(
1066            Big8::from(RationalUsize::new_signed(Sign::Negative, usize::MAX, 1).unwrap()),
1067            Big8::from_str(&format!("-{}", usize::MAX)).unwrap(),
1068        );
1069    }
1070
1071    #[test]
1072    fn from_rational_128_multiple_words() {
1073        // A `u128` doesn't fit in a single word on a 64 bit platform
1074        let words_needed = 128 / BITS_PER_WORD as usize;
1075
1076        let large_numerator = Rational128::new_signed(Sign::Positive, u128::MAX, 1).unwrap();
1077        assert_eq!(
1078            Big8::from(large_numerator),
1079            Big8::from_str("340282366920938463463374607431768211455").unwrap(),
1080        );
1081        assert_eq!(Big8::from(large_numerator).to_string(), u128::MAX.to_string());
1082        assert_eq!(Big8::from(large_numerator).numerator.len(), words_needed);
1083
1084        let large_denominator = Rational128::new_signed(Sign::Negative, 1, u128::MAX).unwrap();
1085        assert_eq!(
1086            Big8::from(large_denominator),
1087            Big8::from_str("-1/340282366920938463463374607431768211455").unwrap(),
1088        );
1089        assert_eq!(Big8::from(large_denominator).denominator.len(), words_needed);
1090
1091        let both_large = Rational128::new_signed(Sign::Negative, u128::MAX - 2, u128::MAX).unwrap();
1092        assert_eq!(
1093            Big8::from(both_large),
1094            Big8::from_str(
1095                "-340282366920938463463374607431768211453/340282366920938463463374607431768211455",
1096            ).unwrap(),
1097        );
1098
1099        // A value divided by itself is one
1100        assert_eq!(Big8::from(Rational128::new_signed(Sign::Positive, u128::MAX, u128::MAX).unwrap()), RB!(1));
1101        assert_eq!(Big8::from(Rational128::new_signed(Sign::Negative, u128::MAX, u128::MAX).unwrap()), -RB!(1));
1102    }
1103
1104    #[test]
1105    fn from_tuple() {
1106        assert_eq!(Big::from((0_i32, 1_u32)), RB!(0));
1107        assert_eq!(Big::from((0_i32, 5_u32)), RB!(0));
1108        assert_eq!(Big::from((1_i64, 2_u64)), RB!(1, 2));
1109        assert_eq!(Big::from((22_i8, 2_u8)), RB!(11));
1110        assert_eq!(Big::from((-1_i16, 2_u16)), RB!(-1, 2));
1111        assert_eq!(Big::from((-1_i32, 1_i32)), RB!(-1));
1112    }
1113
1114    #[test]
1115    fn from_tuple_signed_is_normalized() {
1116        // The fraction is reduced to lowest terms, whatever the signs are
1117        assert_eq!(Big8::from((2_i32, 4_i32)), RB!(1, 2));
1118        assert_eq!(Big8::from((-2_i32, 4_i32)), RB!(-1, 2));
1119        assert_eq!(Big8::from((2_i32, -4_i32)), RB!(-1, 2));
1120        assert_eq!(Big8::from((-2_i32, -4_i32)), RB!(1, 2));
1121        assert_eq!(Big8::from((6_i8, 4_i8)), RB!(3, 2));
1122        assert_eq!(Big8::from((100_i64, 10_i64)), RB!(10));
1123        assert_eq!(Big8::from((4_i128, 6_i128)), RB!(2, 3));
1124        assert_eq!(Big8::from((4_isize, 6_isize)), RB!(2, 3));
1125
1126        // Equality and ordering agree with each other
1127        assert_eq!(Big8::from((2_i32, 4_i32)).cmp(&RB!(1, 2)), Ordering::Equal);
1128        assert_eq!(Big8::from((-2_i32, 4_i32)).cmp(&RB!(-1, 2)), Ordering::Equal);
1129
1130        // A zero numerator gives the canonical zero, whatever the denominator is
1131        for value in [(0_i32, 5_i32), (0_i32, -5_i32), (0_i32, 1_i32)] {
1132            let zero = Big8::from(value);
1133
1134            assert_eq!(zero.sign, Sign::Zero);
1135            assert!(zero.numerator.is_zero());
1136            assert!(zero.denominator.is_one());
1137            assert_eq!(zero, RB!(0));
1138            assert_eq!(zero.cmp(&RB!(0)), Ordering::Equal);
1139        }
1140    }
1141
1142    #[test]
1143    fn from_str() {
1144        assert_eq!(Big::from_str("0"), Ok(RB!(0)));
1145        assert_eq!(Big::from_str("0000000"), Ok(RB!(0)));
1146        assert_eq!(Big::from_str("0/2"), Ok(RB!(0)));
1147        assert_eq!(Big::from_str("-0/2"), Ok(RB!(0)));
1148        assert_eq!(Big::from_str("-2"), Ok(RB!(-2)));
1149        assert_eq!(Big8::from_str("-2a"), Err("Character is not a digit"));
1150        assert_eq!(Big8::from_str("-2.1"), Err("Decimal separators are not supported"));
1151        assert_eq!(Big8::from_str("-2.1/3"), Err("Decimal separators are not supported"));
1152        assert_eq!(Big::from_str("-0"), Ok(RB!(0)));
1153        assert_eq!(Big8::from_str("0/"), Err("Empty string"));
1154        assert_eq!(Big8::from_str("0/0"), Err("Zero division"));
1155        assert_eq!(Big8::from_str(""), Err("Empty string"));
1156        assert_eq!(Big::from_str("1/2"), Ok(RB!(1, 2)));
1157        assert_eq!(Big::from_str("-3/2"), Ok(RB!(-3, 2)));
1158        assert_eq!(
1159            Big8::from_str("27670116110564327425"),
1160            Ok(Big {
1161                sign: Sign::Positive,
1162                numerator: unsafe { Ubig::from_inner_unchecked(smallvec![(1 << 63) + (1 << 0), 1]) },
1163                denominator: NonZeroUbig::one(),
1164            }),
1165        );
1166        assert_eq!(
1167            Big8::from_str("27670116110564327425/2"),
1168            Ok(Big {
1169                sign: Sign::Positive,
1170                numerator: unsafe { Ubig::from_inner_unchecked(smallvec![(1 << 63) + (1 << 0), 1]) },
1171                denominator: NonZeroUbig::new(2).unwrap(),
1172            }),
1173        );
1174        assert_eq!(
1175            Big8::from_str("27670116110564327425/27670116110564327425"),
1176            Ok(Big {
1177                sign: Sign::Positive,
1178                numerator: Ubig::one(),
1179                denominator: NonZeroUbig::one(),
1180            }),
1181        );
1182        assert_eq!(
1183            Big8::from_str("18446744073709551616/2"),
1184            Ok(Big {
1185                sign: Sign::Positive,
1186                numerator: unsafe { Ubig::from_inner_unchecked(smallvec![1 << 63]) },
1187                denominator: NonZeroUbig::one(),
1188            }),
1189        );
1190        assert_eq!(
1191            Big8::from_str("-36893488147419103232"),
1192            Ok(Big {
1193                sign: Sign::Negative,
1194                numerator: unsafe { Ubig::from_inner_unchecked(smallvec![0, 2]) },
1195                denominator: NonZeroUbig::one(),
1196            }),
1197        );
1198
1199        assert_eq!(from_str_radix::<10, 8>("407030945657418069975"), Ok(smallvec![1202576035807934423, 22]));
1200        assert_eq!(from_str_radix::<10, 8>("36893488147419103232"), Ok(smallvec![0, 1 << 1]));
1201        assert_eq!(from_str_radix::<10, 8>("18889465931478580854784"), Ok(smallvec![0, 1 << 10]));
1202        assert_eq!(from_str_radix::<10, 8>("19342813113834066795298816"), Ok(smallvec![0, 1 << 20]));
1203        assert_eq!(from_str_radix::<10, 8>("1208925819614629174706176"), Ok(smallvec![0, 1 << (80 - 64)]));
1204
1205        assert_eq!(
1206            Big8::from_str("-1208925819614629174706176/10301051460877537453973547267843"),
1207            Ok(Big {
1208                sign: Sign::Negative,
1209                numerator: unsafe { Ubig::from_inner_unchecked(smallvec![0, 1 << (80 - 64)]) },
1210                denominator: unsafe { NonZeroUbig::from_inner_unchecked(smallvec![0x6b9676a56c7c3703, 0x82047e0eae]) },
1211            }),
1212        );
1213
1214        type SV = SmallVec<[usize; 8]>;
1215
1216        let mut x = from_str_radix::<10, 8>("676230147000402641135208532975102322580080121519024130").unwrap();
1217        let expected: SV = smallvec![7877410236203542530, 0xe30d7c46c1f853f7, 1987261794136745];
1218        assert_eq!(x, expected);
1219        let mut y = from_str_radix::<10, 8>("68468465468464168545346854646").unwrap();
1220        let expected: SV = smallvec![7062882560094707446, 3711682950];
1221        assert_eq!(y, expected);
1222        unsafe { simplify_fraction_without_info(&mut x, &mut y) };
1223        let expected: SV = smallvec![13162077154956547073, 17403806869180131835, 993630897068372];
1224        assert_eq!(x, expected);
1225        let expected: SV = smallvec![3531441280047353723, 1855841475];
1226        assert_eq!(y, expected);
1227
1228        let z = Big8::from_str("676230147000402641135208532975102322580080121519024130/68468465468464168545346854646");
1229        assert_eq!(z, Ok(Big {
1230            sign: Sign::Positive,
1231            numerator: unsafe { Ubig::from_inner_unchecked(x) },
1232            denominator: unsafe { NonZeroUbig::from_inner_unchecked(y) },
1233        }));
1234
1235        assert_eq!(
1236            Big8::from_str("1190934288550035983230200000000/1219533185348999122218328290051").unwrap(),
1237            Big8::from_str("23800000000/24371529219").unwrap(),
1238        );
1239    }
1240
1241    #[test]
1242    fn test_to_str() {
1243        type SV = SmallVec<[usize; 8]>;
1244
1245        assert_eq!(Ubig::<1>::zero().to_string(), "0");
1246        assert_eq!(Ubig::<1>::one().to_string(), "1");
1247        assert_eq!(Ubig::<1>::new(2).to_string(), "2");
1248        assert_eq!(Ubig::<1>::new(3).to_string(), "3");
1249        assert_eq!(Ubig::<1>::new(10).to_string(), "10");
1250        assert_eq!(Ubig::<1>::new(11).to_string(), "11");
1251        assert_eq!(Ubig::<1>::new(101).to_string(), "101");
1252        assert_eq!(Ubig::<1>::new(123).to_string(), "123");
1253        assert_eq!(Ubig::<1>::new(usize::MAX).to_string(), "18446744073709551615");
1254        assert_eq!(unsafe { Ubig::<1>::from_inner_unchecked(smallvec![0, 1]) }.to_string(), "18446744073709551616");
1255        assert_eq!(unsafe { Ubig::<1>::from_inner_unchecked(smallvec![1, 1]) }.to_string(), "18446744073709551617");
1256
1257        for i in 1..100 {
1258            let expected = unsafe { Ubig::from_inner_unchecked(smallvec![i]) };
1259            assert_eq!(Ubig::<8>::from_str(&expected.to_string()), Ok(expected));
1260        }
1261
1262        let x: SV = smallvec![13284626917187606528, 14353657804625640860, 11366567065457835548, 501247837944];
1263        assert_eq!(
1264            unsafe { Ubig::from_inner_unchecked(x) }.to_string(),
1265            "3146383673420971972032023490593198871229613539715389096610302560000000",
1266        );
1267        let y: SV = smallvec![10945929334190035713, 13004504757950498814, 9];
1268        assert_eq!(unsafe { Ubig::from_inner_unchecked(y) }.to_string(), "3302432073363697202172148890923583722241");
1269        let y: SV = smallvec![602229295517812052, 3];
1270        assert_eq!(unsafe { Ubig::from_inner_unchecked(y) }.to_string(), "55942461516646466900");
1271    }
1272
1273    #[test]
1274    fn test_debug() {
1275        // The debug representation is the same as the display representation, so it round trips
1276        for text in [
1277            "0",
1278            "1",
1279            "-1",
1280            "2/3",
1281            "-2/3",
1282            "18446744073709551616",
1283            "-18446744073709551616",
1284            "676230147000402641135208532975102322580080121519024130",
1285            "676230147000402641135208532975102322580080121519024130/68468465468464168545346854646",
1286        ] {
1287            let value = RationalBig::from_str(text).unwrap();
1288
1289            assert_eq!(format!("{:?}", value), format!("{}", value));
1290            assert_eq!(RationalBig::from_str(&format!("{:?}", value)), Ok(value));
1291        }
1292
1293        assert_eq!(format!("{:?}", RB!(2, 3)), "2/3");
1294        assert_eq!(format!("{:?}", RB!(0)), "0");
1295        assert_eq!(format!("{:?}", RB!(-1)), "-1");
1296    }
1297
1298    /// Both the numerator and the denominator can be too large for the target on their own.
1299    #[test]
1300    fn test_to_float_large_ratio() {
1301        let (words, bits) = (1200 / BITS_PER_WORD, 1200 % BITS_PER_WORD);
1302        let mut numerator: SmallVec<[usize; 8]> = smallvec![0; words as usize];
1303        numerator.push(1 << bits);
1304        let mut denominator = numerator.clone();
1305        denominator[0] |= 1;
1306
1307        // 2 ** 1200 / (2 ** 1200 + 1), which is just below one and in lowest terms
1308        let value = Big8 {
1309            sign: Sign::Positive,
1310            numerator: unsafe { Ubig::from_inner_unchecked(numerator) },
1311            denominator: unsafe { NonZeroUbig::from_inner_unchecked(denominator) },
1312        };
1313
1314        assert_eq!(value.to_f64(), Some(1_f64));
1315        assert_eq!(value.to_f32(), Some(1_f32));
1316        assert_eq!((-value.clone()).to_f64(), Some(-1_f64));
1317    }
1318
1319    /// The magnitude of the most negative value doesn't fit the target type.
1320    #[test]
1321    fn test_to_primitive_most_negative() {
1322        assert_eq!(Big8::from_str("-128").unwrap().to_i8(), Some(i8::MIN));
1323        assert_eq!(Big8::from_str("-32768").unwrap().to_i16(), Some(i16::MIN));
1324        assert_eq!(Big8::from_str("-2147483648").unwrap().to_i32(), Some(i32::MIN));
1325        assert_eq!(Big8::from_str("-9223372036854775808").unwrap().to_i64(), Some(i64::MIN));
1326        assert_eq!(
1327            Big8::from_str("-170141183460469231731687303715884105728").unwrap().to_i128(),
1328            Some(i128::MIN),
1329        );
1330        assert_eq!(
1331            Big8::from_str(&isize::MIN.to_string()).unwrap().to_isize(),
1332            Some(isize::MIN),
1333        );
1334
1335        // One below the most negative value still doesn't fit
1336        assert_eq!(Big8::from_str("-129").unwrap().to_i8(), None);
1337        assert_eq!(Big8::from_str("-9223372036854775809").unwrap().to_i64(), None);
1338
1339        // The positive counterpart doesn't fit either
1340        assert_eq!(Big8::from_str("128").unwrap().to_i8(), None);
1341        assert_eq!(Big8::from_str("9223372036854775808").unwrap().to_i64(), None);
1342    }
1343
1344    #[test]
1345    fn test_to_primitive_128() {
1346        assert_eq!(RB!(0).to_u128(), Some(0));
1347        assert_eq!(RB!(0).to_i128(), Some(0));
1348        assert_eq!(RB!(1).to_u128(), Some(1));
1349        assert_eq!(RB!(-1).to_i128(), Some(-1));
1350        assert_eq!(RB!(-1).to_u128(), None);
1351        assert_eq!(RB!(1, 2).to_u128(), Some(0));
1352        assert_eq!(RB!(-3, 2).to_i128(), Some(-1));
1353
1354        // Round trip through the `Rational128` conversion
1355        let large = Rational128::new_signed(Sign::Positive, u128::MAX, 1).unwrap();
1356        assert_eq!(Big8::from(large).to_u128(), Some(u128::MAX));
1357        assert_eq!(Big8::from(large).to_i128(), None);
1358
1359        let large = Rational128::new_signed(Sign::Positive, i128::MAX as u128, 1).unwrap();
1360        assert_eq!(Big8::from(large).to_i128(), Some(i128::MAX));
1361
1362        // A value that needs more than a `u128`
1363        let too_large = Big8::from_str("340282366920938463463374607431768211456").unwrap();
1364        assert_eq!(too_large.to_u128(), None);
1365        assert_eq!(too_large.to_i128(), None);
1366    }
1367
1368    /// The first byte of the string is not necessarily a character boundary.
1369    #[test]
1370    fn test_from_str_not_ascii() {
1371        assert_eq!(Big8::from_str("\u{e9}"), Err("Character is not a digit"));
1372        assert_eq!(Big8::from_str("-\u{e9}"), Err("Character is not a digit"));
1373        assert_eq!(Big8::from_str("\u{e9}/2"), Err("Character is not a digit"));
1374        assert_eq!(Big8::from_str("1/\u{e9}"), Err("Character is not a digit"));
1375        assert_eq!(Big8::from_str("\u{1f600}"), Err("Character is not a digit"));
1376    }
1377
1378    /// A string that is empty, or that only contains whitespace, is not a number.
1379    #[test]
1380    fn test_from_str_no_digits() {
1381        for text in ["", " ", "\t\n", "-", "+", "/", "-/", " 1", "1 ", "1 / 2", "- 1"] {
1382            assert!(Big8::from_str(text).is_err(), "parsed {:?}", text);
1383        }
1384
1385        // A string of zeros is still zero
1386        assert_eq!(Big8::from_str("0"), Ok(RB!(0)));
1387        assert_eq!(Big8::from_str("0000"), Ok(RB!(0)));
1388        assert_eq!(Big8::from_str("-0000"), Ok(RB!(0)));
1389    }
1390
1391    #[test]
1392    fn test_to_primitive() {
1393        assert_eq!(RB!(1, 2).to_u64(), Some(0));
1394        assert_eq!(RB!(1, 1).to_u64(), Some(1));
1395        assert_eq!(RB!(2, 1).to_u64(), Some(2));
1396        assert_eq!(RB!(-1, 2).to_u64(), None);
1397        assert_eq!(RB!(1, 2).to_i8(), Some(0));
1398        assert_eq!(RB!(1, 1).to_i8(), Some(1));
1399        assert_eq!(RB!(2, 1).to_i8(), Some(2));
1400        assert_eq!(RB!(-1, 2).to_i8(), Some(0));
1401        assert_eq!(RB!(-1, 1).to_i8(), Some(-1));
1402
1403        assert_eq!(RB!(1, 2).to_f32(), Some(0.5_f32));
1404        assert_eq!(RB!(1, 2).to_f64(), Some(0.5_f64));
1405        assert_eq!(RB!(-1, 2).to_f64(), Some(-0.5_f64));
1406        assert_eq!(RB!(123456789, 1).to_f64(), Some(123456789_f64));
1407        assert_eq!(RB!(9_007_199_254_740_992, 1).to_f64(), Some(9_007_199_254_740_992_f64));
1408        assert_eq!(RB!(9_007_199_254_740_993, 1).to_f64(), Some(9_007_199_254_740_993_f64));
1409        assert_eq!(RB!(9_007_199_254_740_994, 1).to_f64(), Some(9_007_199_254_740_994_f64));
1410    }
1411}