dashu_int/modular/
reducer.rs1use crate::{
2 add_ops::repr::{sub_large, sub_large_dword, sub_large_ref_val},
3 buffer::Buffer,
4 cmp,
5 div_const::{ConstDivisor, ConstDivisorRepr},
6 helper_macros::debug_assert_zero,
7 math,
8 primitive::shrink_dword,
9 repr::{Repr, TypedRepr, TypedReprRef},
10 shift,
11 ubig::UBig,
12};
13use num_modular::Reducer;
14
15use super::{
16 repr::{ReducedDword, ReducedLarge, ReducedRepr, ReducedWord},
17 Reduced,
18};
19
20impl ConstDivisor {
21 fn reduce_once(&self, target: UBig) -> UBig {
23 if !self.check(&target) {
24 match &self.0 {
25 ConstDivisorRepr::Single(d) => target - d.normalized_divisor(),
26 ConstDivisorRepr::Double(d) => target - d.normalized_divisor(),
27 ConstDivisorRepr::Large(d) => {
28 match target.into_repr() {
29 TypedRepr::Small(s) => UBig::from_dword(s), TypedRepr::Large(s) => UBig(sub_large(s, &d.normalized_divisor)),
31 }
32 }
33 }
34 } else {
35 target
36 }
37 }
38
39 fn reduce_negate(&self, target: UBig) -> UBig {
41 match &self.0 {
42 ConstDivisorRepr::Single(d) => d.normalized_divisor() - target,
43 ConstDivisorRepr::Double(d) => d.normalized_divisor() - target,
44 ConstDivisorRepr::Large(d) => match target.into_repr() {
45 TypedRepr::Small(s) => {
46 UBig(sub_large_dword(d.normalized_divisor.as_ref().into(), s))
47 }
48 TypedRepr::Large(s) => UBig(sub_large_ref_val(&d.normalized_divisor, s)),
49 },
50 }
51 }
52
53 fn convert_from_normalized(&self, target: &UBig) -> Reduced {
54 match &self.0 {
55 ConstDivisorRepr::Single(d) => {
56 Reduced::from_single(ReducedWord(target.try_into().unwrap()), d)
57 }
58 ConstDivisorRepr::Double(d) => {
59 Reduced::from_double(ReducedDword(target.try_into().unwrap()), d)
60 }
61 ConstDivisorRepr::Large(d) => {
62 let mut buf = Buffer::allocate_exact(d.normalized_divisor.len());
63 let words = target.as_words();
64 buf.push_slice(words);
65 buf.push_zeros(d.normalized_divisor.len() - words.len());
66 Reduced::from_large(ReducedLarge(buf.into_boxed_slice()), d)
67 }
68 }
69 }
70
71 fn convert_to_normalized(&self, target: Reduced) -> UBig {
72 match target.repr() {
75 ReducedRepr::Single(raw, _) => UBig(Repr::from_word(raw.0)),
76 ReducedRepr::Double(raw, _) => UBig(Repr::from_dword(raw.0)),
77 ReducedRepr::Large(raw, _) => {
78 let mut buf = Buffer::from(raw.0.as_ref());
79 buf.pop_zeros();
80 UBig(Repr::from_buffer(buf))
81 }
82 }
83 }
84}
85
86impl Reducer<UBig> for ConstDivisor {
87 #[inline]
88 fn new(m: &UBig) -> Self {
89 ConstDivisor::new(m.clone())
90 }
91
92 fn transform(&self, target: UBig) -> UBig {
93 UBig(match &self.0 {
94 ConstDivisorRepr::Single(d) => Repr::from_word(ReducedWord::from_ubig(&target, d).0),
95 ConstDivisorRepr::Double(d) => Repr::from_dword(ReducedDword::from_ubig(&target, d).0),
96 ConstDivisorRepr::Large(d) => Repr::from_buffer(d.rem_repr(target.into_repr())),
97 })
98 }
99 fn check(&self, target: &UBig) -> bool {
100 match (&self.0, target.repr()) {
102 (ConstDivisorRepr::Single(d), TypedReprRef::RefSmall(dw)) => match shrink_dword(dw) {
103 Some(w) => d.0.check(&w),
104 None => false,
105 },
106 (ConstDivisorRepr::Single(_), TypedReprRef::RefLarge(_)) => false,
107 (ConstDivisorRepr::Double(d), TypedReprRef::RefSmall(dw)) => d.0.check(&dw),
108 (ConstDivisorRepr::Double(_), TypedReprRef::RefLarge(_)) => false,
109 (ConstDivisorRepr::Large(_), TypedReprRef::RefSmall(_)) => true,
110 (ConstDivisorRepr::Large(d), TypedReprRef::RefLarge(words)) => {
111 cmp::cmp_in_place(words, &d.normalized_divisor).is_le()
112 && words[0] & math::ones_word(d.shift) == 0 }
114 }
115 }
116
117 #[inline]
118 fn modulus(&self) -> UBig {
119 self.value()
120 }
121
122 fn residue(&self, target: UBig) -> UBig {
123 UBig(match target.into_repr() {
124 TypedRepr::Small(dw) => match &self.0 {
125 ConstDivisorRepr::Single(d) => {
126 Repr::from_word(shrink_dword(dw).unwrap() >> d.0.shift())
127 }
128 ConstDivisorRepr::Double(d) => Repr::from_dword(dw >> d.0.shift()),
129 ConstDivisorRepr::Large(d) => Repr::from_dword(dw >> d.shift),
130 },
131 TypedRepr::Large(mut buffer) => {
132 if let ConstDivisorRepr::Large(d) = &self.0 {
133 debug_assert_zero!(shift::shr_in_place(&mut buffer, d.shift));
134 Repr::from_buffer(buffer)
135 } else {
136 unreachable!()
137 }
138 }
139 })
140 }
141
142 #[inline(always)]
143 fn is_zero(&self, target: &UBig) -> bool {
144 target.is_zero()
145 }
146
147 #[inline]
148 fn add(&self, lhs: &UBig, rhs: &UBig) -> UBig {
149 self.reduce_once(lhs + rhs)
150 }
151 #[inline]
152 fn dbl(&self, target: UBig) -> UBig {
153 self.reduce_once(target << 1)
154 }
155 #[inline]
156 fn sub(&self, lhs: &UBig, rhs: &UBig) -> UBig {
157 if lhs >= rhs {
158 lhs - rhs
159 } else {
160 self.reduce_negate(rhs - lhs)
161 }
162 }
163 #[inline]
164 fn neg(&self, target: UBig) -> UBig {
165 if target.is_zero() {
166 target
167 } else {
168 self.reduce_negate(target)
169 }
170 }
171
172 #[inline]
176 fn mul(&self, lhs: &UBig, rhs: &UBig) -> UBig {
177 let lhs = self.convert_from_normalized(lhs);
178 let rhs = self.convert_from_normalized(rhs);
179 self.convert_to_normalized(lhs * rhs)
180 }
181 #[inline]
182 fn sqr(&self, target: UBig) -> UBig {
183 self.convert_to_normalized(self.convert_from_normalized(&target).sqr())
184 }
185 #[inline]
186 fn inv(&self, target: UBig) -> Option<UBig> {
187 self.convert_from_normalized(&target)
188 .inv()
189 .map(|v| self.convert_to_normalized(v))
190 }
191 #[inline]
192 fn pow(&self, base: UBig, exp: &UBig) -> UBig {
193 self.convert_to_normalized(self.convert_from_normalized(&base).pow(exp))
194 }
195}