1use libc;
2use serde::de::DeserializeSeed;
3use serde::ser::SerializeTuple;
4use serde::{Deserializer, Serializer, Serialize};
5
6use crate::impl_poly_gcd_locally_for_ZZ;
7use crate::algorithms;
8use crate::pid::*;
9use crate::ordered::*;
10use crate::primitive_int::*;
11use crate::divisibility::*;
12use crate::ring::*;
13use crate::homomorphism::*;
14use crate::integer::*;
15use crate::specialization::*;
16use crate::rings::rust_bigint::*;
17use crate::algorithms::bigint::deserialize_bigint_from_bytes;
18use crate::serialization::*;
19
20mod mpir_bindings;
21
22pub struct MPZEl {
26 integer: mpir_bindings::__mpz_struct
27}
28
29impl MPZEl {
30
31 fn new() -> Self {
32 unsafe {
33 let mut result = mpir_bindings::UNINIT_MPZ;
34 mpir_bindings::__gmpz_init(&mut result as mpir_bindings::mpz_ptr);
35 return MPZEl { integer: result };
36 }
37 }
38
39 pub fn assign(&mut self, rhs: &MPZEl) {
40 unsafe {
41 mpir_bindings::__gmpz_set(&mut self.integer as mpir_bindings::mpz_ptr, &rhs.integer as mpir_bindings::mpz_srcptr);
42 }
43 }
44}
45
46unsafe impl Send for MPZEl {}
51unsafe impl Sync for MPZEl {}
56
57impl Drop for MPZEl {
58
59 fn drop(&mut self) {
60 unsafe {
61 mpir_bindings::__gmpz_clear(&mut self.integer as mpir_bindings::mpz_ptr)
62 }
63 }
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq)]
71pub struct MPZBase;
72
73pub type MPZ = RingValue<MPZBase>;
77
78impl MPZ {
79
80 pub const RING: MPZ = RingValue::from(MPZBase);
81}
82
83impl MPZBase {
84
85 pub fn from_le_bytes(&self, dst: &mut MPZEl, input: &[u8]) {
90 unsafe {
91 assert_eq!(std::mem::size_of::<mpir_bindings::mpir_ui>(), std::mem::size_of::<u64>());
92 if input.len() == 0 {
93 mpir_bindings::__gmpz_set_ui(&mut dst.integer as mpir_bindings::mpz_ptr, 0);
94 return;
95 }
96 assert!(input.len() > 0);
97 mpir_bindings::__gmpz_import(
98 &mut dst.integer as mpir_bindings::mpz_ptr,
99 input.len(),
100 -1i32, 1 as libc::size_t,
102 -1, 0,
104 input.as_ptr() as *const libc::c_void
105 );
106 }
107 }
108
109 pub fn from_base_u64_repr(&self, dst: &mut MPZEl, input: &[u64]) {
114 unsafe {
115 assert_eq!(std::mem::size_of::<mpir_bindings::mpir_ui>(), std::mem::size_of::<u64>());
116 if input.len() == 0 {
117 mpir_bindings::__gmpz_set_ui(&mut dst.integer as mpir_bindings::mpz_ptr, 0);
118 return;
119 }
120 assert!(input.len() > 0);
121 mpir_bindings::__gmpz_import(
122 &mut dst.integer as mpir_bindings::mpz_ptr,
123 input.len(),
124 -1i32, (u64::BITS / 8) as libc::size_t,
126 0, 0,
128 input.as_ptr() as *const libc::c_void
129 );
130 }
131 }
132
133 pub fn abs_base_u64_repr_len(&self, src: &MPZEl) -> usize {
134 self.abs_highest_set_bit(src).map(|n| (n / u64::BITS as usize) + 1).unwrap_or(0)
135 }
136
137 pub fn abs_base_u64_repr(&self, src: &MPZEl, out: &mut [u64]) {
141 unsafe {
142 if self.abs_base_u64_repr_len(src) > 0 {
143 assert!(out.len() >= self.abs_base_u64_repr_len(src));
144 let mut size = 0;
145
146 let result_ptr = mpir_bindings::__gmpz_export(
147 out.as_mut_ptr() as *mut libc::c_void,
148 &mut size,
149 -1, (u64::BITS / 8) as libc::size_t,
151 0, 0,
153 &src.integer as mpir_bindings::mpz_srcptr
154 );
155 assert_eq!(result_ptr as *const libc::c_void, out.as_ptr() as *const libc::c_void);
156 for i in size..out.len() {
157 out[i] = 0;
158 }
159 } else {
160 for i in 0..out.len() {
161 out[i] = 0;
162 }
163 }
164 }
165 }
166
167 pub fn to_le_bytes_len(&self, src: &MPZEl) -> usize {
168 self.abs_highest_set_bit(src).map(|n| (n / u8::BITS as usize) + 1).unwrap_or(0)
169 }
170
171 pub fn to_le_bytes(&self, src: &MPZEl, out: &mut [u8]) {
175 unsafe {
176 if self.to_le_bytes_len(src) > 0 {
177 assert!(out.len() >= self.to_le_bytes_len(src));
178 let mut size = 0;
179
180 let result_ptr = mpir_bindings::__gmpz_export(
181 out.as_mut_ptr() as *mut libc::c_void,
182 &mut size,
183 -1, 1 as libc::size_t,
185 -1, 0,
187 &src.integer as mpir_bindings::mpz_srcptr
188 );
189 assert_eq!(result_ptr as *const libc::c_void, out.as_ptr() as *const libc::c_void);
190 for i in size..out.len() {
191 out[i] = 0;
192 }
193 } else {
194 for i in 0..out.len() {
195 out[i] = 0;
196 }
197 }
198 }
199 }
200}
201
202impl RingBase for MPZBase {
203
204 type Element = MPZEl;
205
206 fn clone_el(&self, val: &Self::Element) -> Self::Element {
207 unsafe {
208 let mut result = MPZEl::new();
209 mpir_bindings::__gmpz_set(&mut result.integer as mpir_bindings::mpz_ptr, &val.integer as mpir_bindings::mpz_srcptr);
210 return result;
211 }
212 }
213
214 fn mul_ref(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
215 unsafe {
216 let mut result = MPZEl::new();
217 mpir_bindings::__gmpz_mul(&mut result.integer as mpir_bindings::mpz_ptr, &lhs.integer as mpir_bindings::mpz_srcptr, &rhs.integer as mpir_bindings::mpz_srcptr);
218 return result;
219 }
220 }
221
222 fn negate_inplace(&self, lhs: &mut Self::Element) {
223 unsafe {
224 mpir_bindings::__gmpz_neg(&mut lhs.integer as mpir_bindings::mpz_ptr, &lhs.integer as mpir_bindings::mpz_srcptr)
225 }
226 }
227
228 fn zero(&self) -> Self::Element {
229 MPZEl::new()
230 }
231
232 fn one(&self) -> Self::Element {
233 self.from_int(1)
234 }
235
236 fn sub_ref_fst(&self, lhs: &Self::Element, mut rhs: Self::Element) -> Self::Element {
237 unsafe {
238 mpir_bindings::__gmpz_sub(&mut rhs.integer as mpir_bindings::mpz_ptr, &lhs.integer as mpir_bindings::mpz_srcptr, &rhs.integer as mpir_bindings::mpz_srcptr);
239 return rhs;
240 }
241 }
242
243 fn sub_ref_snd(&self, mut lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
244 unsafe {
245 mpir_bindings::__gmpz_sub(&mut lhs.integer as mpir_bindings::mpz_ptr, &lhs.integer as mpir_bindings::mpz_srcptr, &rhs.integer as mpir_bindings::mpz_srcptr);
246 return lhs;
247 }
248 }
249
250 fn add_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
251 self.add_assign_ref(lhs, &rhs);
252 }
253
254 fn add_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
255 unsafe {
256 mpir_bindings::__gmpz_add(&mut lhs.integer as mpir_bindings::mpz_ptr, &lhs.integer as mpir_bindings::mpz_srcptr, &rhs.integer as mpir_bindings::mpz_srcptr);
257 }
258 }
259
260 fn mul_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
261 self.mul_assign_ref(lhs, &rhs)
262 }
263
264 fn mul_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
265 unsafe {
266 mpir_bindings::__gmpz_mul(&mut lhs.integer as mpir_bindings::mpz_ptr, &lhs.integer as mpir_bindings::mpz_srcptr, &rhs.integer as mpir_bindings::mpz_srcptr);
267 }
268 }
269
270 fn mul_assign_int(&self, lhs: &mut Self::Element, rhs: i32) {
271 unsafe {
272 mpir_bindings::__gmpz_mul_ui(&mut lhs.integer as mpir_bindings::mpz_ptr, &lhs.integer as mpir_bindings::mpz_srcptr, rhs.abs() as u64);
273 if rhs < 0 {
274 mpir_bindings::__gmpz_neg(&mut lhs.integer as mpir_bindings::mpz_ptr, &lhs.integer as mpir_bindings::mpz_srcptr)
275 }
276 }
277 }
278
279 fn sub(&self, lhs: Self::Element, rhs: Self::Element) -> Self::Element {
280 self.sub_ref_snd(lhs, &rhs)
281 }
282
283 fn from_int(&self, value: i32) -> Self::Element {
284 unsafe {
285 let mut result = MPZEl::new();
286 mpir_bindings::__gmpz_set_ui(&mut result.integer as mpir_bindings::mpz_ptr, value.abs() as u64);
287 if value < 0 {
288 return self.negate(result);
289 } else {
290 return result;
291 }
292 }
293 }
294
295 fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool {
296 unsafe {
297 mpir_bindings::__gmpz_cmp(&lhs.integer as mpir_bindings::mpz_srcptr, &rhs.integer as mpir_bindings::mpz_srcptr) == 0
298 }
299 }
300
301 fn is_zero(&self, val: &Self::Element) -> bool {
302 unsafe {
303 mpir_bindings::__gmpz_cmp_si(&val.integer as mpir_bindings::mpz_srcptr, 0) == 0
304 }
305 }
306
307 fn is_one(&self, val: &Self::Element) -> bool {
308 unsafe {
309 mpir_bindings::__gmpz_cmp_si(&val.integer as mpir_bindings::mpz_srcptr, 1) == 0
310 }
311 }
312
313 fn is_neg_one(&self, val: &Self::Element) -> bool {
314 unsafe {
315 mpir_bindings::__gmpz_cmp_si(&val.integer as mpir_bindings::mpz_srcptr, -1) == 0
316 }
317 }
318
319 fn is_noetherian(&self) -> bool {
320 true
321 }
322
323 fn is_commutative(&self) -> bool {
324 true
325 }
326
327 fn is_approximate(&self) -> bool {
328 false
329 }
330
331 fn dbg_within<'a>(&self, value: &Self::Element, out: &mut std::fmt::Formatter<'a>, _env: EnvBindingStrength) -> std::fmt::Result {
332 RustBigintRing::RING.get_ring().dbg(&self.map_out(RustBigintRing::RING.get_ring(), self.clone_el(value), &()), out)
333 }
334
335 fn characteristic<I: IntegerRingStore + Copy>(&self, other_ZZ: I) -> Option<El<I>>
336 where I::Type: IntegerRing
337 {
338 Some(other_ZZ.zero())
339 }
340}
341
342impl OrderedRing for MPZBase {
343
344 fn cmp(&self, lhs: &Self::Element, rhs: &Self::Element) -> std::cmp::Ordering {
345 unsafe {
346 let res = mpir_bindings::__gmpz_cmp(
347 &lhs.integer as mpir_bindings::mpz_srcptr,
348 &rhs.integer as mpir_bindings::mpz_srcptr
349 );
350 if res < 0 {
351 return std::cmp::Ordering::Less;
352 } else if res > 0 {
353 return std::cmp::Ordering::Greater;
354 } else {
355 return std::cmp::Ordering::Equal;
356 }
357 }
358 }
359
360 fn is_neg(&self, value: &Self::Element) -> bool {
361 unsafe {
362 mpir_bindings::mpz_is_neg(&value.integer as mpir_bindings::mpz_srcptr)
363 }
364 }
365}
366
367impl SerializableElementRing for MPZBase {
368
369 fn deserialize<'de, D>(&self, deserializer: D) -> Result<Self::Element, D::Error>
370 where D: Deserializer<'de>
371 {
372 if deserializer.is_human_readable() {
373 return DeserializeWithRing::new(RustBigintRing::RING).deserialize(deserializer).map(|n| int_cast(n, RingRef::new(self), RustBigintRing::RING));
374 } else {
375 let (negative, mut result) = deserialize_bigint_from_bytes(deserializer, |data| {
376 let mut result = self.zero();
377 self.from_le_bytes(&mut result, data);
378 return result;
379 })?;
380 if negative {
381 self.negate_inplace(&mut result);
382 }
383 return Ok(result);
384 }
385 }
386
387 fn serialize<S>(&self, el: &Self::Element, serializer: S) -> Result<S::Ok, S::Error>
388 where S: Serializer
389 {
390 if serializer.is_human_readable() {
391 SerializableNewtype::new("BigInt", format!("{}", RingRef::new(self).format(el)).as_str()).serialize(serializer)
392 } else {
393 let len = self.to_le_bytes_len(el);
394 let mut data = Vec::with_capacity(len);
395 data.resize(len, 0u8);
396 self.to_le_bytes(el, &mut data);
397 let mut seq = serializer.serialize_tuple(2)?;
398 seq.serialize_element(&self.is_neg(el))?;
399 seq.serialize_element(serde_bytes::Bytes::new(&data[..]))?;
400 return seq.end();
401 }
402 }
403}
404
405impl DivisibilityRing for MPZBase {
406
407 fn checked_left_div(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
408 if self.is_zero(rhs) {
409 if self.is_zero(lhs) {
410 return Some(self.zero());
411 } else {
412 return None;
413 }
414 }
415 let (quo, rem) = self.euclidean_div_rem(self.clone_el(lhs), rhs);
416 if self.is_zero(&rem) {
417 return Some(quo);
418 } else {
419 return None;
420 }
421 }
422
423 fn balance_factor<'a, I>(&self, elements: I) -> Option<Self::Element>
424 where I: Iterator<Item = &'a Self::Element>,
425 Self: 'a
426 {
427 Some(elements.fold(self.zero(), |a, b| self.ideal_gen(&a, b)))
428 }
429}
430
431impl PrincipalIdealRing for MPZBase {
432
433 fn extended_ideal_gen(&self, lhs: &Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element, Self::Element) {
434 algorithms::eea::eea(self.clone_el(lhs), self.clone_el(rhs), MPZ::RING)
435 }
436
437 fn checked_div_min(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
438 if self.is_zero(lhs) && self.is_zero(rhs) {
439 return Some(self.one());
440 }
441 self.checked_left_div(lhs, rhs)
442 }
443}
444
445impl EuclideanRing for MPZBase {
446
447 fn euclidean_div_rem(&self, mut lhs: Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element) {
448 unsafe {
449 assert!(!self.is_zero(rhs));
450 let mut quo = MPZEl::new();
451 mpir_bindings::__gmpz_tdiv_qr(
452 &mut quo.integer as mpir_bindings::mpz_ptr,
453 &mut lhs.integer as mpir_bindings::mpz_ptr,
454 &lhs.integer as mpir_bindings::mpz_srcptr,
455 &rhs.integer as mpir_bindings::mpz_srcptr
456 );
457 return (quo, lhs);
458 }
459 }
460
461 fn euclidean_rem(&self, lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
462 unsafe {
463 assert!(!self.is_zero(rhs));
464 let mut rem = MPZEl::new();
465 mpir_bindings::__gmpz_tdiv_r(
466 &mut rem.integer as mpir_bindings::mpz_ptr,
467 &lhs.integer as mpir_bindings::mpz_srcptr,
468 &rhs.integer as mpir_bindings::mpz_srcptr
469 );
470 return rem;
471 }
472 }
473
474 fn euclidean_div(&self, lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
475 unsafe {
476 assert!(!self.is_zero(rhs));
477 let mut rem = MPZEl::new();
478 mpir_bindings::__gmpz_tdiv_q(
479 &mut rem.integer as mpir_bindings::mpz_ptr,
480 &lhs.integer as mpir_bindings::mpz_srcptr,
481 &rhs.integer as mpir_bindings::mpz_srcptr
482 );
483 return rem;
484 }
485 }
486
487 fn euclidean_deg(&self, val: &Self::Element) -> Option<usize> {
488 if self.abs_highest_set_bit(val).unwrap_or(0) < usize::BITS as usize {
489 unsafe {
490 mpir_bindings::__gmpz_get_ui(&val.integer as mpir_bindings::mpz_srcptr).try_into().ok()
491 }
492 } else {
493 None
494 }
495 }
496}
497
498impl Default for MPZBase {
499
500 fn default() -> Self {
501 MPZ::RING.into()
502 }
503}
504
505impl Domain for MPZBase {}
506
507impl IntegerRing for MPZBase {
508
509 fn to_float_approx(&self, el: &Self::Element) -> f64 {
510 unsafe {
511 mpir_bindings::__gmpz_get_d(&el.integer as mpir_bindings::mpz_srcptr)
512 }
513 }
514
515 fn from_float_approx(&self, el: f64) -> Option<Self::Element> {
516 unsafe {
517 let mut result = MPZEl::new();
518 mpir_bindings::__gmpz_set_d(&mut result.integer as mpir_bindings::mpz_ptr, el);
519 return Some(result);
520 }
521 }
522
523 fn mul_pow_2(&self, el: &mut Self::Element, power: usize) {
524 unsafe {
525 mpir_bindings::__gmpz_mul_2exp(&mut el.integer as mpir_bindings::mpz_ptr, &el.integer as mpir_bindings::mpz_srcptr, power as u64)
526 }
527 }
528
529 fn euclidean_div_pow_2(&self, el: &mut Self::Element, power: usize) {
530 unsafe {
531 mpir_bindings::__gmpz_tdiv_q_2exp(&mut el.integer as mpir_bindings::mpz_ptr, &el.integer as mpir_bindings::mpz_srcptr, power as u64)
532 }
533 }
534
535 fn abs_is_bit_set(&self, el: &Self::Element, bit: usize) -> bool {
536 unsafe {
537 if mpir_bindings::mpz_is_neg(&el.integer as mpir_bindings::mpz_srcptr) {
538 let value = mpir_bindings::__gmpz_tstbit(&el.integer as mpir_bindings::mpz_srcptr, bit as u64) == 1;
539 let least_significant_zero = mpir_bindings::__gmpz_scan1(&el.integer as mpir_bindings::mpz_srcptr, 0);
540 if bit <= least_significant_zero as usize {
541 value
542 } else {
543 !value
544 }
545 } else {
546 mpir_bindings::__gmpz_tstbit(&el.integer as mpir_bindings::mpz_srcptr, bit as u64) == 1
547 }
548 }
549 }
550
551 fn abs_highest_set_bit(&self, value: &Self::Element) -> Option<usize> {
552 unsafe {
553 if self.is_zero(value) {
554 return None;
555 }
556 Some(mpir_bindings::__gmpz_sizeinbase(&value.integer as mpir_bindings::mpz_srcptr, 2) - 1)
557 }
558 }
559
560 fn abs_lowest_set_bit(&self, value: &Self::Element) -> Option<usize> {
561 unsafe {
562 let result = mpir_bindings::__gmpz_scan1(&value.integer as mpir_bindings::mpz_srcptr, 0);
563 if result == mpir_bindings::mpir_ui::MAX {
564 return None;
565 } else {
566 return Some(result as usize);
567 }
568 }
569 }
570
571 fn rounded_div(&self, lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
572 let mut rhs_half = self.abs(self.clone_el(rhs));
573 self.euclidean_div_pow_2(&mut rhs_half, 1);
574 if self.is_neg(&lhs) {
575 return self.euclidean_div(self.sub(lhs, rhs_half), rhs);
576 } else {
577 return self.euclidean_div(self.add(lhs, rhs_half), rhs);
578 }
579 }
580
581 fn get_uniformly_random_bits<G: FnMut() -> u64>(&self, log2_bound_exclusive: usize, rng: G) -> Self::Element {
582 unsafe {
583 let mut result = MPZEl::new();
584 let len = (log2_bound_exclusive - 1) / u64::BITS as usize + 1;
585 let mut data = Vec::new();
586 data.resize_with(len, rng);
587
588 mpir_bindings::__gmpz_import(
589 &mut result.integer as mpir_bindings::mpz_ptr,
590 data.len(),
591 -1i32,
592 (u64::BITS / 8) as libc::size_t,
593 0,
594 0,
595 (data.as_ptr() as *const mpir_bindings::mpir_ui) as *const libc::c_void
596 );
597
598 self.euclidean_div_pow_2(&mut result, len * u64::BITS as usize - log2_bound_exclusive);
599 return result;
600 }
601 }
602
603 fn representable_bits(&self) -> Option<usize> {
604 None
605 }
606}
607
608impl_poly_gcd_locally_for_ZZ!{ IntegerPolyGCDRing for MPZBase }
609
610impl FiniteRingSpecializable for MPZBase {
611
612 fn specialize<O: FiniteRingOperation<Self>>(_op: O) -> Result<O::Output, ()> {
613 Err(())
614 }
615}
616
617impl HashableElRing for MPZBase {
618
619 fn hash<H: std::hash::Hasher>(&self, el: &Self::Element, h: &mut H) {
620 unsafe {
621 <_ as std::hash::Hash>::hash(&(self.is_neg(&el), self.abs_highest_set_bit(&el), mpir_bindings::__gmpz_get_ui(&el.integer as mpir_bindings::mpz_srcptr)), h)
622 }
623 }
624}
625
626impl IntCast<RustBigintRingBase> for MPZBase {
627
628 fn cast(&self, _: &RustBigintRingBase, el: RustBigint) -> Self::Element {
629 let mut result = MPZEl::new();
630 self.from_base_u64_repr(&mut result, &RustBigintRing::RING.get_ring().abs_base_u64_repr(&el).collect::<Vec<_>>()[..]);
631 if RustBigintRing::RING.is_neg(&el) {
632 self.negate_inplace(&mut result);
633 }
634 return result;
635 }
636}
637
638impl IntCast<MPZBase> for RustBigintRingBase {
639
640 fn cast(&self, from: &MPZBase, el: MPZEl) -> RustBigint {
641 let mut result = (0..from.abs_base_u64_repr_len(&el)).map(|_| 0u64).collect::<Vec<_>>();
642 from.abs_base_u64_repr(&el, &mut result[..]);
643 let result = RustBigintRing::RING.get_ring().from_base_u64_repr(result.into_iter());
644 if from.is_neg(&el) {
645 return RustBigintRing::RING.negate(result);
646 } else {
647 return result;
648 }
649 }
650}
651
652impl IntCast<MPZBase> for MPZBase {
653
654 fn cast(&self, _from: &MPZBase, el: MPZEl) -> MPZEl {
655 el
656 }
657}
658
659impl IntCast<StaticRingBase<i64>> for MPZBase {
660
661 fn cast(&self, _: &StaticRingBase<i64>, el: i64) -> Self::Element {
662 unsafe {
663 let mut result = MPZEl::new();
664 mpir_bindings::__gmpz_set_si(&mut result.integer as *mut _, el);
665 return result;
666 }
667 }
668}
669
670impl IntCast<MPZBase> for StaticRingBase<i64> {
671
672 fn cast(&self, from: &MPZBase, el: MPZEl) -> i64 {
673 assert!(from.abs_highest_set_bit(&el).unwrap_or(0) < u64::BITS as usize);
674 let negative = from.is_neg(&el);
675 unsafe {
676 let result = mpir_bindings::__gmpz_get_ui(&el.integer as mpir_bindings::mpz_srcptr);
677 if !negative {
678 result.try_into().unwrap()
679 } else if result == i64::MAX as u64 + 1 {
680 i64::MIN
681 } else {
682 -i64::try_from(result).unwrap()
683 }
684 }
685 }
686}
687
688impl IntCast<StaticRingBase<i128>> for MPZBase {
689
690 fn cast(&self, _: &StaticRingBase<i128>, el: i128) -> MPZEl {
691 let el_abs = el.unsigned_abs();
692 let data = [(el_abs & u64::MAX as u128) as u64, (el_abs >> u64::BITS) as u64];
693 let mut result = MPZEl::new();
694 self.from_base_u64_repr(&mut result, &data[..]);
695 if el < 0 {
696 self.negate_inplace(&mut result);
697 }
698 return result;
699 }
700}
701
702impl IntCast<MPZBase> for StaticRingBase<i128> {
703
704 fn cast(&self, from: &MPZBase, el: MPZEl) -> i128 {
705 assert!(from.abs_base_u64_repr_len(&el) <= 2);
706 let mut data = [0u64; 2];
707 from.abs_base_u64_repr(&el, &mut data);
708 let result = data[0] as u128 + ((data[1] as u128) << u64::BITS);
709 if from.is_neg(&el) {
710 if result == i128::MIN.unsigned_abs() {
711 return i128::MIN;
712 } else {
713 return -i128::try_from(result).unwrap();
714 }
715 } else {
716 return result.try_into().unwrap();
717 }
718 }
719}
720
721macro_rules! specialize_int_cast {
722 ($($from:ty),*) => {
723 $(
724 impl IntCast<StaticRingBase<$from>> for MPZBase {
725
726 fn cast(&self, _: &StaticRingBase<$from>, el: $from) -> MPZEl {
727 int_cast(el as i64, &RingRef::new(self), StaticRing::<i64>::RING)
728 }
729 }
730
731 impl IntCast<MPZBase> for StaticRingBase<$from> {
732
733 fn cast(&self, _: &MPZBase, el: MPZEl) -> $from {
734 int_cast(el, &StaticRing::<i64>::RING, &MPZ::RING) as $from
735 }
736 }
737 )*
738 }
739}
740
741specialize_int_cast!{ i8, i16, i32 }
742
743#[cfg(test)]
744use crate::pid::EuclideanRingStore;
745use crate::serialization::DeserializeWithRing;
746use crate::serialization::SerializableElementRing;
747
748#[cfg(test)]
749fn edge_case_elements_bigint() -> impl Iterator<Item = RustBigint> {
750 [
751 RustBigintRing::RING.int_hom().map(0),
752 RustBigintRing::RING.int_hom().map(1),
753 RustBigintRing::RING.int_hom().map(-1),
754 RustBigintRing::RING.int_hom().map(7),
755 RustBigintRing::RING.int_hom().map(-7),
756 RustBigintRing::RING.int_hom().map(i32::MAX),
757 RustBigintRing::RING.int_hom().map(i32::MIN),
758 RustBigintRing::RING.power_of_two(64),
759 RustBigintRing::RING.negate(RustBigintRing::RING.power_of_two(64)),
760 RustBigintRing::RING.sub(RustBigintRing::RING.power_of_two(64), RustBigintRing::RING.one()),
761 RustBigintRing::RING.power_of_two(128),
762 RustBigintRing::RING.negate(RustBigintRing::RING.power_of_two(128)),
763 RustBigintRing::RING.sub(RustBigintRing::RING.power_of_two(128), RustBigintRing::RING.one()),
764 RustBigintRing::RING.power_of_two(192),
765 RustBigintRing::RING.negate(RustBigintRing::RING.power_of_two(192)),
766 RustBigintRing::RING.sub(RustBigintRing::RING.power_of_two(192), RustBigintRing::RING.one())
767 ].into_iter()
768}
769
770#[cfg(test)]
771fn edge_case_elements() -> impl Iterator<Item = MPZEl> {
772 edge_case_elements_bigint().map(|n| MPZ::RING.coerce(&RustBigintRing::RING, n))
773}
774
775#[test]
776fn test_negate_inplace() {
777 let mut a = MPZ::RING.power_of_two(64);
778 MPZ::RING.negate_inplace(&mut a);
779 assert!(MPZ::RING.is_neg(&a));
780
781 for a in edge_case_elements() {
782 let mut b = MPZ::RING.clone_el(&a);
783 MPZ::RING.negate_inplace(&mut b);
784 assert!(MPZ::RING.is_zero(&a) || (MPZ::RING.is_neg(&a) ^ MPZ::RING.is_neg(&b)));
785 }
786}
787
788#[test]
789fn test_ring_axioms() {
790 crate::ring::generic_tests::test_ring_axioms(MPZ::RING, edge_case_elements())
791}
792
793#[test]
794fn test_hash_axioms() {
795 crate::ring::generic_tests::test_hash_axioms(MPZ::RING, edge_case_elements());
796}
797
798#[test]
799fn test_divisibility_ring_axioms() {
800 crate::divisibility::generic_tests::test_divisibility_axioms(MPZ::RING, edge_case_elements())
801}
802
803#[test]
804fn test_euclidean_ring_axioms() {
805 crate::pid::generic_tests::test_euclidean_ring_axioms(MPZ::RING, edge_case_elements())
806}
807
808#[test]
809fn test_integer_ring_axioms() {
810 crate::integer::generic_tests::test_integer_axioms(MPZ::RING, edge_case_elements())
811}
812
813#[test]
814fn test_canonical_iso_axioms_i32() {
815 crate::ring::generic_tests::test_hom_axioms(StaticRing::<i32>::RING, MPZ::RING, [0, -1, 1, i16::MAX as i32, i16::MIN as i32].into_iter());
816 crate::ring::generic_tests::test_iso_axioms(StaticRing::<i32>::RING, MPZ::RING, [0, -1, 1, i16::MIN as i32, i16::MAX as i32].into_iter());
817}
818
819#[test]
820fn test_canonical_iso_axioms_i64() {
821 crate::ring::generic_tests::test_hom_axioms(StaticRing::<i64>::RING, MPZ::RING, [0, -1, 1, i32::MAX as i64, i32::MIN as i64].into_iter());
822 crate::ring::generic_tests::test_iso_axioms(StaticRing::<i64>::RING, MPZ::RING, [0, -1, 1, i32::MIN as i64, i32::MAX as i64].into_iter());
823
824 assert_el_eq!(MPZ::RING, MPZ::RING.sub(MPZ::RING.power_of_two(63), MPZ::RING.one()), &MPZ::RING.coerce(&StaticRing::<i64>::RING, i64::MAX));
825 assert_el_eq!(MPZ::RING, MPZ::RING.negate(MPZ::RING.power_of_two(63)), MPZ::RING.coerce(&StaticRing::<i64>::RING, i64::MIN));
826 assert_eq!(i64::MAX, int_cast(MPZ::RING.sub(MPZ::RING.power_of_two(63), MPZ::RING.one()), &StaticRing::<i64>::RING, MPZ::RING));
827 assert_eq!(i64::MIN, int_cast(MPZ::RING.negate(MPZ::RING.power_of_two(63)), &StaticRing::<i64>::RING, MPZ::RING));
828}
829
830#[test]
831fn test_canonical_iso_axioms_i128() {
832 crate::ring::generic_tests::test_hom_axioms(StaticRing::<i128>::RING, MPZ::RING, [0, -1, 1, i64::MAX as i128, i64::MIN as i128].into_iter());
833 crate::ring::generic_tests::test_iso_axioms(StaticRing::<i128>::RING, MPZ::RING, [0, -1, 1, i64::MIN as i128, i64::MAX as i128].into_iter());
834
835 assert_el_eq!(MPZ::RING, MPZ::RING.sub(MPZ::RING.power_of_two(127), MPZ::RING.one()), &MPZ::RING.coerce(&StaticRing::<i128>::RING, i128::MAX));
836 assert_el_eq!(MPZ::RING, MPZ::RING.negate(MPZ::RING.power_of_two(127)), MPZ::RING.coerce(&StaticRing::<i128>::RING, i128::MIN));
837 assert_eq!(i128::MAX, int_cast(MPZ::RING.sub(MPZ::RING.power_of_two(127), MPZ::RING.one()), &StaticRing::<i128>::RING, MPZ::RING));
838 assert_eq!(i128::MIN, int_cast(MPZ::RING.negate(MPZ::RING.power_of_two(127)), &StaticRing::<i128>::RING, MPZ::RING));
839}
840
841#[test]
842fn test_canonical_iso_axioms_bigint() {
843 crate::ring::generic_tests::test_hom_axioms(RustBigintRing::RING, MPZ::RING, edge_case_elements_bigint());
844 crate::ring::generic_tests::test_iso_axioms(RustBigintRing::RING, MPZ::RING, edge_case_elements_bigint());
845}
846
847#[test]
848fn test_abs_is_bit_set() {
849 let a = MPZ::RING.int_hom().map(1 << 15);
850 assert_eq!(true, MPZ::RING.abs_is_bit_set(&a, 15));
851 assert_eq!(false, MPZ::RING.abs_is_bit_set(&a, 16));
852 assert_eq!(false, MPZ::RING.abs_is_bit_set(&a, 14));
853
854 let a = MPZ::RING.int_hom().map(-7);
855 assert_eq!(true, MPZ::RING.abs_is_bit_set(&a, 0));
856 assert_eq!(true, MPZ::RING.abs_is_bit_set(&a, 1));
857 assert_eq!(true, MPZ::RING.abs_is_bit_set(&a, 2));
858 assert_eq!(false, MPZ::RING.abs_is_bit_set(&a, 3));
859
860 let a = MPZ::RING.int_hom().map(-1 << 15);
861 assert_eq!(true, MPZ::RING.abs_is_bit_set(&a, 15));
862 assert_eq!(false, MPZ::RING.abs_is_bit_set(&a, 16));
863 assert_eq!(false, MPZ::RING.abs_is_bit_set(&a, 14));
864}
865
866#[test]
867fn test_highest_set_bit() {
868 assert_eq!(None, MPZ::RING.abs_highest_set_bit(&MPZ::RING.int_hom().map(0)));
869 assert_eq!(Some(0), MPZ::RING.abs_highest_set_bit(&MPZ::RING.int_hom().map(1)));
870 assert_eq!(Some(0), MPZ::RING.abs_highest_set_bit(&MPZ::RING.int_hom().map(-1)));
871 assert_eq!(Some(1), MPZ::RING.abs_highest_set_bit(&MPZ::RING.int_hom().map(2)));
872 assert_eq!(Some(1), MPZ::RING.abs_highest_set_bit(&MPZ::RING.int_hom().map(-2)));
873 assert_eq!(Some(1), MPZ::RING.abs_highest_set_bit(&MPZ::RING.int_hom().map(3)));
874 assert_eq!(Some(1), MPZ::RING.abs_highest_set_bit(&MPZ::RING.int_hom().map(-3)));
875 assert_eq!(Some(2), MPZ::RING.abs_highest_set_bit(&MPZ::RING.int_hom().map(4)));
876 assert_eq!(Some(2), MPZ::RING.abs_highest_set_bit(&MPZ::RING.int_hom().map(-4)));
877}
878
879#[test]
880fn test_lowest_set_bit() {
881 assert_eq!(None, MPZ::RING.abs_highest_set_bit(&MPZ::RING.int_hom().map(0)));
882 assert_eq!(Some(0), MPZ::RING.abs_lowest_set_bit(&MPZ::RING.int_hom().map(1)));
883 assert_eq!(Some(0), MPZ::RING.abs_lowest_set_bit(&MPZ::RING.int_hom().map(-1)));
884 assert_eq!(Some(1), MPZ::RING.abs_lowest_set_bit(&MPZ::RING.int_hom().map(2)));
885 assert_eq!(Some(1), MPZ::RING.abs_lowest_set_bit(&MPZ::RING.int_hom().map(-2)));
886 assert_eq!(Some(0), MPZ::RING.abs_lowest_set_bit(&MPZ::RING.int_hom().map(3)));
887 assert_eq!(Some(0), MPZ::RING.abs_lowest_set_bit(&MPZ::RING.int_hom().map(-3)));
888 assert_eq!(Some(2), MPZ::RING.abs_lowest_set_bit(&MPZ::RING.int_hom().map(4)));
889 assert_eq!(Some(2), MPZ::RING.abs_lowest_set_bit(&MPZ::RING.int_hom().map(-4)));
890}
891
892#[test]
893fn from_to_float_approx() {
894 let x: f64 = 83465209236517892563478156042389675783219532497861237985328563.;
895 let y = MPZ::RING.to_float_approx(&MPZ::RING.from_float_approx(x).unwrap());
896 assert!(x * 0.99 < y);
897 assert!(y < x * 1.01);
898}
899
900#[bench]
901fn bench_mul_300_bits(bencher: &mut test::Bencher) {
902 let x = MPZ::RING.coerce(&RustBigintRing::RING, RustBigintRing::RING.get_ring().parse("2382385687561872365981723456981723456987134659834659813491964132897159283746918732563498628754", 10).unwrap());
903 let y = MPZ::RING.coerce(&RustBigintRing::RING, RustBigintRing::RING.get_ring().parse("48937502893645789234569182735646324895723409587234", 10).unwrap());
904 let z = MPZ::RING.coerce(&RustBigintRing::RING, RustBigintRing::RING.get_ring().parse("116588006478839442056346504147013274749794691549803163727888681858469844569693215953808606899770104590589390919543097259495176008551856143726436", 10).unwrap());
905 bencher.iter(|| {
906 let p = MPZ::RING.mul_ref(&x, &y);
907 assert_el_eq!(MPZ::RING, z, p);
908 })
909}
910
911#[bench]
912fn bench_div_300_bits(bencher: &mut test::Bencher) {
913 let x = MPZ::RING.coerce(&RustBigintRing::RING, RustBigintRing::RING.get_ring().parse("2382385687561872365981723456981723456987134659834659813491964132897159283746918732563498628754", 10).unwrap());
914 let y = MPZ::RING.coerce(&RustBigintRing::RING, RustBigintRing::RING.get_ring().parse("48937502893645789234569182735646324895723409587234", 10).unwrap());
915 let z = MPZ::RING.coerce(&RustBigintRing::RING, RustBigintRing::RING.get_ring().parse("116588006478839442056346504147013274749794691549803163727888681858469844569693215953808606899770104590589390919543097259495176008551856143726436", 10).unwrap());
916 bencher.iter(|| {
917 let q = MPZ::RING.euclidean_div(MPZ::RING.clone_el(&z), &y);
918 assert_el_eq!(MPZ::RING, x, q);
919 })
920}
921
922#[test]
923fn test_serialization() {
924 crate::serialization::generic_tests::test_serialization(MPZ::RING, edge_case_elements());
925}