1use std::any::TypeId;
2use std::ops::{AddAssign, Div, MulAssign, Neg, Rem, Shr, SubAssign};
3use std::marker::PhantomData;
4use std::fmt::{Debug, Display};
5
6use feanor_serde::newtype_struct::{DeserializeSeedNewtypeStruct, SerializableNewtypeStruct};
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8use serde::de::{DeserializeOwned, DeserializeSeed};
9
10use crate::{impl_interpolation_base_ring_char_zero, impl_poly_gcd_locally_for_ZZ, impl_eval_poly_locally_for_ZZ};
11use crate::ring::*;
12use crate::algorithms;
13use crate::homomorphism::*;
14use crate::pid::{EuclideanRing, PrincipalIdealRing};
15use crate::divisibility::*;
16use crate::ordered::*;
17use crate::integer::*;
18use crate::algorithms::convolution::KaratsubaHint;
19use crate::algorithms::matmul::StrassenHint;
20use crate::specialization::*;
21use crate::serialization::SerializableElementRing;
22
23pub trait PrimitiveInt: 'static + Send + Sync + Serialize + DeserializeOwned + AddAssign + SubAssign + MulAssign + Neg<Output = Self> + Shr<usize, Output = Self> + Eq + Into<Self::Larger> + TryFrom<Self::Larger> + From<i8> + TryFrom<i32> + TryFrom<i128> + Into<i128> + Copy + Div<Self, Output = Self> + Rem<Self, Output = Self> + Display {
27
28 type Larger: PrimitiveInt;
33
34 fn bits() -> usize;
38
39 fn overflowing_mul(self, rhs: Self) -> Self;
43
44 fn overflowing_sub(self, rhs: Self) -> Self;
48}
49
50impl PrimitiveInt for i8 {
51
52 type Larger = i16;
53
54 fn bits() -> usize { Self::BITS as usize }
55 fn overflowing_mul(self, rhs: Self) -> Self { i8::overflowing_mul(self, rhs).0 }
56 fn overflowing_sub(self, rhs: Self) -> Self { i8::overflowing_sub(self, rhs).0 }
57}
58
59impl PrimitiveInt for i16 {
60
61 type Larger = i32;
62
63 fn bits() -> usize { Self::BITS as usize }
64 fn overflowing_mul(self, rhs: Self) -> Self { i16::overflowing_mul(self, rhs).0 }
65 fn overflowing_sub(self, rhs: Self) -> Self { i16::overflowing_sub(self, rhs).0 }
66}
67
68impl PrimitiveInt for i32 {
69
70 type Larger = i64;
71
72 fn bits() -> usize { Self::BITS as usize }
73 fn overflowing_mul(self, rhs: Self) -> Self { i32::overflowing_mul(self, rhs).0 }
74 fn overflowing_sub(self, rhs: Self) -> Self { i32::overflowing_sub(self, rhs).0 }
75}
76
77impl PrimitiveInt for i64 {
78
79 type Larger = i128;
80
81 fn bits() -> usize { Self::BITS as usize }
82 fn overflowing_mul(self, rhs: Self) -> Self { i64::overflowing_mul(self, rhs).0 }
83 fn overflowing_sub(self, rhs: Self) -> Self { i64::overflowing_sub(self, rhs).0 }
84}
85
86impl PrimitiveInt for i128 {
87
88 type Larger = i128;
89
90 fn bits() -> usize { Self::BITS as usize }
91 fn overflowing_mul(self, rhs: Self) -> Self { i128::overflowing_mul(self, rhs).0 }
92 fn overflowing_sub(self, rhs: Self) -> Self { i128::overflowing_sub(self, rhs).0 }
93}
94
95macro_rules! specialize_int_cast {
96 ($(($int_from:ty, $int_to:ty)),*) => {
97 $(
98 impl IntCast<StaticRingBase<$int_from>> for StaticRingBase<$int_to> {
99
100 fn cast(&self, _: &StaticRingBase<$int_from>, value: $int_from) -> Self::Element {
101 <$int_to>::try_from(<_ as Into<i128>>::into(value)).map_err(|_| ()).unwrap()
102 }
103 }
104 )*
105 };
106}
107
108specialize_int_cast!{
109 (i8, i8), (i8, i16), (i8, i32), (i8, i64), (i8, i128),
110 (i16, i8), (i16, i16), (i16, i32), (i16, i64), (i16, i128),
111 (i32, i8), (i32, i16), (i32, i32), (i32, i64), (i32, i128),
112 (i64, i8), (i64, i16), (i64, i32), (i64, i64), (i64, i128),
113 (i128, i8), (i128, i16), (i128, i32), (i128, i64), (i128, i128)
114}
115
116impl<T: PrimitiveInt> DivisibilityRing for StaticRingBase<T> {
117
118 type PreparedDivisorData = PrimitiveIntPreparedDivisorData<T>;
119
120 fn checked_left_div(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
121 if self.is_zero(lhs) && self.is_zero(rhs) {
122 return Some(self.zero());
123 } else if self.is_zero(rhs) {
124 return None;
125 }
126 let (div, rem) = self.euclidean_div_rem(*lhs, rhs);
127 if self.is_zero(&rem) {
128 return Some(div);
129 } else {
130 return None;
131 }
132 }
133
134 fn balance_factor<'a, I>(&self, elements: I) -> Option<Self::Element>
135 where I: Iterator<Item = &'a Self::Element>,
136 Self: 'a
137 {
138 Some(elements.fold(self.zero(), |a, b| self.ideal_gen(&a, b)))
139 }
140
141 fn prepare_divisor(&self, x: &Self::Element) -> Self::PreparedDivisorData {
142 if TypeId::of::<T>() == TypeId::of::<i128>() {
145 return PrimitiveIntPreparedDivisorData(T::from(0));
146 }
147 return match <T as Into<i128>>::into(*x) {
148 0 => PrimitiveIntPreparedDivisorData(T::from(0)),
149 1 => PrimitiveIntPreparedDivisorData(T::try_from((1i128 << (T::bits() - 1)) - 1).ok().unwrap()),
150 -1 => PrimitiveIntPreparedDivisorData(T::try_from((-1i128 << (T::bits() - 1)) + 1).ok().unwrap()),
151 val => PrimitiveIntPreparedDivisorData(<T as TryFrom<i128>>::try_from((1i128 << (T::bits() - 1)) / val).ok().unwrap())
152 };
153 }
154
155 fn checked_left_div_prepared(&self, lhs: &Self::Element, rhs: &Self::Element, rhs_prep: &Self::PreparedDivisorData) -> Option<Self::Element> {
156 if TypeId::of::<T>() == TypeId::of::<i128>() {
159 return self.checked_left_div(lhs, &rhs);
160 }
161 if *rhs == T::from(0) {
162 if *lhs == T::from(0) { Some(T::from(0)) } else { None }
163 } else {
164 let mut prod = <T as Into<T::Larger>>::into(*lhs);
165 prod *= <T as Into<T::Larger>>::into(rhs_prep.0);
166 let mut result = <T as TryFrom<T::Larger>>::try_from(prod >> (T::bits() - 1)).ok().unwrap();
167 let remainder = T::overflowing_sub(*lhs, T::overflowing_mul(result, *rhs));
168 if remainder == T::from(0) {
169 Some(result)
170 } else if remainder == *rhs {
171 result += T::from(1);
172 Some(result)
173 } else if -remainder == *rhs {
174 result -= T::from(1);
175 Some(result)
176 } else {
177 None
178 }
179 }
180 }
181}
182
183#[derive(Clone, Copy, Debug)]
189pub struct PrimitiveIntPreparedDivisorData<T: PrimitiveInt>(T);
190
191impl<T: PrimitiveInt> Domain for StaticRingBase<T> {}
192
193impl<T: PrimitiveInt> PrincipalIdealRing for StaticRingBase<T> {
194
195 fn checked_div_min(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
196 if self.is_zero(lhs) && self.is_zero(rhs) {
197 return Some(self.one());
198 }
199 self.checked_left_div(lhs, rhs)
200 }
201
202 fn extended_ideal_gen(&self, lhs: &Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element, Self::Element) {
203 algorithms::eea::eea(*lhs, *rhs, StaticRing::<T>::RING)
204 }
205}
206
207impl<T: PrimitiveInt> EuclideanRing for StaticRingBase<T> {
208
209 fn euclidean_div_rem(&self, lhs: Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element) {
210 (lhs / *rhs, lhs % *rhs)
211 }
212
213 fn euclidean_deg(&self, val: &Self::Element) -> Option<usize> {
214 RingRef::new(self).can_iso::<StaticRing<i128>>(&StaticRing::<i128>::RING).unwrap().map(*val).checked_abs().and_then(|x| usize::try_from(x).ok())
215 }
216}
217
218impl<T: PrimitiveInt> OrderedRing for StaticRingBase<T> {
219
220 fn cmp(&self, lhs: &Self::Element, rhs: &Self::Element) -> std::cmp::Ordering {
221 RingRef::new(self).can_iso::<StaticRing<i128>>(&StaticRing::<i128>::RING).unwrap().map(*lhs).cmp(
222 &RingRef::new(self).can_iso::<StaticRing<i128>>(&StaticRing::<i128>::RING).unwrap().map(*rhs)
223 )
224 }
225}
226
227impl_interpolation_base_ring_char_zero!{ <{T}> InterpolationBaseRing for StaticRingBase<T> where T: PrimitiveInt }
228
229impl_poly_gcd_locally_for_ZZ!{ <{T}> IntegerPolyGCDRing for StaticRingBase<T> where T: PrimitiveInt }
230
231impl_eval_poly_locally_for_ZZ!{ <{T}> EvalPolyLocallyRing for StaticRingBase<T> where T: PrimitiveInt }
232
233impl<T> FiniteRingSpecializable for StaticRingBase<T>
234 where T: PrimitiveInt
235{
236 fn specialize<O: FiniteRingOperation<Self>>(op: O) -> O::Output {
237 op.fallback()
238 }
239}
240
241impl<T: PrimitiveInt> IntegerRing for StaticRingBase<T> {
242
243 fn to_float_approx(&self, value: &Self::Element) -> f64 {
244 RingRef::new(self).can_iso::<StaticRing<i128>>(&StaticRing::<i128>::RING).unwrap().map(*value) as f64
245 }
246
247 fn from_float_approx(&self, value: f64) -> Option<Self::Element> {
248 Some(RingRef::new(self).coerce::<StaticRing<i128>>(&StaticRing::<i128>::RING, value as i128))
249 }
250
251 fn abs_is_bit_set(&self, value: &Self::Element, i: usize) -> bool {
252 match RingRef::new(self).can_iso::<StaticRing<i128>>(&StaticRing::<i128>::RING).unwrap().map(*value) {
253 i128::MIN => i == i128::BITS as usize - 1,
254 x => (x.abs() >> i) & 1 == 1
255 }
256 }
257
258 fn abs_highest_set_bit(&self, value: &Self::Element) -> Option<usize> {
259 match RingRef::new(self).can_iso::<StaticRing<i128>>(&StaticRing::<i128>::RING).unwrap().map(*value) {
260 0 => None,
261 i128::MIN => Some(i128::BITS as usize - 1),
262 x => Some(i128::BITS as usize - x.abs().leading_zeros() as usize - 1)
263 }
264 }
265
266 fn abs_lowest_set_bit(&self, value: &Self::Element) -> Option<usize> {
267 match RingRef::new(self).can_iso::<StaticRing<i128>>(&StaticRing::<i128>::RING).unwrap().map(*value) {
268 0 => None,
269 i128::MIN => Some(i128::BITS as usize - 1),
270 x => Some(x.abs().trailing_zeros() as usize)
271 }
272 }
273
274 fn euclidean_div_pow_2(&self, value: &mut Self::Element, power: usize) {
275 *value = RingRef::new(self).coerce::<StaticRing<i128>>(&StaticRing::<i128>::RING,
276 RingRef::new(self).can_iso::<StaticRing<i128>>(&StaticRing::<i128>::RING).unwrap().map(*value) / (1 << power));
277 }
278
279 fn mul_pow_2(&self, value: &mut Self::Element, power: usize) {
280 *value = RingRef::new(self).coerce::<StaticRing<i128>>(&StaticRing::<i128>::RING,
281 RingRef::new(self).can_iso::<StaticRing<i128>>(&StaticRing::<i128>::RING).unwrap().map(*value) << power);
282 }
283
284 fn get_uniformly_random_bits<G: FnMut() -> u64>(&self, log2_bound_exclusive: usize, mut rng: G) -> Self::Element {
285 assert!(log2_bound_exclusive <= T::bits() - 1);
286 RingRef::new(self).coerce::<StaticRing<i128>>(
287 &StaticRing::<i128>::RING,
288 ((((rng() as u128) << u64::BITS) | (rng() as u128)) & ((1 << log2_bound_exclusive) - 1)) as i128
289 )
290 }
291
292 fn representable_bits(&self) -> Option<usize> {
293 Some(T::bits() - 1)
294 }
295}
296
297impl<T: PrimitiveInt> HashableElRing for StaticRingBase<T> {
298
299 fn hash<H: std::hash::Hasher>(&self, el: &Self::Element, h: &mut H) {
300 h.write_i128(RingRef::new(self).can_iso::<StaticRing<i128>>(&StaticRing::<i128>::RING).unwrap().map(*el))
301 }
302}
303
304pub struct StaticRingBase<T> {
310 element: PhantomData<T>
311}
312
313impl<T> Debug for StaticRingBase<T> {
314 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
315 write!(f, "Z")
316 }
317}
318
319impl<T> PartialEq for StaticRingBase<T> {
320 fn eq(&self, _: &Self) -> bool {
321 true
322 }
323}
324
325impl<T: PrimitiveInt> RingValue<StaticRingBase<T>> {
326
327 pub const RING: StaticRing<T> = RingValue::from(StaticRingBase { element: PhantomData });
331}
332
333impl<T> Copy for StaticRingBase<T> {}
334
335impl<T> Clone for StaticRingBase<T> {
336
337 fn clone(&self) -> Self {
338 *self
339 }
340}
341
342impl<T: PrimitiveInt> RingBase for StaticRingBase<T> {
343
344 type Element = T;
345
346 fn clone_el(&self, val: &Self::Element) -> Self::Element {
347 *val
348 }
349
350 fn add_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
351 *lhs += rhs;
352 }
353
354 fn negate_inplace(&self, lhs: &mut Self::Element) {
355 *lhs = -*lhs;
356 }
357
358 fn mul_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
359 *lhs *= rhs;
360 }
361
362 fn from_int(&self, value: i32) -> Self::Element { T::try_from(value).map_err(|_| ()).unwrap() }
363
364 fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool {
365 *lhs == *rhs
366 }
367
368 fn is_commutative(&self) -> bool { true }
369 fn is_noetherian(&self) -> bool { true }
370
371 fn dbg_within<'a>(&self, value: &Self::Element, out: &mut std::fmt::Formatter<'a>, _: EnvBindingStrength) -> std::fmt::Result {
372 write!(out, "{}", *value)
373 }
374
375 fn characteristic<I: RingStore>(&self, ZZ: I) -> Option<El<I>>
376 where I::Type: IntegerRing
377 {
378 Some(ZZ.zero())
379 }
380
381 fn pow_gen<R: RingStore>(&self, x: Self::Element, power: &El<R>, integers: R) -> Self::Element
382 where R::Type: IntegerRing
383 {
384 assert!(!integers.is_neg(power));
385 algorithms::sqr_mul::generic_abs_square_and_multiply(
386 x,
387 power,
388 &integers,
389 |mut a| {
390 self.square(&mut a);
391 a
392 },
393 |a, b| self.mul_ref_fst(a, b),
394 self.one()
395 )
396 }
397
398 fn is_approximate(&self) -> bool { false }
399}
400
401impl KaratsubaHint for StaticRingBase<i8> {
402 fn karatsuba_threshold(&self) -> usize { 4 }
403}
404
405impl KaratsubaHint for StaticRingBase<i16> {
406 fn karatsuba_threshold(&self) -> usize { 4 }
407}
408
409impl KaratsubaHint for StaticRingBase<i32> {
410 fn karatsuba_threshold(&self) -> usize { 4 }
411}
412
413impl KaratsubaHint for StaticRingBase<i64> {
414 fn karatsuba_threshold(&self) -> usize { 4 }
415}
416
417impl KaratsubaHint for StaticRingBase<i128> {
418 fn karatsuba_threshold(&self) -> usize { 3 }
419}
420
421impl StrassenHint for StaticRingBase<i8> {
422 fn strassen_threshold(&self) -> usize { 6 }
423}
424
425impl StrassenHint for StaticRingBase<i16> {
426 fn strassen_threshold(&self) -> usize { 6 }
427}
428
429impl StrassenHint for StaticRingBase<i32> {
430 fn strassen_threshold(&self) -> usize { 6 }
431}
432
433impl StrassenHint for StaticRingBase<i64> {
434 fn strassen_threshold(&self) -> usize { 6 }
435}
436
437impl StrassenHint for StaticRingBase<i128> {
438 fn strassen_threshold(&self) -> usize { 5 }
439}
440
441impl<T: PrimitiveInt> SerializableElementRing for StaticRingBase<T> {
442
443 fn deserialize<'de, D>(&self, deserializer: D) -> Result<Self::Element, D::Error>
444 where D: Deserializer<'de>
445 {
446 T::deserialize(deserializer)
447 }
448
449 fn serialize<S>(&self, el: &Self::Element, serializer: S) -> Result<S::Ok, S::Error>
450 where S: Serializer
451 {
452 T::serialize(el, serializer)
453 }
454}
455
456impl<T: PrimitiveInt> Serialize for StaticRingBase<T> {
457
458 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
459 where S: Serializer
460 {
461 SerializableNewtypeStruct::new("IntegerRing(primitive int)", ()).serialize(serializer)
462 }
463}
464
465impl<'de, T: PrimitiveInt> Deserialize<'de> for StaticRingBase<T> {
466
467 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
468 where D: Deserializer<'de>
469 {
470 DeserializeSeedNewtypeStruct::new("IntegerRing(primitive int)", PhantomData::<()>).deserialize(deserializer).map(|()| StaticRing::<T>::RING.into())
471 }
472}
473
474pub type StaticRing<T> = RingValue<StaticRingBase<T>>;
478
479impl<T: PrimitiveInt> Default for StaticRingBase<T> {
480 fn default() -> Self {
481 StaticRing::RING.into()
482 }
483}
484
485#[test]
486fn test_ixx_bit_op() {
487 let ring_i16 = StaticRing::<i16>::RING;
488 let ring_i128 = StaticRing::<i128>::RING;
489 assert_eq!(Some(2), ring_i16.abs_highest_set_bit(&0x5));
490 assert_eq!(Some(15), ring_i16.abs_highest_set_bit(&i16::MIN));
491 assert_eq!(Some(1), ring_i16.abs_highest_set_bit(&-2));
492 assert_eq!(Some(2), ring_i128.abs_highest_set_bit(&0x5));
493 assert_eq!(Some(127), ring_i128.abs_highest_set_bit(&i128::MIN));
494 assert_eq!(Some(126), ring_i128.abs_highest_set_bit(&(i128::MIN + 1)));
495 assert_eq!(Some(126), ring_i128.abs_highest_set_bit(&(-1 - i128::MIN)));
496 assert_eq!(Some(1), ring_i128.abs_highest_set_bit(&-2));
497 assert_eq!(true, ring_i128.abs_is_bit_set(&-12, 2));
498 assert_eq!(false, ring_i128.abs_is_bit_set(&-12, 1));
499 assert_eq!(true, ring_i128.abs_is_bit_set(&i128::MIN, 127));
500 assert_eq!(false, ring_i128.abs_is_bit_set(&i128::MIN, 126));
501}
502
503#[test]
504fn test_get_uniformly_random() {
505 crate::integer::generic_tests::test_integer_get_uniformly_random(StaticRing::<i8>::RING);
506 crate::integer::generic_tests::test_integer_get_uniformly_random(StaticRing::<i16>::RING);
507 crate::integer::generic_tests::test_integer_get_uniformly_random(StaticRing::<i32>::RING);
508 crate::integer::generic_tests::test_integer_get_uniformly_random(StaticRing::<i64>::RING);
509 crate::integer::generic_tests::test_integer_get_uniformly_random(StaticRing::<i128>::RING);
510}
511
512#[test]
513fn test_integer_axioms() {
514 crate::integer::generic_tests::test_integer_axioms(StaticRing::<i8>::RING, [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8].into_iter());
515 crate::integer::generic_tests::test_integer_axioms(StaticRing::<i16>::RING, [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8].into_iter());
516 crate::integer::generic_tests::test_integer_axioms(StaticRing::<i32>::RING, [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8].into_iter());
517 crate::integer::generic_tests::test_integer_axioms(StaticRing::<i64>::RING, [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8].into_iter());
518 crate::integer::generic_tests::test_integer_axioms(StaticRing::<i128>::RING, [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8].into_iter());
519}
520
521#[test]
522fn test_euclidean_ring_axioms() {
523 crate::pid::generic_tests::test_euclidean_ring_axioms(StaticRing::<i8>::RING, [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8].into_iter());
524 crate::pid::generic_tests::test_euclidean_ring_axioms(StaticRing::<i16>::RING, [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8].into_iter());
525 crate::pid::generic_tests::test_euclidean_ring_axioms(StaticRing::<i32>::RING, [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8].into_iter());
526 crate::pid::generic_tests::test_euclidean_ring_axioms(StaticRing::<i64>::RING, [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8].into_iter());
527 crate::pid::generic_tests::test_euclidean_ring_axioms(StaticRing::<i128>::RING, [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8].into_iter());
528}
529
530#[test]
531fn test_principal_ideal_ring_ring_axioms() {
532 crate::pid::generic_tests::test_principal_ideal_ring_axioms(StaticRing::<i8>::RING, [-2, -1, 0, 1, 2].into_iter());
533 crate::pid::generic_tests::test_principal_ideal_ring_axioms(StaticRing::<i16>::RING, [-2, -1, 0, 1, 2, 3, 4].into_iter());
534 crate::pid::generic_tests::test_principal_ideal_ring_axioms(StaticRing::<i32>::RING, [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8].into_iter());
535 crate::pid::generic_tests::test_principal_ideal_ring_axioms(StaticRing::<i64>::RING, [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8].into_iter());
536 crate::pid::generic_tests::test_principal_ideal_ring_axioms(StaticRing::<i128>::RING, [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8].into_iter());
537
538}
539
540#[test]
541fn test_lowest_set_bit() {
542 assert_eq!(None, StaticRing::<i32>::RING.abs_lowest_set_bit(&0));
543 assert_eq!(Some(0), StaticRing::<i32>::RING.abs_lowest_set_bit(&3));
544 assert_eq!(Some(0), StaticRing::<i32>::RING.abs_lowest_set_bit(&-3));
545 assert_eq!(None, StaticRing::<i128>::RING.abs_lowest_set_bit(&0));
546 assert_eq!(Some(127), StaticRing::<i128>::RING.abs_lowest_set_bit(&i128::MIN));
547 assert_eq!(Some(0), StaticRing::<i128>::RING.abs_lowest_set_bit(&i128::MAX));
548}
549
550#[test]
551fn test_prepared_div() {
552 type PrimInt = i8;
553 for x in PrimInt::MIN..PrimInt::MAX {
554 let div_x = PreparedDivisor::new(StaticRing::<PrimInt>::RING.get_ring(), x);
555 for y in PrimInt::MIN..PrimInt::MAX {
556 if x == 0 {
557 if y == 0 {
558 assert!(div_x.checked_left_div_by(&y, StaticRing::<PrimInt>::RING.get_ring()).is_some());
559 } else {
560 assert!(div_x.checked_left_div_by(&y, StaticRing::<PrimInt>::RING.get_ring()).is_none());
561 }
562 } else if y == PrimInt::MIN && x == -1 {
563 } else if y % x == 0 {
565 assert_eq!(y / x, div_x.checked_left_div_by(&y, StaticRing::<PrimInt>::RING.get_ring()).unwrap());
566 } else {
567 assert!(div_x.checked_left_div_by(&y, StaticRing::<PrimInt>::RING.get_ring()).is_none());
568 }
569 }
570 }
571}
572
573#[test]
574fn test_serialization() {
575 crate::serialization::generic_tests::test_serialize_deserialize(StaticRing::<i8>::RING.into());
576 crate::serialization::generic_tests::test_serialize_deserialize(StaticRing::<i16>::RING.into());
577 crate::serialization::generic_tests::test_serialize_deserialize(StaticRing::<i32>::RING.into());
578 crate::serialization::generic_tests::test_serialize_deserialize(StaticRing::<i64>::RING.into());
579 crate::serialization::generic_tests::test_serialize_deserialize(StaticRing::<i128>::RING.into());
580}