reweb3_num/buint/
numtraits.rs

1macro_rules! to_int {
2    { $Digit: ident; $($name: ident -> $int: ty), * }  => {
3        $(
4            #[inline]
5            fn $name(&self) -> Option<$int> {
6                let mut out = 0;
7                let mut i = 0;
8                if $Digit::BITS > <$int>::BITS {
9                    let small = self.digits[i] as $int;
10                    let trunc = small as $Digit;
11                    if self.digits[i] != trunc {
12                        return None;
13                    }
14                    out = small;
15                    i = 1;
16                } else {
17                    loop {
18                        let shift = i << crate::digit::$Digit::BIT_SHIFT;
19                        if i >= N || shift >= <$int>::BITS as usize {
20                            break;
21                        }
22                        out |= self.digits[i] as $int << shift;
23                        i += 1;
24                    }
25                }
26
27                #[allow(unused_comparisons)]
28                if out < 0 {
29                    return None;
30                }
31
32                while i < N {
33                    if self.digits[i] != 0 {
34                        return None;
35                    }
36                    i += 1;
37                }
38
39                Some(out)
40            }
41        )*
42    };
43}
44
45pub const fn u32_bits(u: u32) -> ExpType {
46    32 - u.leading_zeros() as ExpType
47}
48
49pub const fn u64_bits(u: u64) -> ExpType {
50    64 - u.leading_zeros() as ExpType
51}
52use crate::buint::cast::{decode_f32, decode_f64};
53//use crate::nightly::impl_const;
54use crate::ExpType;
55use num_integer::{Integer, Roots};
56use num_traits::{
57    AsPrimitive, Bounded, CheckedAdd, CheckedDiv, CheckedEuclid, CheckedMul, CheckedNeg,
58    CheckedRem, CheckedShl, CheckedShr, CheckedSub, Euclid, FromPrimitive, MulAdd, MulAddAssign,
59    Num, One, Pow, PrimInt, Saturating, SaturatingAdd, SaturatingMul, SaturatingSub, ToPrimitive,
60    Unsigned, WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub, Zero,
61};
62
63use crate::cast::CastFrom;
64use crate::int::numtraits::num_trait_impl;
65
66macro_rules! numtraits {
67    ($BUint: ident, $BInt: ident, $Digit: ident) => {
68        crate::int::numtraits::impls!($BUint, $BUint, $BInt);
69
70        macro_rules! from_float {
71            ($method: ident, $float: ty, $decoder: ident, $mant_bits: ident) => {
72                #[inline]
73                fn $method(f: $float) -> Option<Self> {
74                    if !f.is_finite() {
75                        return None;
76                    }
77                    if f == 0.0 {
78                        return Some(Self::ZERO);
79                    }
80                    if f.is_sign_negative() {
81                        return None;
82                    }
83                    let (mut mant, exp) = $decoder(f);
84                    if exp.is_negative() {
85                        mant = mant.checked_shr((-exp) as ExpType).unwrap_or(0);
86                        if $mant_bits(mant) > Self::BITS {
87                            return None;
88                        }
89                        Some(Self::cast_from(mant))
90                    } else {
91                        if $mant_bits(mant) + exp as ExpType > Self::BITS {
92                            return None;
93                        }
94                        Some(Self::cast_from(mant) << exp)
95                    }
96                }
97            };
98        }
99
100        //impl_const! {
101        impl<const N: usize> FromPrimitive for $BUint<N> {
102            #[inline]
103            fn from_u64(int: u64) -> Option<Self> {
104                const UINT_BITS: usize = u64::BITS as usize;
105                let mut out = $BUint::ZERO;
106                let mut i = 0;
107                while i << crate::digit::$Digit::BIT_SHIFT < UINT_BITS {
108                    let d = (int >> (i << crate::digit::$Digit::BIT_SHIFT)) as $Digit;
109                    if d != 0 {
110                        if i < N {
111                            out.digits[i] = d;
112                        } else {
113                            return None;
114                        }
115                    }
116                    i += 1;
117                }
118                Some(out)
119            }
120
121            #[inline]
122            fn from_i64(int: i64) -> Option<Self> {
123                match u64::try_from(int) {
124                    Ok(int) => Self::from_u64(int),
125                    _ => None,
126                }
127            }
128
129            #[inline]
130            fn from_u128(int: u128) -> Option<Self> {
131                const UINT_BITS: usize = u128::BITS as usize;
132                let mut out = $BUint::ZERO;
133                let mut i = 0;
134                while i << crate::digit::$Digit::BIT_SHIFT < UINT_BITS {
135                    let d = (int >> (i << crate::digit::$Digit::BIT_SHIFT)) as $Digit;
136                    if d != 0 {
137                        if i < N {
138                            out.digits[i] = d;
139                        } else {
140                            return None;
141                        }
142                    }
143                    i += 1;
144                }
145                Some(out)
146            }
147
148            #[inline]
149            fn from_i128(n: i128) -> Option<Self> {
150                match u128::try_from(n) {
151                    Ok(n) => Self::from_u128(n),
152                    _ => None,
153                }
154            }
155
156            from_float!(from_f32, f32, decode_f32, u32_bits);
157            from_float!(from_f64, f64, decode_f64, u64_bits);
158        }
159        //}
160
161        //impl_const! {
162        impl<const N: usize> Integer for $BUint<N> {
163            #[inline]
164            fn div_floor(&self, other: &Self) -> Self {
165                *self / *other
166            }
167
168            #[inline]
169            fn mod_floor(&self, other: &Self) -> Self {
170                *self % *other
171            }
172
173            #[inline]
174            fn gcd(&self, other: &Self) -> Self {
175                // Paul E. Black, "binary GCD", in Dictionary of Algorithms and Data Structures [online], Paul E. Black, ed. 2 November 2020. (accessed 15th June 2022) Available from: https://www.nist.gov/dads/HTML/binaryGCD.html
176                // https://en.wikipedia.org/wiki/Binary_GCD_algorithm#Implementation
177
178                let (mut a, mut b) = (*self, *other);
179                if a.is_zero() {
180                    return b;
181                }
182                if b.is_zero() {
183                    return a;
184                }
185                let mut a_tz = a.trailing_zeros();
186                let mut b_tz = b.trailing_zeros();
187                // Normalise `a` and `b` so that both of them has no leading zeros, so both must be odd.
188                unsafe {
189                    a = Self::unchecked_shr_internal(a, a_tz);
190                    b = Self::unchecked_shr_internal(b, b_tz);
191                }
192
193                if b_tz > a_tz {
194                    // Ensure `a_tz >= b_tz`
195                    core::mem::swap(&mut a_tz, &mut b_tz);
196                }
197                loop {
198                    if a < b {
199                        // Ensure `a >= b`
200                        core::mem::swap(&mut a, &mut b);
201                    }
202                    a -= b;
203                    if a.is_zero() {
204                        return unsafe { Self::unchecked_shl_internal(b, b_tz) };
205                    }
206                    unsafe {
207                        a = Self::unchecked_shr_internal(a, a.trailing_zeros());
208                    }
209                }
210            }
211
212            #[inline]
213            fn lcm(&self, other: &Self) -> Self {
214                if self.is_zero() || other.is_zero() {
215                    Self::ZERO
216                } else {
217                    self.div_floor(&self.gcd(other)) * *other
218                }
219            }
220
221            #[inline]
222            fn divides(&self, other: &Self) -> bool {
223                self.is_multiple_of(other)
224            }
225
226            #[inline]
227            fn is_multiple_of(&self, other: &Self) -> bool {
228                self.mod_floor(other).is_zero()
229            }
230
231            #[inline]
232            fn is_even(&self) -> bool {
233                self.digits[0] & 1 == 0
234            }
235
236            #[inline]
237            fn is_odd(&self) -> bool {
238                self.digits[0] & 1 == 1
239            }
240
241            #[inline]
242            fn div_rem(&self, rhs: &Self) -> (Self, Self) {
243                Self::div_rem(*self, *rhs)
244            }
245        }
246        //}
247
248        //impl_const! {
249        impl<const N: usize> PrimInt for $BUint<N> {
250            crate::int::numtraits::prim_int_methods!();
251
252            #[inline]
253            fn signed_shl(self, n: u32) -> Self {
254                self << n
255            }
256
257            #[inline]
258            fn signed_shr(self, n: u32) -> Self {
259                ($BInt::from_bits(self) >> n).to_bits()
260            }
261
262            #[inline]
263            fn unsigned_shl(self, n: u32) -> Self {
264                self << n
265            }
266
267            #[inline]
268            fn unsigned_shr(self, n: u32) -> Self {
269                self >> n
270            }
271        }
272        //}
273
274        macro_rules! check_zero_or_one {
275            ($self: ident) => {
276                if N == 0 {
277                    return *$self;
278                }
279                if $self.last_digit_index() == 0 {
280                    let d = $self.digits[0];
281                    if d == 0 || d == 1 {
282                        return *$self;
283                    }
284                }
285            };
286        }
287
288        /*
289        The `fixpoint` function and the implementation of `Roots` below are adapted from the Rust `num_bigint` library, https://docs.rs/num-bigint/latest/num_bigint/, modified under the MIT license. The changes are released under either the MIT license or the Apache License 2.0, as described in the README. See LICENSE-MIT or LICENSE-APACHE at the project root.
290
291        The appropriate copyright notice for the `num_bigint` code is given below:
292        Copyright (c) 2014 The Rust Project Developers
293
294        The original license file and copyright notice for `num_bigint` can be found in this project's root at licenses/LICENSE-num-bigint.
295        */
296
297        impl<const N: usize> $BUint<N> {
298            #[inline]
299            fn fixpoint<F>(mut self, max_bits: ExpType, f: F) -> Self
300            where
301                F: Fn(Self) -> Self,
302            {
303                let mut xn = f(self);
304                while self < xn {
305                    self = if xn.bits() > max_bits {
306                        Self::power_of_two(max_bits)
307                    } else {
308                        xn
309                    };
310                    xn = f(self);
311                }
312                while self > xn {
313                    self = xn;
314                    xn = f(self);
315                }
316                self
317            }
318        }
319
320        impl<const N: usize> Roots for $BUint<N> {
321            #[inline]
322            fn sqrt(&self) -> Self {
323                check_zero_or_one!(self);
324
325                #[cfg(not(test))]
326                // disable this when testing as this condition will always be true when testing against primitives, so the rest of the algorithm wouldn't be tested
327                if let Some(n) = self.to_u128() {
328                    return n.sqrt().into();
329                }
330                let bits = self.bits();
331                let max_bits = bits / 2 + 1;
332
333                let guess = Self::power_of_two(max_bits);
334                guess.fixpoint(max_bits, |s| {
335                    let q = self / s;
336                    let t = s + q;
337                    t >> 1
338                })
339            }
340
341            #[inline]
342            fn cbrt(&self) -> Self {
343                check_zero_or_one!(self);
344
345                #[cfg(not(test))]
346                // disable this when testing as this condition will always be true when testing against primitives, so the rest of the algorithm wouldn't be tested
347                if let Some(n) = self.to_u128() {
348                    return n.cbrt().into();
349                }
350                let bits = self.bits();
351                let max_bits = bits / 3 + 1;
352
353                let guess = Self::power_of_two(max_bits);
354                guess.fixpoint(max_bits, |s| {
355                    let q = self / (s * s);
356                    let t: Self = (s << 1) + q;
357                    t.div_rem_digit(3).0
358                })
359            }
360
361            #[inline]
362            fn nth_root(&self, n: u32) -> Self {
363                match n {
364                    0 => panic!(crate::errors::err_msg!("attempt to calculate zeroth root")),
365                    1 => *self,
366                    2 => self.sqrt(),
367                    3 => self.cbrt(),
368                    _ => {
369                        check_zero_or_one!(self);
370
371                        #[cfg(not(test))]
372                        // disable this when testing as this condition will always be true when testing against primitives, so the rest of the algorithm wouldn't be tested
373                        if let Some(x) = self.to_u128() {
374                            return x.nth_root(n).into();
375                        }
376                        let bits = self.bits();
377                        let n = n as ExpType;
378                        if bits <= n {
379                            return Self::ONE;
380                        }
381
382                        let max_bits = bits / n + 1;
383
384                        let guess = Self::power_of_two(max_bits);
385                        let n_minus_1 = n - 1;
386
387                        guess.fixpoint(max_bits, |s| {
388                            let q = self / s.pow(n_minus_1);
389                            let mul: Self = n_minus_1.into();
390                            let t: Self = s * mul + q;
391                            t.div_rem_unchecked(n.into()).0
392                        })
393                    }
394                }
395            }
396        }
397
398        //impl_const! {
399        impl<const N: usize> ToPrimitive for $BUint<N> {
400            to_int! {
401                $Digit;
402                to_u8 -> u8,
403                to_u16 -> u16,
404                to_u32 -> u32,
405                to_u64 -> u64,
406                to_u128 -> u128,
407                to_usize -> usize,
408
409                to_i8 -> i8,
410                to_i16 -> i16,
411                to_i32 -> i32,
412                to_i64 -> i64,
413                to_i128 -> i128,
414                to_isize -> isize
415            }
416
417            #[inline]
418            fn to_f32(&self) -> Option<f32> {
419                Some(self.as_())
420            }
421
422            #[inline]
423            fn to_f64(&self) -> Option<f64> {
424                Some(self.as_())
425            }
426        }
427        //}
428
429        impl<const N: usize> Unsigned for $BUint<N> {}
430    };
431}
432
433crate::macro_impl!(numtraits);