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;
110 fn into_ring(self, reducer: &'a RingReducer) -> Self::RingElement;
112}
113
114impl<'a> IntoRing<'a, ConstDivisor> for UBig {
115 type RingElement = Reduced<'a>;
116 #[inline]
117 fn into_ring(self, ring: &'a ConstDivisor) -> Reduced<'a> {
118 match &ring.0 {
119 ConstDivisorRepr::Single(ring) => {
120 Reduced::from_single(ReducedWord::from_ubig(&self, ring), ring)
121 }
122 ConstDivisorRepr::Double(ring) => {
123 Reduced::from_double(ReducedDword::from_ubig(&self, ring), ring)
124 }
125 ConstDivisorRepr::Large(ring) => {
126 Reduced::from_large(ReducedLarge::from_ubig(self, ring), ring)
127 }
128 }
129 }
130}
131
132impl<'a> IntoRing<'a, ConstDivisor> for IBig {
133 type RingElement = Reduced<'a>;
134
135 #[inline]
136 fn into_ring(self, ring: &'a ConstDivisor) -> Reduced<'a> {
137 let sign = self.sign();
138 let modulo = self.unsigned_abs().into_ring(ring);
139 match sign {
140 Positive => modulo,
141 Negative => -modulo,
142 }
143 }
144}
145
146macro_rules! impl_into_ring_for_unsigned {
148 ($t:ty) => {
149 impl<'a> IntoRing<'a, ConstDivisor> for $t {
150 type RingElement = Reduced<'a>;
151 #[inline]
152 fn into_ring(self, ring: &'a ConstDivisor) -> Reduced<'a> {
153 UBig::from(self).into_ring(ring)
154 }
155 }
156 };
157}
158
159macro_rules! impl_into_modulo_for_signed {
161 ($t:ty) => {
162 impl<'a> IntoRing<'a, ConstDivisor> for $t {
163 type RingElement = Reduced<'a>;
164 #[inline]
165 fn into_ring(self, ring: &'a ConstDivisor) -> Reduced<'a> {
166 IBig::from(self).into_ring(ring)
167 }
168 }
169 };
170}
171
172impl_into_ring_for_unsigned!(bool);
173impl_into_ring_for_unsigned!(u8);
174impl_into_ring_for_unsigned!(u16);
175impl_into_ring_for_unsigned!(u32);
176impl_into_ring_for_unsigned!(u64);
177impl_into_ring_for_unsigned!(u128);
178impl_into_ring_for_unsigned!(usize);
179impl_into_modulo_for_signed!(i8);
180impl_into_modulo_for_signed!(i16);
181impl_into_modulo_for_signed!(i32);
182impl_into_modulo_for_signed!(i64);
183impl_into_modulo_for_signed!(i128);
184impl_into_modulo_for_signed!(isize);
185
186impl ConstDivisor {
187 pub fn reduce<'a, T: IntoRing<'a, ConstDivisor, RingElement = Reduced<'a>>>(
199 &'a self,
200 x: T,
201 ) -> Reduced<'a> {
202 x.into_ring(self)
203 }
204}