Skip to main content

relp_num/integer/big/
io.rs

1#![allow(unused_unsafe)]
2
3use core::mem;
4use std::cmp::Ordering;
5use std::convert::TryFrom;
6use std::convert::TryInto;
7use std::fmt;
8use std::num::{NonZeroU128, NonZeroUsize};
9use std::str::FromStr;
10
11use num_traits::{FromPrimitive, One, ToPrimitive, Zero};
12use smallvec::SmallVec;
13use smallvec::smallvec;
14
15use crate::integer::big::{BITS_PER_WORD, NonZeroUbig, Ubig};
16use crate::integer::big::ops::building_blocks::is_well_formed;
17use crate::integer::big::ops::non_zero::{add_assign_single_non_zero, mul_assign_single_non_zero, shl_mut, shr_mut};
18use crate::rational::{f32_kind, f64_kind};
19use crate::rational::big::io::FloatKind;
20
21impl<const S: usize> Ubig<S> {
22    /// Creates a new unsigned integer with the small specified value.
23    #[must_use]
24    #[inline]
25    pub fn new(value: usize) -> Self {
26        Ubig(if value > 0 { smallvec![value] } else { smallvec![] })
27    }
28    /// Creates a new unsigned integer with the specified value.
29    ///
30    /// The value might not fit in a single word.
31    #[must_use]
32    #[inline]
33    pub fn new_u128(value: u128) -> Self {
34        Ubig(u128_words(value))
35    }
36    #[must_use]
37    #[inline]
38    pub(crate) unsafe fn from_inner_unchecked(values: SmallVec<[usize; S]>) -> Self {
39        debug_assert!(is_well_formed(&values));
40
41        Self(values)
42    }
43}
44
45impl<const S: usize> NonZeroUbig<S> {
46    /// Creates a new unsigned integer with the small specified value.
47    ///
48    /// If the specified value is non zero, this succeeds, otherwise, returns `None`.
49    #[must_use]
50    pub fn new(n: usize) -> Option<Self> {
51        if n != 0 {
52            Some(unsafe { Self(smallvec![n]) })
53        } else {
54            None
55        }
56    }
57    /// Creates a new unsigned integer with the specified value.
58    ///
59    /// The value might not fit in a single word; if the specified value is non zero, this succeeds,
60    /// otherwise, returns `None`.
61    #[must_use]
62    pub fn new_u128(n: u128) -> Option<Self> {
63        if n != 0 {
64            Some(Self(u128_words(n)))
65        } else {
66            None
67        }
68    }
69    #[must_use]
70    #[inline]
71    pub(crate) unsafe fn new_unchecked(value: usize) -> Self {
72        NonZeroUbig(smallvec![value])
73    }
74    /// # Safety
75    ///
76    /// The value should not be zero.
77    #[must_use]
78    #[inline]
79    pub(crate) unsafe fn new_u128_unchecked(value: u128) -> Self {
80        debug_assert_ne!(value, 0);
81
82        NonZeroUbig(u128_words(value))
83    }
84    #[must_use]
85    #[inline]
86    pub(crate) unsafe fn from_inner_unchecked(values: SmallVec<[usize; S]>) -> Self {
87        debug_assert!(is_well_formed(&values));
88
89        Self(values)
90    }
91}
92
93impl<const S: usize> Default for Ubig<S> {
94    fn default() -> Self {
95        Self::zero()
96    }
97}
98
99impl<const S: usize> From<NonZeroUsize> for Ubig<S> {
100    fn from(value: NonZeroUsize) -> Self {
101        Self(smallvec![value.get()])
102    }
103}
104
105impl<const S: usize> From<NonZeroUsize> for NonZeroUbig<S> {
106    fn from(value: NonZeroUsize) -> Self {
107        Self(smallvec![value.get()])
108    }
109}
110
111impl<const S: usize> From<NonZeroU128> for Ubig<S> {
112    fn from(value: NonZeroU128) -> Self {
113        Self(u128_words(value.get()))
114    }
115}
116
117impl<const S: usize> From<NonZeroU128> for NonZeroUbig<S> {
118    fn from(value: NonZeroU128) -> Self {
119        Self(u128_words(value.get()))
120    }
121}
122
123impl<const S: usize, const I: usize> TryFrom<[usize; I]> for Ubig<S> {
124    // TODO
125    type Error = ();
126
127    fn try_from(value: [usize; I]) -> Result<Self, Self::Error> {
128        if is_well_formed(&value) {
129            Ok(Self(SmallVec::from_slice(&value)))
130        } else {
131            Err(())
132        }
133    }
134}
135
136impl<const S: usize, const I: usize> TryFrom<[usize; I]> for NonZeroUbig<S> {
137    // TODO
138    type Error = ();
139
140    fn try_from(value: [usize; I]) -> Result<Self, Self::Error> {
141        if is_well_formed(&value) && !value.is_empty() {
142            Ok(Self(SmallVec::from_slice(&value)))
143        } else {
144            Err(())
145        }
146    }
147}
148
149impl<const S: usize> Zero for Ubig<S> {
150    #[inline]
151    fn zero() -> Self {
152        Self(smallvec![])
153    }
154
155    #[inline]
156    fn set_zero(&mut self) {
157        self.0.clear();
158    }
159
160    #[inline]
161    fn is_zero(&self) -> bool {
162        self.0.is_empty()
163    }
164}
165
166impl<const S: usize> One for Ubig<S> {
167    #[inline]
168    fn one() -> Self {
169        Self(smallvec![1])
170    }
171
172    #[inline]
173    fn set_one(&mut self) {
174        self.0.clear();
175        self.0.push(1);
176    }
177
178    #[inline]
179    fn is_one(&self) -> bool {
180        self.0.len() == 1 && self.0[0] == 1
181    }
182}
183
184impl<const S: usize> One for NonZeroUbig<S> {
185    #[inline]
186    fn one() -> Self {
187        Self(smallvec![1])
188    }
189
190    #[inline]
191    fn set_one(&mut self) {
192        self.0.truncate(1);
193        *unsafe { self.0.get_unchecked_mut(0) } = 1;
194    }
195
196    #[inline]
197    fn is_one(&self) -> bool {
198        *unsafe { self.0.get_unchecked(0) } == 1 && self.0.len() == 1
199    }
200}
201
202
203impl<const S: usize> From<usize> for Ubig<S> {
204    fn from(value: usize) -> Self {
205        Self(if value > 0 { smallvec![value] } else { smallvec![] })
206    }
207}
208
209impl<const S: usize> From<u128> for Ubig<S> {
210    fn from(value: u128) -> Self {
211        Self::new_u128(value)
212    }
213}
214
215/// Splits a `u128` into little endian words of the size of a `usize`.
216///
217/// The number of words that is needed depends on the platform: two on a 64 bit platform, four on a
218/// 32 bit platform.
219///
220/// # Return value
221///
222/// A well formed value: trailing zero words are removed, such that the result is empty if and only
223/// if the value is zero.
224#[must_use]
225#[inline]
226fn u128_words<const S: usize>(value: u128) -> SmallVec<[usize; S]> {
227    // At least one word, also when a `usize` would not be smaller than a `u128`
228    let word_count = (mem::size_of::<u128>() / mem::size_of::<usize>()).max(1) as u32;
229
230    let mut words = (0..word_count)
231        .map(|index| (value >> (index * BITS_PER_WORD)) as usize)
232        .collect::<SmallVec<[usize; S]>>();
233
234    while let Some(&0) = words.last() {
235        words.pop();
236    }
237
238    debug_assert!(is_well_formed(&words));
239
240    words
241}
242
243impl<const S: usize> FromStr for Ubig<S> {
244    // TODO(ARCHITECTURE): Better error handling
245    type Err = &'static str;
246
247    fn from_str(s: &str) -> Result<Self, Self::Err> {
248        from_str_radix::<10, S>(s).map(Self)
249    }
250}
251
252impl<const S: usize> FromStr for NonZeroUbig<S> {
253    // TODO(ARCHITECTURE): Better error handling
254    type Err = &'static str;
255
256    fn from_str(s: &str) -> Result<Self, Self::Err> {
257        from_str_radix::<10, S>(s)
258            .and_then(|inner| {
259                if !inner.is_empty() {
260                    Ok(unsafe { Self(inner) })
261                } else {
262                    Err("Zero value")
263                }
264            })
265    }
266}
267
268impl<const S: usize> fmt::Display for Ubig<S> {
269    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
270        f.write_str(&to_str_radix::<10>(self))
271    }
272}
273
274impl<const S: usize> fmt::Display for NonZeroUbig<S> {
275    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
276        // TODO(PERFORMANCE): Skip zero case
277        f.write_str(&to_str_radix::<10>(self))
278    }
279}
280
281#[inline]
282pub fn from_str_radix<const RADIX: u32, const S: usize>(s: &str) -> Result<SmallVec<[usize; S]>, &'static str> {
283    debug_assert!(RADIX <= 36);
284
285    match s.len() {
286        0 => Err("Empty string"),
287        _ => {
288            // Note that the input is not trimmed: whitespace is not a digit, so a string that is
289            // empty after trimming would otherwise be read as zero
290            let mut char_iterator = s
291                .chars()
292                .skip_while(|&c| c == '0');
293            match char_iterator.next() {
294                None => Ok(smallvec![]),
295                Some(value) => {
296                    match value.to_digit(RADIX) {
297                        None => Err("Character is not a digit"),
298                        Some(value) => {
299                            let mut non_zero_total = unsafe { smallvec![value as usize] };
300
301                            for character in char_iterator {
302                                match character.to_digit(RADIX) {
303                                    None => return Err("Character is not a digit"),
304                                    Some(value) => {
305                                        mul_assign_single_non_zero(&mut non_zero_total, RADIX as usize);
306                                        add_assign_single_non_zero(&mut non_zero_total, value as usize);
307                                    }
308                                }
309                            }
310
311                            Ok(non_zero_total)
312                        }
313                    }
314                }
315            }
316        }
317    }
318}
319
320fn to_str_radix<const RADIX: u32>(value: &[usize]) -> String {
321    assert!(RADIX > 1 && RADIX <= 36);
322
323    match value.len() {
324        0 => "0".to_string(),
325        _ => {
326            let mut digits = vec![0];
327
328            // Set highest word to the lowest index, and reverse the bits
329            let mut leading_zero_words = 0;
330            while value[leading_zero_words] == 0 {
331                // At least the last value is not allowed to be zero, so we don't have to check bounds
332                leading_zero_words += 1;
333            }
334            let leading_zero_bits = value.last().unwrap().leading_zeros();
335
336            // Set highest word to the lowest index, and reverse the bits
337            let mut value = value.iter()
338                .skip(leading_zero_words)
339                .map(|word| word.reverse_bits())
340                .rev()
341                .collect::<SmallVec<[usize; 8]>>();
342            let len_before_shift = value.len() as u32;
343            shr_mut(&mut value, 0, leading_zero_bits);
344
345            let bit_count = len_before_shift * BITS_PER_WORD - leading_zero_bits;
346            debug_assert_eq!(value[0] % 2, 1);
347            for bit_index in 0..bit_count {
348                update_digits::<RADIX>(&mut digits, value[0] % 2 == 1);
349                shr_mut(&mut value, 0, 1);
350
351                if value.is_empty() {
352                    // Had this many bits remaining
353                    for _ in (bit_index + 1)..(leading_zero_words as u32 * BITS_PER_WORD + bit_count) {
354                        update_digits::<RADIX>(&mut digits, false);
355                    }
356                    break;
357                }
358            }
359
360            digits.into_iter()
361                .rev()
362                .map(|digit| {
363                    if digit < 10 {
364                        digit.to_string()
365                    } else {
366                        ASCII_LOWER[(digit - 10) as usize].to_string()
367                    }
368                })
369                .collect()
370        }
371    }
372}
373
374static ASCII_LOWER: [char; 26] = [
375    'a', 'b', 'c', 'd', 'e',
376    'f', 'g', 'h', 'i', 'j',
377    'k', 'l', 'm', 'n', 'o',
378    'p', 'q', 'r', 's', 't',
379    'u', 'v', 'w', 'x', 'y',
380    'z',
381];
382
383fn update_digits<const RADIX: u32>(digits: &mut Vec<u32>, mut carry: bool) {
384    for digit in digits.iter_mut() {
385        *digit *= 2; // binary, each bit multiplies by 2
386        if carry {
387            *digit += 1;
388            carry = false;
389        }
390        if *digit >= RADIX {
391            *digit %= RADIX;
392            carry = true;
393        }
394    }
395    if carry {
396        digits.push(1);
397    }
398}
399
400impl<const S: usize> FromPrimitive for Ubig<S> {
401    fn from_isize(n: isize) -> Option<Self> {
402        if n >= 0 {
403            Some(Self::new(n.unsigned_abs()))
404        } else {
405            None
406        }
407    }
408
409    fn from_i8(n: i8) -> Option<Self> {
410        if n >= 0 {
411            Some(Self::new(n.unsigned_abs() as usize))
412        } else {
413            None
414        }
415    }
416
417    fn from_i16(n: i16) -> Option<Self> {
418        if n >= 0 {
419            Some(Self::new(n.unsigned_abs() as usize))
420        } else {
421            None
422        }
423    }
424
425    fn from_i32(n: i32) -> Option<Self> {
426        if n >= 0 {
427            Some(Self::new(n.unsigned_abs() as usize))
428        } else {
429            None
430        }
431    }
432
433    fn from_i64(n: i64) -> Option<Self> {
434        if n >= 0 {
435            Some(Self::new(n.unsigned_abs() as usize))
436        } else {
437            None
438        }
439    }
440
441    fn from_i128(n: i128) -> Option<Self> {
442        if n >= 0 {
443            Self::from_u128(n.unsigned_abs())
444        } else {
445            None
446        }
447    }
448
449    fn from_usize(n: usize) -> Option<Self> {
450        Some(Self::new(n))
451    }
452
453    fn from_u8(n: u8) -> Option<Self> {
454        Some(Self::new(n as usize))
455    }
456
457    fn from_u16(n: u16) -> Option<Self> {
458        Some(Self::new(n as usize))
459    }
460
461    fn from_u32(n: u32) -> Option<Self> {
462        Some(Self::new(n as usize))
463    }
464
465    fn from_u64(n: u64) -> Option<Self> {
466        Some(Self::new(n as usize))
467    }
468
469    fn from_u128(n: u128) -> Option<Self> {
470        Some(Self::new_u128(n))
471    }
472
473    fn from_f32(n: f32) -> Option<Self> {
474        Self::from_float_kind(f32_kind(n))
475    }
476
477    fn from_f64(n: f64) -> Option<Self> {
478        Self::from_float_kind(f64_kind(n))
479    }
480}
481
482impl<const S: usize> Ubig<S> {
483    fn from_float_kind(kind: FloatKind) -> Option<Self> {
484        match kind  {
485            FloatKind::Subnormal(as_ratio) | FloatKind::Normal(as_ratio) => {
486                if as_ratio.sign == 0 {
487                    let result = match as_ratio.exponent.cmp(&0) {
488                        Ordering::Less => {
489                            // The value is `fraction * 2 ** exponent`, so it is shifted to the
490                            // right; the fractional part is truncated towards zero. The shift can
491                            // be larger than the number of bits in the fraction, a subnormal `f64`
492                            // has an exponent of -1074.
493                            let shift = as_ratio.exponent.unsigned_abs();
494                            let result = as_ratio.fraction.get().unbounded_shr(shift);
495
496                            Self::new_u128(result as u128)
497                        }
498                        Ordering::Equal => Self::new_u128(as_ratio.fraction.get() as u128),
499                        Ordering::Greater => {
500                            // The value is shifted to the left
501                            let shift = as_ratio.exponent.unsigned_abs();
502                            let (words, bits) = (shift / BITS_PER_WORD, shift % BITS_PER_WORD);
503
504                            // The fraction is not zero, so this is well formed and not empty
505                            let mut values = u128_words::<S>(as_ratio.fraction.get() as u128);
506                            shl_mut(&mut values, words as usize, bits);
507
508                            unsafe {
509                                // SAFETY: Shifting a non zero value to the left keeps it well
510                                // formed and non zero
511                                Self::from_inner_unchecked(values)
512                            }
513                        }
514                    };
515
516                    Some(result)
517                } else {
518                    None
519                }
520            },
521            FloatKind::Zero => Some(Self::zero()),
522            _ => None,
523        }
524    }
525}
526
527
528macro_rules! small {
529    ($value:expr) => {
530        {
531            match $value.len() {
532                0 => Some(0),
533                1 => $value[0].try_into().ok(),
534                _ => None,
535            }
536        }
537    }
538}
539
540/// The number of significant bits of the value.
541#[must_use]
542#[inline]
543pub(crate) fn bit_length(words: &[usize]) -> u32 {
544    debug_assert!(is_well_formed(words));
545
546    match words.last() {
547        None => 0,
548        Some(&last) => (words.len() as u32 - 1) * BITS_PER_WORD + last.bit_width(),
549    }
550}
551
552/// The highest word of the value, together with the number of bits that were dropped below it.
553///
554/// This is the value shifted to the right as far as is needed to fit a single word; it keeps the
555/// most significant bits, which is what a float needs.
556///
557/// The value should not be zero.
558#[must_use]
559pub(crate) fn highest_word(words: &[usize]) -> (usize, u32) {
560    debug_assert!(!words.is_empty());
561
562    let shift = bit_length(words).saturating_sub(BITS_PER_WORD);
563    let (word_shift, bit_shift) = ((shift / BITS_PER_WORD) as usize, shift % BITS_PER_WORD);
564    debug_assert!(word_shift < words.len());
565
566    let low = words[word_shift] >> bit_shift;
567    // A `bit_shift` of zero would ask for a shift by the full width of a word, which is where
568    // `unbounded_shl` returns the zero the branch used to supply.
569    let high = match words.get(word_shift + 1) {
570        Some(&word) => word.unbounded_shl(BITS_PER_WORD - bit_shift),
571        None => 0,
572    };
573
574    (low | high, shift)
575}
576
577/// The value of the words as a `u128`.
578///
579/// # Return value
580///
581/// `None` if the value doesn't fit a `u128`, the value otherwise.
582#[must_use]
583#[inline]
584pub(crate) fn words_to_u128(words: &[usize]) -> Option<u128> {
585    // At least one word, also when a `usize` would not be smaller than a `u128`
586    let word_count = (mem::size_of::<u128>() / mem::size_of::<usize>()).max(1);
587
588    if words.len() > word_count {
589        return None;
590    }
591
592    let mut total = 0_u128;
593    for (index, &word) in words.iter().enumerate() {
594        total |= (word as u128) << (index as u32 * BITS_PER_WORD);
595    }
596
597    Some(total)
598}
599
600macro_rules! to_primitive_impl {
601    ($name:ty) => {
602        impl<const S: usize> ToPrimitive for $name {
603            fn to_isize(&self) -> Option<isize> {
604                small!(self)
605            }
606
607            fn to_i8(&self) -> Option<i8> {
608                small!(self)
609            }
610
611            fn to_i16(&self) -> Option<i16> {
612                small!(self)
613            }
614
615            fn to_i32(&self) -> Option<i32> {
616                small!(self)
617            }
618
619            fn to_i64(&self) -> Option<i64> {
620                small!(self)
621            }
622
623            fn to_i128(&self) -> Option<i128> {
624                words_to_u128(self).and_then(|value| i128::try_from(value).ok())
625            }
626
627            fn to_usize(&self) -> Option<usize> {
628                small!(self)
629            }
630
631            fn to_u8(&self) -> Option<u8> {
632                small!(self)
633            }
634
635            fn to_u16(&self) -> Option<u16> {
636                small!(self)
637            }
638
639            fn to_u32(&self) -> Option<u32> {
640                small!(self)
641            }
642
643            fn to_u64(&self) -> Option<u64> {
644                small!(self)
645            }
646
647            fn to_u128(&self) -> Option<u128> {
648                words_to_u128(self)
649            }
650
651            fn to_f32(&self) -> Option<f32> {
652                Some(make_float_32::<S>(self))
653            }
654
655            fn to_f64(&self) -> Option<f64> {
656                Some(make_float_64::<S>(self))
657            }
658        }
659    }
660}
661
662to_primitive_impl!(Ubig<S>);
663to_primitive_impl!(NonZeroUbig<S>);
664
665macro_rules! define_float_maker {
666    ($name:ident, $target:ty, $bit_array:ty, $bits_in_exponent:expr, $bits_in_fraction:expr) => {
667        fn $name<const S: usize>(values: &[usize]) -> $target {
668            let sign = 0;
669
670            match values.last() {
671                None => <$target>::zero(),
672                Some(last_value) => {
673                    debug_assert_ne!(*last_value, 0);
674                    let bits_in_highest = last_value.bit_width();
675                    debug_assert!(bits_in_highest > 0);
676                    let bits = (values.len() - 1) as u32 * BITS_PER_WORD + bits_in_highest;
677                    debug_assert!(bits > 0);
678
679                    let biased_exponent = bits as $bit_array + ((2 as $bit_array).pow($bits_in_exponent - 1) - 1 - 1);
680                    if biased_exponent >= ((1 as $bit_array) << $bits_in_exponent) - 1 {
681                        // The value doesn't fit the target; an exponent field of all ones is
682                        // infinity, anything larger would overflow into the sign bit
683                        return <$target>::INFINITY;
684                    }
685                    let exponent = biased_exponent << $bits_in_fraction;
686
687                    let mut copy = SmallVec::<[usize; S]>::from_slice(values);
688                    // The leading bit is implicit in the target's representation, so it is dropped
689                    // here rather than encoded.
690                    *copy.last_mut().unwrap() -= last_value.isolate_highest_one();
691
692                    let remaining_bits = bits - 1;
693                    let fraction = match remaining_bits.cmp(&$bits_in_fraction) {
694                        Ordering::Less => copy[0] << ($bits_in_fraction - remaining_bits),
695                        Ordering::Equal => copy[0],
696                        Ordering::Greater => {
697                            let to_shift = remaining_bits - $bits_in_fraction;
698                            let (highest_bit_lost_set, any_other_set) = {
699                                let index = to_shift - 1;
700
701                                let (words, bits) = ((index / BITS_PER_WORD) as usize, index % BITS_PER_WORD);
702                                let highest_bit_lost = copy[words] & (1 << bits) > 0;
703
704                                // With `bits` at zero there is nothing below the bit that was
705                                // just tested, and the mask `unbounded_shr` returns is empty.
706                                let mask = usize::MAX.unbounded_shr(BITS_PER_WORD - bits);
707                                let any_other = copy[..words].iter().any(|&w| w != 0)
708                                    || mask & copy[words] > 0;
709
710                                (highest_bit_lost, any_other)
711                            };
712
713                            let (words, bits) = (to_shift / BITS_PER_WORD, to_shift % BITS_PER_WORD);
714
715                            let unrounded = 'scope: {
716                                // Subtracting the implicit leading bit can have zeroed the highest
717                                // words; drop them to satisfy the assumptions of `shr_mut`. Note
718                                // that `words` counts the lowest words that are shifted away, so
719                                // it is unaffected by this.
720                                while let Some(&0) = copy.last() {
721                                    copy.pop();
722                                }
723
724                                if words as usize >= copy.len() {
725                                    // Everything that is left is shifted away; this includes the
726                                    // case where the value is a power of two and nothing is left
727                                    break 'scope 0;
728                                }
729
730                                shr_mut(&mut copy, words as usize, bits);
731
732                                match copy.last() {
733                                    Some(&value) => value,
734                                    None => 0,
735                                }
736                            };
737
738                            if highest_bit_lost_set {
739                                if any_other_set {
740                                    unrounded + 1
741                                } else {
742                                    // Tie to even
743                                    if unrounded % 2 == 1 {
744                                        unrounded + 1
745                                    } else {
746                                        unrounded
747                                    }
748                                }
749                            } else {
750                                unrounded
751                            }
752                        },
753                    };
754
755                    // The fraction is added rather than or-ed in: rounding can carry out of
756                    // the mantissa, leaving `fraction == 1 << $bits_in_fraction`, and that carry
757                    // has to increment the exponent. Or-ing loses it whenever the biased exponent
758                    // is odd, which halves the result. The exponent is bounded above, so the carry
759                    // at worst produces an all ones exponent with a zero mantissa, which is the
760                    // correct encoding of infinity.
761                    <$target>::from_bits(sign | (exponent + fraction as $bit_array))
762                }
763            }
764        }
765    }
766}
767
768define_float_maker!(make_float_32, f32, u32, 8, 23);
769define_float_maker!(make_float_64, f64, u64, 11, 52);
770
771#[cfg(test)]
772mod test {
773    use std::num::NonZeroU128;
774    use std::str::FromStr;
775
776    use num_traits::FromPrimitive;
777    use num_traits::One;
778    use num_traits::ToPrimitive;
779    use num_traits::Zero;
780    use smallvec::{smallvec, SmallVec};
781
782    use crate::integer::big::{BITS_PER_WORD, NonZeroUbig};
783    use crate::Ubig;
784
785    /// Two to the power of the argument, as an arbitrary precision integer.
786    fn power_of_two<const S: usize>(power: u32) -> Ubig<S> {
787        let (words, bits) = (power / BITS_PER_WORD, power % BITS_PER_WORD);
788
789        let mut values: SmallVec<[usize; S]> = smallvec![0; words as usize];
790        values.push(1 << bits);
791
792        unsafe {
793            // SAFETY: The last word is not zero
794            Ubig::from_inner_unchecked(values)
795        }
796    }
797
798    /// Two to the power of the argument, plus one.
799    fn power_of_two_plus_one<const S: usize>(power: u32) -> Ubig<S> {
800        debug_assert!(power >= BITS_PER_WORD);
801
802        let mut value = power_of_two::<S>(power);
803        unsafe {
804            // SAFETY: The power is at least a word, so the lowest word is zero and the value stays
805            // well formed
806            value.inner_mut()[0] |= 1;
807        }
808
809        value
810    }
811
812    /// The values that are interesting when a `u128` is split into words.
813    const U128_CASES: [u128; 8] = [
814        0,
815        1,
816        19,
817        usize::MAX as u128,
818        usize::MAX as u128 + 1,
819        (usize::MAX as u128 + 1) * 3,
820        i128::MAX as u128,
821        u128::MAX,
822    ];
823
824    #[test]
825    fn test_from_u128() {
826        assert_eq!(Ubig::<8>::new_u128(0), Ubig::zero());
827        assert_eq!(Ubig::<8>::new_u128(1), Ubig::one());
828        assert_eq!(Ubig::<8>::new_u128(19), Ubig::new(19));
829        assert_eq!(Ubig::<8>::new_u128(usize::MAX as u128), Ubig::new(usize::MAX));
830
831        // Nothing is truncated when more than a single word is needed
832        for value in U128_CASES {
833            assert_eq!(Ubig::<8>::new_u128(value).to_string(), value.to_string());
834            assert_eq!(Ubig::<8>::from_str(&value.to_string()), Ok(Ubig::new_u128(value)));
835
836            // The `From` implementation is the same conversion
837            assert_eq!(Ubig::<8>::from(value), Ubig::new_u128(value));
838        }
839    }
840
841    #[test]
842    fn test_from_u128_is_normalized() {
843        // The zero value is empty, all others don't have a trailing zero word
844        assert!(Ubig::<8>::new_u128(0).inner().is_empty());
845        for value in U128_CASES {
846            assert!(unsafe { Ubig::<8>::new_u128(value).is_well_formed() });
847            assert_eq!(Ubig::<8>::new_u128(value).is_zero(), value == 0);
848        }
849    }
850
851    #[test]
852    fn test_non_zero_from_u128() {
853        assert_eq!(NonZeroUbig::<8>::new_u128(0), None);
854        assert_eq!(NonZeroUbig::<8>::new_u128(1), Some(NonZeroUbig::one()));
855
856        for value in U128_CASES.into_iter().filter(|&value| value != 0) {
857            let expected = NonZeroUbig::<8>::from_str(&value.to_string()).unwrap();
858
859            assert_eq!(NonZeroUbig::<8>::new_u128(value), Some(expected.clone()));
860            assert_eq!(unsafe { NonZeroUbig::<8>::new_u128_unchecked(value) }, expected);
861            assert!(unsafe { expected.is_well_formed() });
862
863            let non_zero = NonZeroU128::new(value).unwrap();
864            assert_eq!(NonZeroUbig::<8>::from(non_zero), expected);
865            assert_eq!(Ubig::<8>::from(non_zero), Ubig::new_u128(value));
866        }
867    }
868
869    #[test]
870    fn test_from_primitive() {
871        assert_eq!(Ubig::<1>::from_i16(-4), None);
872        assert_eq!(Ubig::<1>::from_u16(4), Some(Ubig::from(4_usize)));
873        assert_eq!(Ubig::<1>::from_i128(0), Some(Ubig::from(0_usize)));
874        assert_eq!(Ubig::<1>::from_i128(1), Some(Ubig::from(1_usize)));
875        assert_eq!(Ubig::<1>::from_i128(-1), None);
876
877        assert_eq!(Ubig::<1>::from_f32(1.5_f32), Some(Ubig::from(1_usize)));
878        assert_eq!(Ubig::<1>::from_f32(1_f32), Some(Ubig::from(1_usize)));
879        assert_eq!(Ubig::<1>::from_f32(0.5_f32), Some(Ubig::from(0_usize)));
880        assert_eq!(Ubig::<1>::from_f32(0.75_f32), Some(Ubig::from(0_usize)));
881        assert_eq!(Ubig::<1>::from_f32(0_f32), Some(Ubig::from(0_usize)));
882
883        assert_eq!(Ubig::<1>::from_f32(-1.5_f32), None);
884        assert_eq!(Ubig::<1>::from_f32(-0_f32), Some(Ubig::from(0_usize)));
885    }
886
887    #[test]
888    fn test_from_primitive_large() {
889        for value in U128_CASES {
890            assert_eq!(Ubig::<8>::from_u128(value), Some(Ubig::new_u128(value)));
891        }
892
893        assert_eq!(Ubig::<8>::from_i128(i128::MAX), Some(Ubig::new_u128(i128::MAX as u128)));
894        assert_eq!(Ubig::<8>::from_i128(i128::MIN), None);
895        assert_eq!(Ubig::<8>::from_u128(u128::MAX).unwrap().to_string(), u128::MAX.to_string());
896    }
897
898    /// A positive binary exponent means the fraction is shifted to the left, not to the right.
899    #[test]
900    fn test_from_float_with_positive_exponent() {
901        // The formatting with a zero precision is the exact value of the float, which is an integer
902        for value in [
903            1e16_f64,
904            9007199254740992_f64,
905            1.8446744073709552e19,
906            2_f64.powi(64),
907            2_f64.powi(100),
908            2_f64.powi(1000),
909            1e300,
910        ] {
911            let expected = Ubig::<8>::from_str(&format!("{:.0}", value)).unwrap();
912            assert_eq!(Ubig::<8>::from_f64(value), Some(expected), "value {}", value);
913        }
914
915        for value in [1e30_f32, 2_f32.powi(64), 2_f32.powi(100), f32::MAX] {
916            let expected = Ubig::<8>::from_str(&format!("{:.0}", value)).unwrap();
917            assert_eq!(Ubig::<8>::from_f32(value), Some(expected), "value {}", value);
918        }
919    }
920
921    /// A negative binary exponent can shift away more bits than a `u64` has.
922    #[test]
923    fn test_from_float_with_large_negative_exponent() {
924        // Truncation towards zero, so all of these are zero
925        assert_eq!(Ubig::<8>::from_f64(f64::MIN_POSITIVE), Some(Ubig::zero()));
926        assert_eq!(Ubig::<8>::from_f64(f64::from_bits(1)), Some(Ubig::zero()));
927        assert_eq!(Ubig::<8>::from_f64(1e-300), Some(Ubig::zero()));
928        assert_eq!(Ubig::<8>::from_f32(1e-30_f32), Some(Ubig::zero()));
929        assert_eq!(Ubig::<8>::from_f32(f32::MIN_POSITIVE), Some(Ubig::zero()));
930        assert_eq!(Ubig::<8>::from_f32(f32::from_bits(1)), Some(Ubig::zero()));
931    }
932
933    /// Subtracting the implicit leading bit can zero the highest word, which used to underflow the
934    /// bookkeeping of the words that are shifted away.
935    #[test]
936    fn test_to_float_powers_of_two() {
937        for power in [0_u32, 1, 52, 53, 62, 63, 64, 65, 66, 100, 127, 128, 200, 1000] {
938            let value = power_of_two::<8>(power);
939            assert_eq!(value.to_f64(), Some(2_f64.powi(power as i32)), "2 ** {}", power);
940        }
941
942        for power in [0_u32, 1, 22, 23, 30, 31, 32, 33, 63, 64, 65, 100, 127] {
943            let value = power_of_two::<8>(power);
944            assert_eq!(value.to_f32(), Some(2_f32.powi(power as i32)), "2 ** {}", power);
945        }
946    }
947
948    #[test]
949    fn test_to_float_one_above_power_of_two() {
950        for power in [64_u32, 65, 66, 100, 127, 128, 200] {
951            let value = power_of_two_plus_one::<8>(power);
952            assert_eq!(value.to_f64(), Some(2_f64.powi(power as i32)), "2 ** {} + 1", power);
953        }
954
955        for power in [64_u32, 65, 100, 127] {
956            let value = power_of_two_plus_one::<8>(power);
957            assert_eq!(value.to_f32(), Some(2_f32.powi(power as i32)), "2 ** {} + 1", power);
958        }
959    }
960
961    /// A value that is too large for the target overflowed the exponent field into the sign bit.
962    #[test]
963    fn test_to_float_overflow_is_infinite() {
964        // Larger than the largest finite `f32`
965        for power in [128_u32, 129, 140, 300, 1000] {
966            for value in [power_of_two::<8>(power), power_of_two_plus_one::<8>(power)] {
967                let result = value.to_f32().unwrap();
968
969                assert_eq!(result, f32::INFINITY, "2 ** {}", power);
970                assert!(result.is_sign_positive(), "2 ** {}", power);
971            }
972        }
973
974        // Larger than the largest finite `f64`
975        for power in [1024_u32, 1025, 2000] {
976            for value in [power_of_two::<8>(power), power_of_two_plus_one::<8>(power)] {
977                let result = value.to_f64().unwrap();
978
979                assert_eq!(result, f64::INFINITY, "2 ** {}", power);
980                assert!(result.is_sign_positive(), "2 ** {}", power);
981            }
982        }
983
984        // Just below the threshold the values are still finite
985        assert_eq!(power_of_two::<8>(127).to_f32(), Some(2_f32.powi(127)));
986        assert_eq!(power_of_two::<8>(1023).to_f64(), Some(2_f64.powi(1023)));
987    }
988
989    /// Rounding can carry out of the mantissa, which has to increment the exponent.
990    ///
991    /// The parts used to be or-ed together, which drops that carry whenever the biased exponent is
992    /// odd, that is, whenever the value has an odd number of bits. The result is then exactly half
993    /// of the true value. `2 ** p - d` for a small `d` rounds up to `2 ** p` and so is the shape
994    /// that triggers it.
995    #[test]
996    fn test_to_float_mantissa_carry() {
997        assert_eq!(Ubig::<8>::from((1_u128 << 55) - 1).to_f64(), Some(2_f64.powi(55)));
998        assert_eq!(Ubig::<8>::from((1_u128 << 25) - 1).to_f32(), Some(2_f32.powi(25)));
999
1000        for power in 2_u32..=127 {
1001            // Do not underflow at the small powers
1002            for difference in 1..=64_u128.min((1_u128 << power) - 1) {
1003                let value = (1_u128 << power) - difference;
1004                let big = Ubig::<8>::from(value);
1005
1006                assert_eq!(big.to_f64(), Some(value as f64), "2 ** {power} - {difference}");
1007                assert_eq!(big.to_f32(), Some(value as f32), "2 ** {power} - {difference}");
1008            }
1009        }
1010    }
1011
1012    #[test]
1013    fn test_to_primitive_128() {
1014        for value in U128_CASES {
1015            assert_eq!(Ubig::<8>::new_u128(value).to_u128(), Some(value));
1016        }
1017
1018        assert_eq!(Ubig::<8>::zero().to_i128(), Some(0));
1019        assert_eq!(Ubig::<8>::new_u128(i128::MAX as u128).to_i128(), Some(i128::MAX));
1020        assert_eq!(Ubig::<8>::new_u128(i128::MAX as u128 + 1).to_i128(), None);
1021        assert_eq!(Ubig::<8>::new_u128(u128::MAX).to_i128(), None);
1022
1023        assert_eq!(NonZeroUbig::<8>::new_u128(u128::MAX).unwrap().to_u128(), Some(u128::MAX));
1024        assert_eq!(NonZeroUbig::<8>::one().to_i128(), Some(1));
1025
1026        // Larger than a `u128`
1027        let too_large = Ubig::<8>::from_str("340282366920938463463374607431768211456").unwrap();
1028        assert_eq!(too_large.to_u128(), None);
1029        assert_eq!(too_large.to_i128(), None);
1030    }
1031
1032    #[test]
1033    fn test_to_primitive() {
1034        assert_eq!(Ubig::<1>::from(4_usize).to_i16(), Some(4));
1035
1036        assert_eq!(Ubig::<1>::from(0_usize).to_f32(), Some(0_f32));
1037        assert_eq!(Ubig::<1>::from(1_usize).to_f32(), Some(1_f32));
1038        assert_eq!(Ubig::<1>::from(2_usize).to_f32(), Some(2_f32));
1039        assert_eq!(Ubig::<1>::from(3_usize).to_f32(), Some(3_f32));
1040        assert_eq!(Ubig::<1>::from(4_usize).to_f32(), Some(4_f32));
1041        assert_eq!(Ubig::<1>::from(5_usize).to_f32(), Some(5_f32));
1042        assert_eq!(Ubig::<1>::from(6_usize).to_f32(), Some(6_f32));
1043        assert_eq!(Ubig::<1>::from(7_usize).to_f32(), Some(7_f32));
1044
1045        assert_eq!(Ubig::<1>::from(0_usize).to_f64(), Some(0_f64));
1046        assert_eq!(Ubig::<1>::from(1_usize).to_f64(), Some(1_f64));
1047        assert_eq!(Ubig::<1>::from(2_usize).to_f64(), Some(2_f64));
1048        assert_eq!(Ubig::<1>::from(3_usize).to_f64(), Some(3_f64));
1049        assert_eq!(Ubig::<1>::from(4_usize).to_f64(), Some(4_f64));
1050        assert_eq!(Ubig::<1>::from(5_usize).to_f64(), Some(5_f64));
1051        assert_eq!(Ubig::<1>::from(6_usize).to_f64(), Some(6_f64));
1052        assert_eq!(Ubig::<1>::from(7_usize).to_f64(), Some(7_f64));
1053        assert_eq!(Ubig::<1>::from(123456789_usize).to_f64(), Some(123456789_f64));
1054    }
1055
1056    #[test]
1057    fn test_to_primitive_rounding() {
1058        assert_eq!(Ubig::<1>::from(16777216_usize).to_f32(), Some(16777216_f32));
1059        assert_eq!(Ubig::<1>::from(16777217_usize).to_f32(), Some(16777217_f32));
1060        assert_eq!(Ubig::<1>::from(16777218_usize).to_f32(), Some(16777218_f32));
1061        assert_eq!(Ubig::<1>::from(16777219_usize).to_f32(), Some(16777219_f32));
1062
1063        assert_eq!(Ubig::<1>::from(123_456_789_usize).to_f32(), Some(123456790_f32));
1064
1065        for i in 0..100 {
1066            let x = 2_usize.pow(25) + i;
1067            assert_eq!(Ubig::<1>::from(x).to_f32(), Some(x as f32));
1068        }
1069
1070        assert_eq!(Ubig::<1>::from(9_007_199_254_740_992_usize).to_f32(), Some(9007199000000000_f32));
1071        assert_eq!(Ubig::<1>::from(9_007_199_254_740_993_usize).to_f32(), Some(9007199000000000_f32));
1072        assert_eq!(Ubig::<1>::from(9_007_199_254_740_994_usize).to_f32(), Some(9007199000000000_f32));
1073
1074        assert_eq!(Ubig::<1>::from(9_007_199_254_740_992_usize).to_f64(), Some(9_007_199_254_740_992_f64));
1075        assert_eq!(Ubig::<1>::from(9_007_199_254_740_993_usize).to_f64(), Some(9_007_199_254_740_992_f64));
1076        assert_eq!(Ubig::<1>::from(9_007_199_254_740_994_usize).to_f64(), Some(9_007_199_254_740_994_f64));
1077
1078        for i in 0..100 {
1079            let x = 2_usize.pow(54) + i;
1080            assert_eq!(Ubig::<1>::from(x).to_f64(), Some(x as f64));
1081        }
1082    }
1083}