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 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 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 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 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 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 };
382}
383
384crate::macro_impl!(numtraits);