reweb3_num/bint/
numtraits.rs

1macro_rules! from_int {
2    ($BUint: ident, $Digit: ident; $int: ty, $name: ident) => {
3        #[inline]
4        fn $name(n: $int) -> Option<Self> {
5            const INT_BITS: usize = <$int>::BITS as usize;
6            let initial_digit = if n.is_negative() {
7                $Digit::MAX
8            } else {
9                $Digit::MIN
10            };
11            let mut out = Self::from_bits($BUint::from_digits([initial_digit; N]));
12            let mut i = 0;
13            while i << crate::digit::$Digit::BIT_SHIFT < INT_BITS {
14                let d = (n >> (i << crate::digit::$Digit::BIT_SHIFT)) as $Digit;
15                if d != initial_digit {
16                    if i < N {
17                        out.bits.digits[i] = d;
18                    } else {
19                        return None;
20                    }
21                }
22                i += 1;
23            }
24            if n.is_negative() != out.is_negative() {
25                return None;
26            }
27            Some(out)
28        }
29    };
30}
31
32macro_rules! from_uint {
33    ($Digit: ident; $uint: ty, $name: ident) => {
34        #[inline]
35        fn $name(n: $uint) -> Option<Self> {
36            const UINT_BITS: usize = <$uint>::BITS as usize;
37            let mut out = Self::ZERO;
38            let mut i = 0;
39            while i << crate::digit::$Digit::BIT_SHIFT < UINT_BITS {
40                let d = (n >> (i << crate::digit::$Digit::BIT_SHIFT)) as $Digit;
41                if d != 0 {
42                    if i < N {
43                        out.bits.digits[i] = d;
44                    } else {
45                        return None;
46                    }
47                }
48                i += 1;
49            }
50            if Signed::is_negative(&out) {
51                None
52            } else {
53                Some(out)
54            }
55        }
56    };
57}
58
59macro_rules! from_float {
60    ($BUint: ident; $method: ident, $float: ty) => {
61        #[inline]
62        fn $method(f: $float) -> Option<Self> {
63            if f.is_sign_negative() {
64                let i = Self::from_bits($BUint::$method(-f)?);
65                if i == Self::MIN {
66                    Some(Self::MIN)
67                } else if i.is_negative() {
68                    None
69                } else {
70                    Some(-i)
71                }
72            } else {
73                let i = Self::from_bits($BUint::$method(f)?);
74                if i.is_negative() {
75                    None
76                } else {
77                    Some(i)
78                }
79            }
80        }
81    };
82}
83
84macro_rules! to_uint {
85    { $($name: ident -> $uint: ty), * } => {
86        $(
87            #[inline]
88            fn $name(&self) -> Option<$uint> {
89                if self.is_negative() {
90                    None
91                } else {
92                    self.bits.$name()
93                }
94            }
95        )*
96    };
97}
98
99macro_rules! to_int {
100    { $Digit: ident; $($name: ident -> $int: ty), * }  => {
101        $(
102            fn $name(&self) -> Option<$int> {
103                let neg = self.is_negative();
104                let (mut out, padding) = if neg {
105                    (-1, $Digit::MAX)
106                } else {
107                    (0, $Digit::MIN)
108                };
109                let mut i = 0;
110                if $Digit::BITS > <$int>::BITS {
111                    let small = self.bits.digits[i] as $int;
112                    let trunc = small as $Digit;
113                    if self.bits.digits[i] != trunc {
114                        return None;
115                    }
116                    out = small;
117                    i = 1;
118                } else {
119                    if neg {
120                        loop {
121                            let shift = i << digit::$Digit::BIT_SHIFT;
122                            if i >= N || shift >= <$int>::BITS as usize {
123                                break;
124                            }
125                            out &= !((!self.bits.digits[i]) as $int << shift);
126                            i += 1;
127                        }
128                    } else {
129                        loop {
130                            let shift = i << digit::$Digit::BIT_SHIFT;
131                            if i >= N || shift >= <$int>::BITS as usize {
132                                break;
133                            }
134                            out |= self.bits.digits[i] as $int << shift;
135                            i += 1;
136                        }
137                    }
138                }
139
140                while i < N {
141                    if self.bits.digits[i] != padding {
142                        return None;
143                    }
144                    i += 1;
145                }
146
147                if out.is_negative() != neg {
148                    return None;
149                }
150
151                Some(out)
152            }
153        )*
154    };
155}
156
157use crate::digit;
158use crate::errors;
159use crate::ExpType;
160use num_integer::{Integer, Roots};
161use num_traits::{
162    AsPrimitive, Bounded, CheckedAdd, CheckedDiv, CheckedEuclid, CheckedMul, CheckedNeg,
163    CheckedRem, CheckedShl, CheckedShr, CheckedSub, Euclid, FromPrimitive, MulAdd, MulAddAssign,
164    Num, One, Pow, PrimInt, Saturating, SaturatingAdd, SaturatingMul, SaturatingSub, Signed,
165    ToPrimitive, WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub,
166    Zero,
167};
168
169use crate::cast::CastFrom;
170use crate::int::numtraits::num_trait_impl;
171
172macro_rules! numtraits {
173    ($BUint: ident, $BInt: ident, $Digit: ident) => {
174        crate::int::numtraits::impls!($BInt, $BUint, $BInt);
175
176        impl<const N: usize> FromPrimitive for $BInt<N> {
177            from_uint!($Digit; u8, from_u8);
178            from_uint!($Digit; u16, from_u16);
179            from_uint!($Digit; u32, from_u32);
180            from_uint!($Digit; u64, from_u64);
181            from_uint!($Digit; u128, from_u128);
182            from_uint!($Digit; usize, from_usize);
183            from_int!($BUint, $Digit; i8, from_i8);
184            from_int!($BUint, $Digit; i16, from_i16);
185            from_int!($BUint, $Digit; i32, from_i32);
186            from_int!($BUint, $Digit; i64, from_i64);
187            from_int!($BUint, $Digit; i128, from_i128);
188            from_int!($BUint, $Digit; isize, from_isize);
189
190            from_float!($BUint; from_f32, f32);
191            from_float!($BUint; from_f64, f64);
192        }
193
194        //crate::nightly::impl_const! {
195            impl<const N: usize> Integer for $BInt<N> {
196                #[inline]
197                fn div_floor(&self, other: &Self) -> Self {
198                    *self / *other
199                }
200
201                #[inline]
202                fn mod_floor(&self, other: &Self) -> Self {
203                    *self % *other
204                }
205
206                #[inline]
207                fn gcd(&self, other: &Self) -> Self {
208                    let gcd = self.unsigned_abs().gcd(&other.unsigned_abs());
209                    let out = Self::from_bits(gcd);
210                    out.abs()
211                }
212
213                #[inline]
214                fn lcm(&self, other: &Self) -> Self {
215                    if self.is_zero() || other.is_zero() {
216                        Self::ZERO
217                    } else {
218                        self.div_floor(&self.gcd(other)) * *other
219                    }
220                }
221
222                #[inline]
223                fn divides(&self, other: &Self) -> bool {
224                    self.is_multiple_of(other)
225                }
226
227                #[inline]
228                fn is_multiple_of(&self, other: &Self) -> bool {
229                    self.mod_floor(other).is_zero()
230                }
231
232                #[inline]
233                fn is_even(&self) -> bool {
234                    self.bits.is_even()
235                }
236
237                #[inline]
238                fn is_odd(&self) -> bool {
239                    self.bits.is_odd()
240                }
241
242                #[inline]
243                fn div_rem(&self, other: &Self) -> (Self, Self) {
244                    (self.div_floor(other), self.mod_floor(other))
245                }
246            }
247        //}
248
249        //crate::nightly::impl_const! {
250            impl<const N: usize> PrimInt for $BInt<N> {
251                crate::int::numtraits::prim_int_methods!();
252
253                #[inline]
254                fn signed_shl(self, n: u32) -> Self {
255                    self << n
256                }
257
258                #[inline]
259                fn signed_shr(self, n: u32) -> Self {
260                    self >> n
261                }
262
263                #[inline]
264                fn unsigned_shl(self, n: u32) -> Self {
265                    self << n
266                }
267
268                #[inline]
269                fn unsigned_shr(self, n: u32) -> Self {
270                    Self::from_bits(self.to_bits() >> n)
271                }
272            }
273        //}
274
275        impl<const N: usize> Roots for $BInt<N> {
276            #[inline]
277            fn sqrt(&self) -> Self {
278                if self.is_negative() {
279                    panic!(crate::errors::err_msg!("imaginary square root"))
280                } else {
281                    Self::from_bits(self.bits.sqrt())
282                }
283            }
284
285            #[inline]
286            fn cbrt(&self) -> Self {
287                if self.is_negative() {
288                    let out = Self::from_bits(self.unsigned_abs().cbrt());
289                    -out
290                } else {
291                    Self::from_bits(self.bits.cbrt())
292                }
293            }
294
295            #[inline]
296            fn nth_root(&self, n: u32) -> Self {
297                if self.is_negative() {
298                    if n == 0 {
299                        panic!(crate::errors::err_msg!("attempt to calculate zeroth root"));
300                    }
301                    if n == 1 {
302                        return *self;
303                    }
304                    if n.is_even() {
305                        panic!("{} imaginary root degree of {}", errors::err_prefix!(), n)
306                    } else {
307                        let out = Self::from_bits(self.unsigned_abs().nth_root(n));
308                        out.wrapping_neg()
309                    }
310                } else {
311                    Self::from_bits(self.bits.nth_root(n))
312                }
313            }
314        }
315
316        //crate::nightly::impl_const! {
317        impl<const N: usize> ToPrimitive for $BInt<N> {
318            to_uint! {
319                to_u8 -> u8,
320                to_u16 -> u16,
321                to_u32 -> u32,
322                to_u64 -> u64,
323                to_u128 -> u128,
324                to_usize -> usize
325            }
326
327            to_int! {
328                $Digit;
329                to_i8 -> i8,
330                to_i16 -> i16,
331                to_i32 -> i32,
332                to_i64 -> i64,
333                to_i128 -> i128,
334                to_isize -> isize
335            }
336
337            #[inline]
338            fn to_f32(&self) -> Option<f32> {
339                Some(self.as_())
340            }
341
342            #[inline]
343            fn to_f64(&self) -> Option<f64> {
344                Some(self.as_())
345            }
346        }
347        //}
348
349        //crate::nightly::impl_const! {
350            impl<const N: usize> Signed for $BInt<N> {
351                #[inline]
352                fn abs(&self) -> Self {
353                    Self::abs(*self)
354                }
355
356                #[inline]
357                fn abs_sub(&self, other: &Self) -> Self {
358                    if *self <= *other {
359                        Self::ZERO
360                    } else {
361                        *self - *other
362                    }
363                }
364
365                #[inline]
366                fn signum(&self) -> Self {
367                    Self::signum(*self)
368                }
369
370                #[inline]
371                fn is_positive(&self) -> bool {
372                    Self::is_positive(*self)
373                }
374
375                #[inline]
376                fn is_negative(&self) -> bool {
377                    self.signed_digit().is_negative()
378                }
379            }
380        //}
381    };
382}
383
384crate::macro_impl!(numtraits);