dashu_int/modular/
convert.rs1use crate::{
4 arch::word::{DoubleWord, Word},
5 buffer::Buffer,
6 div_const::{ConstDivisorRepr, ConstDoubleDivisor, ConstLargeDivisor, ConstSingleDivisor},
7 fast_div::ConstDivisor,
8 helper_macros::debug_assert_zero,
9 ibig::IBig,
10 primitive::shrink_dword,
11 repr::{Repr, TypedReprRef::*},
12 shift,
13 ubig::UBig,
14 Sign::*,
15};
16use dashu_base::UnsignedAbs;
17
18use super::repr::{Reduced, ReducedDword, ReducedLarge, ReducedRepr, ReducedWord};
19
20impl Reduced<'_> {
21 #[inline]
32 pub fn residue(&self) -> UBig {
33 let repr = match self.repr() {
34 ReducedRepr::Single(raw, ring) => Repr::from_word(raw.residue(ring)),
35 ReducedRepr::Double(raw, ring) => Repr::from_dword(raw.residue(ring)),
36 ReducedRepr::Large(raw, ring) => Repr::from_buffer(raw.residue(ring)),
37 };
38 UBig(repr)
39 }
40
41 pub fn modulus(&self) -> UBig {
43 let repr = match self.repr() {
44 ReducedRepr::Single(_, ring) => Repr::from_word(ring.divisor()),
45 ReducedRepr::Double(_, ring) => Repr::from_dword(ring.divisor()),
46 ReducedRepr::Large(_, ring) => Repr::from_buffer(ring.divisor()),
47 };
48 UBig(repr)
49 }
50}
51
52impl ReducedWord {
53 #[inline]
54 pub fn from_ubig(x: &UBig, ring: &ConstSingleDivisor) -> Self {
55 Self(match x.repr() {
56 RefSmall(dword) => {
57 if let Some(word) = shrink_dword(dword) {
58 ring.rem_word(word)
59 } else {
60 ring.rem_dword(dword)
61 }
62 }
63 RefLarge(words) => ring.rem_large(words),
64 })
65 }
66
67 #[inline]
68 pub fn residue(self, ring: &ConstSingleDivisor) -> Word {
69 debug_assert!(self.is_valid(ring));
70 self.0 >> ring.shift()
71 }
72}
73
74impl ReducedDword {
75 #[inline]
76 pub fn from_ubig(x: &UBig, ring: &ConstDoubleDivisor) -> Self {
77 Self(match x.repr() {
78 RefSmall(dword) => ring.rem_dword(dword),
79 RefLarge(words) => ring.rem_large(words),
80 })
81 }
82
83 #[inline]
84 pub fn residue(self, ring: &ConstDoubleDivisor) -> DoubleWord {
85 debug_assert!(self.is_valid(ring));
86 self.0 >> ring.shift()
87 }
88}
89
90impl ReducedLarge {
91 pub fn from_ubig(x: UBig, ring: &ConstLargeDivisor) -> ReducedLarge {
92 let mut buffer = ring.rem_repr(x.into_repr());
93 let modulus_len = ring.normalized_divisor.len();
94 buffer.ensure_capacity_exact(modulus_len);
95 buffer.push_zeros(modulus_len - buffer.len());
96 Self(buffer.into_boxed_slice())
97 }
98
99 pub fn residue(&self, ring: &ConstLargeDivisor) -> Buffer {
100 let mut buffer: Buffer = self.0.as_ref().into();
101 debug_assert_zero!(shift::shr_in_place(&mut buffer, ring.shift));
102 buffer
103 }
104}
105
106pub trait IntoRing<'a, RingReducer> {
108 type RingElement: 'a;
109 fn into_ring(self, reducer: &'a RingReducer) -> Self::RingElement;
110}
111
112impl<'a> IntoRing<'a, ConstDivisor> for UBig {
113 type RingElement = Reduced<'a>;
114 #[inline]
115 fn into_ring(self, ring: &ConstDivisor) -> Reduced {
116 match &ring.0 {
117 ConstDivisorRepr::Single(ring) => {
118 Reduced::from_single(ReducedWord::from_ubig(&self, ring), ring)
119 }
120 ConstDivisorRepr::Double(ring) => {
121 Reduced::from_double(ReducedDword::from_ubig(&self, ring), ring)
122 }
123 ConstDivisorRepr::Large(ring) => {
124 Reduced::from_large(ReducedLarge::from_ubig(self, ring), ring)
125 }
126 }
127 }
128}
129
130impl<'a> IntoRing<'a, ConstDivisor> for IBig {
131 type RingElement = Reduced<'a>;
132
133 #[inline]
134 fn into_ring(self, ring: &ConstDivisor) -> Reduced {
135 let sign = self.sign();
136 let modulo = self.unsigned_abs().into_ring(ring);
137 match sign {
138 Positive => modulo,
139 Negative => -modulo,
140 }
141 }
142}
143
144macro_rules! impl_into_ring_for_unsigned {
146 ($t:ty) => {
147 impl<'a> IntoRing<'a, ConstDivisor> for $t {
148 type RingElement = Reduced<'a>;
149 #[inline]
150 fn into_ring(self, ring: &'a ConstDivisor) -> Reduced<'a> {
151 UBig::from(self).into_ring(ring)
152 }
153 }
154 };
155}
156
157macro_rules! impl_into_modulo_for_signed {
159 ($t:ty) => {
160 impl<'a> IntoRing<'a, ConstDivisor> for $t {
161 type RingElement = Reduced<'a>;
162 #[inline]
163 fn into_ring(self, ring: &'a ConstDivisor) -> Reduced<'a> {
164 IBig::from(self).into_ring(ring)
165 }
166 }
167 };
168}
169
170impl_into_ring_for_unsigned!(bool);
171impl_into_ring_for_unsigned!(u8);
172impl_into_ring_for_unsigned!(u16);
173impl_into_ring_for_unsigned!(u32);
174impl_into_ring_for_unsigned!(u64);
175impl_into_ring_for_unsigned!(u128);
176impl_into_ring_for_unsigned!(usize);
177impl_into_modulo_for_signed!(i8);
178impl_into_modulo_for_signed!(i16);
179impl_into_modulo_for_signed!(i32);
180impl_into_modulo_for_signed!(i64);
181impl_into_modulo_for_signed!(i128);
182impl_into_modulo_for_signed!(isize);
183
184impl ConstDivisor {
185 pub fn reduce<'a, T: IntoRing<'a, ConstDivisor, RingElement = Reduced<'a>>>(
197 &'a self,
198 x: T,
199 ) -> Reduced {
200 x.into_ring(self)
201 }
202}