relp_num/integer/factorization/
size_large.rs1use std::num::NonZeroU64;
2
3use smallvec::SmallVec;
4
5use crate::{NonZeroFactorizable, NonZeroFactorization, NonZeroSign, Ubig};
6use crate::integer::big::{BITS_PER_WORD, NonZeroUbig};
7use crate::integer::big::ops::div::div_assign_one_word;
8use crate::integer::big::ops::non_zero::{is_one_non_zero, shr};
9use crate::integer::big::ops::normalize::trailing_zeros;
10use crate::integer::factorization::{KEEP_RESIDUAL, NR_SMALL_PRIMES, size_64, start, TRIAL_DIVISION_LIMIT};
11use crate::integer::factorization::prime::primes::SMALL_ODD_PRIMES;
12use crate::non_zero::NonZero;
13use crate::Prime;
14use crate::traits::factorization::FactorizationResidual;
15
16impl<const S: usize> FactorizationResidual for Ubig<S> {
18 #[inline]
19 fn one() -> Self {
20 <Self as num_traits::One>::one()
21 }
22
23 #[inline]
24 fn is_one(&self) -> bool {
25 <Self as num_traits::One>::is_one(self)
26 }
27}
28
29macro_rules! define {
30 ($ty:ident) => {
31 impl<const S: usize> NonZeroFactorizable for $ty<S> {
32 type Factor = usize;
33 type Power = u32;
34 type Residual = Ubig<S>;
40
41 fn factorize(&self) -> NonZeroFactorization<Self::Factor, Self::Power, Self::Residual> {
42 assert!(self.is_not_zero(), "attempt to factorize zero");
43
44 let (factors, residual) = factorize::<
45 NR_SMALL_PRIMES, TRIAL_DIVISION_LIMIT, KEEP_RESIDUAL, S
46 >(self.inner());
47 let residual = unsafe {
48 Ubig::from_inner_unchecked(residual)
51 };
52
53 NonZeroFactorization { sign: NonZeroSign::Positive, factors, residual }
54 }
55 }
56 }
57}
58
59define!(Ubig);
60define!(NonZeroUbig);
61
62fn factorize<
70 const NR_SMALL_PRIMES: usize,
71 const TRIAL_DIVISION_LIMIT: u64,
72 const KEEP_RESIDUAL: bool,
73 const S: usize,
74>(values: &[usize]) -> (Vec<(usize, u32)>, SmallVec<[usize; S]>) {
75 let (words, bits) = unsafe {
76 trailing_zeros(values)
78 };
79
80 let mut x = shr::<S>(values, words, bits);
81 let total = words as u32 * BITS_PER_WORD + bits;
82 let mut factors = vec![];
83 if total > 0 {
84 factors.push((2, total));
85 }
86
87 if x.len() == 1 {
88 let as_small = unsafe {
89 NonZeroU64::new_unchecked(x[0] as u64)
91 };
92 let (small, residual) = size_64::factorize::<
93 NR_SMALL_PRIMES, TRIAL_DIVISION_LIMIT, 0, KEEP_RESIDUAL,
94 >(as_small);
95 for (factor, power) in small {
96 factors.push((factor as usize, power));
97 }
98 x[0] = residual as usize;
101 } else {
102 'odd: {
104 for divisor in &SMALL_ODD_PRIMES[..NR_SMALL_PRIMES] {
105 let divisor = *divisor as usize;
106
107 let mut counter = 0;
108 loop {
109 let mut copy = x.clone();
110 let remainder = unsafe {
111 div_assign_one_word(&mut copy, divisor)
113 };
114 if remainder == 0 {
115 counter += 1;
116 x = copy;
117 } else {
118 break;
119 }
120 }
121
122 if counter > 0 {
123 factors.push((divisor, counter));
124 }
125
126 if unsafe { is_one_non_zero(&x) } {
127 break 'odd;
128 }
129 }
130
131 if TRIAL_DIVISION_LIMIT != 0 {
132 let start = start(NR_SMALL_PRIMES) as usize;
133 trial_division::<TRIAL_DIVISION_LIMIT, S>(&mut x, start, &mut factors);
134
135 if unsafe { is_one_non_zero(&x) } {
136 break 'odd;
137 }
138 }
139
140 if KEEP_RESIDUAL && let &[value] = x.as_slice() && (value as u64).is_prime() {
145 factors.push((value, 1));
146 x[0] = 1;
147 }
148 }
149 }
150
151 (factors, x)
152}
153
154fn trial_division<
156 const END: u64,
157 const S: usize,
158>(
159 x: &mut SmallVec<[usize; S]>,
160 start: usize,
161 factors: &mut Vec<(usize, u32)>,
162) {
163 let get_x_bits = |y: &[usize]| {
165 let most_significant = *y.last().expect("the value is nonzero, so it has a word");
166 (y.len() as u32 - 1) * BITS_PER_WORD + most_significant.bit_width()
167 };
168
169 let mut divisor = start;
170 let mut x_bits = get_x_bits(x);
171 while {
172 let not_one = unsafe { !is_one_non_zero(x) };
173 let below_limit = divisor as u64 <= END;
174 let below_sqrt = {
175 let divisor_bits = divisor.bit_width();
176 2 * divisor_bits <= x_bits
177 };
178
179 not_one && below_limit && below_sqrt
180 } {
181 let mut counter = 0;
182 loop {
183 let mut copy = x.clone();
184 let remainder = unsafe {
185 div_assign_one_word(&mut copy, divisor)
187 };
188 if remainder == 0 {
189 counter += 1;
190 *x = copy;
191 } else {
192 break;
193 }
194 }
195
196 if counter > 0 {
197 factors.push((divisor, counter));
198 x_bits = get_x_bits(x);
199 }
200
201 divisor += 2;
202 }
203}
204
205#[cfg(test)]
206mod test {
207 use std::str::FromStr;
208
209 use num_traits::One;
210 use smallvec::smallvec;
211
212 use crate::{NonZeroFactorizable, NonZeroFactorization, NonZeroSign, NonZeroUbig, Ubig};
213 use crate::integer::factorization::size_large::factorize;
214
215 #[test]
216 fn test_factor() {
217 assert_eq!(
218 NonZeroUbig::<4>::one().factorize(),
219 NonZeroFactorization { sign: NonZeroSign::Positive, factors: vec![], residual: Ubig::one() },
220 );
221 assert_eq!(
222 NonZeroUbig::<4>::new(4).unwrap().factorize(),
223 NonZeroFactorization { sign: NonZeroSign::Positive, factors: vec![(2, 2)], residual: Ubig::one() },
224 );
225 assert_eq!(
228 unsafe { NonZeroUbig::<2>::from_inner_unchecked(smallvec![0, 351684787688]) }.factorize(),
229 NonZeroFactorization {
230 sign: NonZeroSign::Positive,
231 factors: vec![
232 (2, 64 + 3),
233 (13, 1),
234 ],
235 residual: Ubig::new(3381584497),
236 },
237 );
238 assert_eq!(
239 factorize::<5, 0, true, 2>(&[0, 351684787688]),
240 (vec![(2, 64 + 3), (13, 1), (3381584497, 1)], smallvec![1]),
241 );
242 let composite = NonZeroUbig::<8>::from_str("22429238517634168458101140012627848499653000000").unwrap();
243 assert_eq!(
244 factorize::<256, 100, true, 8>(&composite),
245 (vec![(2, 6), (3, 18), (5, 6), (11, 12), (18446744073709551437, 1)], smallvec![1]),
246 );
247 }
248
249 #[test]
251 fn test_multi_word_residual() {
252 let left = 2_u128.pow(64) - 59;
254 let right = 2_u128.pow(64) - 83;
255 let product = left * right;
256
257 let value = NonZeroUbig::<2>::new_u128(product).unwrap();
258 let NonZeroFactorization { sign, factors, residual } = value.factorize();
259 assert_eq!(sign, NonZeroSign::Positive);
260 assert_eq!(factors, vec![]);
261 assert_eq!(residual, Ubig::<2>::new_u128(product));
262
263 let (factors, residual) = factorize::<256, 0, true, 2>(value.inner());
266 assert_eq!(factors, vec![]);
267 assert_eq!(residual.as_slice(), value.inner().as_slice());
268 }
269}