malachite_base/num/factorization/
factor.rs

1// Copyright © 2025 Mikhail Hogrefe
2//
3// Uses code adopted from the FLINT Library.
4//
5//      Copyright © 2009 Tom Boothby
6//
7//      Copyright © 2008, 2009, 2012 William Hart
8//
9// This file is part of Malachite.
10//
11// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
12// Lesser General Public License (LGPL as published by the Free Software Foundation; either version
13// 3 of the License, or (at your option any later version. See <https://www.gnu.org/licenses/>.
14
15use crate::num::arithmetic::mod_pow::mul_mod_helper;
16use crate::num::arithmetic::sqrt::{sqrt_rem_2_newton, sqrt_rem_newton};
17use crate::num::arithmetic::traits::{
18    DivMod, FloorRoot, FloorSqrt, Gcd, ModMulPrecomputed, ModSub, ModSubAssign, Parity, PowerOf2,
19    SqrtRem, Square, WrappingAddAssign, WrappingMulAssign, WrappingSquare, WrappingSubAssign,
20    XMulYToZZ, XXDivModYToQR, XXSubYYToZZ,
21};
22use crate::num::basic::integers::{PrimitiveInt, USIZE_IS_U32};
23use crate::num::basic::unsigneds::PrimitiveUnsigned;
24use crate::num::conversion::traits::{ExactFrom, WrappingFrom};
25use crate::num::factorization::primes::SMALL_PRIMES;
26use crate::num::factorization::traits::{Factor, IsPrime, Primes};
27use crate::num::logic::traits::{LeadingZeros, LowMask, SignificantBits};
28use core::mem::swap;
29
30pub(crate) const MAX_FACTORS_IN_U8: usize = 4;
31pub(crate) const MAX_FACTORS_IN_U16: usize = 6;
32pub(crate) const MAX_FACTORS_IN_U32: usize = 9;
33pub(crate) const MAX_FACTORS_IN_U64: usize = 15;
34pub(crate) const MAX_FACTORS_IN_USIZE: usize = 15;
35
36/// A struct that contains the prime factorization of an integer. See implementations of the
37/// [`Factor`] trait for more information.
38#[derive(Clone, Debug, Eq, PartialEq)]
39pub struct Factors<T: PrimitiveUnsigned, const N: usize> {
40    factors: [T; N],
41    exponents: [u8; N],
42}
43
44/// An iterator over [`Factors`].
45#[derive(Clone, Debug, Eq, PartialEq)]
46pub struct FactorsIterator<T: PrimitiveUnsigned, const N: usize> {
47    i: usize,
48    factors: Factors<T, N>,
49}
50
51impl<T: PrimitiveUnsigned, const N: usize> Iterator for FactorsIterator<T, N> {
52    type Item = (T, u8);
53
54    fn next(&mut self) -> Option<(T, u8)> {
55        let e = *self.factors.exponents.get(self.i)?;
56        if e == 0 {
57            return None;
58        }
59        let f = self.factors.factors[self.i];
60        self.i += 1;
61        Some((f, e))
62    }
63}
64
65impl<T: PrimitiveUnsigned, const N: usize> IntoIterator for Factors<T, N> {
66    type IntoIter = FactorsIterator<T, N>;
67    type Item = (T, u8);
68
69    fn into_iter(self) -> FactorsIterator<T, N> {
70        FactorsIterator {
71            i: 0,
72            factors: self,
73        }
74    }
75}
76
77impl<T: PrimitiveUnsigned, const N: usize> Factors<T, N> {
78    const fn new() -> Factors<T, N> {
79        Factors {
80            factors: [T::ZERO; N],
81            exponents: [0; N],
82        }
83    }
84
85    // This takes linear time in the number of factors, but that's ok because the number of factors
86    // is small.
87    //
88    // This is n_factor_insert from ulong_extras/factor_insert.c, FLINT 3.1.2, but it also ensures
89    // that the factors are ordered least to greatest.
90    fn insert(&mut self, factor: T, exp: u8) {
91        let mut inserting = false;
92        let mut previous_f = T::ZERO;
93        let mut previous_e = 0;
94        for (f, e) in self.factors.iter_mut().zip(self.exponents.iter_mut()) {
95            if inserting {
96                swap(&mut previous_f, f);
97                swap(&mut previous_e, e);
98                if previous_e == 0 {
99                    break;
100                }
101            } else if *e == 0 {
102                *f = factor;
103                *e = exp;
104                break;
105            } else if *f == factor {
106                *e += exp;
107                break;
108            } else if *f > factor {
109                previous_f = *f;
110                previous_e = *e;
111                *f = factor;
112                *e = exp;
113                inserting = true;
114            }
115        }
116    }
117}
118
119type FactorsU8 = Factors<u8, MAX_FACTORS_IN_U8>;
120type FactorsU16 = Factors<u16, MAX_FACTORS_IN_U16>;
121type FactorsU32 = Factors<u32, MAX_FACTORS_IN_U32>;
122type FactorsU64 = Factors<u64, MAX_FACTORS_IN_U64>;
123type FactorsUsize = Factors<usize, MAX_FACTORS_IN_USIZE>;
124
125// This is n_divrem2_precomp when FLINT64 is false, from ulong_extras/divrem2_precomp.c, FLINT
126// 3.1.2, simplified to only include the branches used when factoring a `u32`.
127fn div_rem_precomputed_float_for_u32_factorization(a: u32, n: u32, inverse: f64) -> (u32, u32) {
128    let mut q = (f64::from(a) * inverse) as u32;
129    let r = a.wrapping_sub(q * n);
130    let ri = i32::wrapping_from(r);
131    if ri >= i32::wrapping_from(n) {
132        q += (f64::from(ri) * inverse) as u32;
133        (q + 1, a.wrapping_sub(q * n).wrapping_sub(n))
134    } else {
135        (q, r)
136    }
137}
138
139// This is n_divrem2_precomp when FLINT64 is true, from ulong_extras/divrem2_precomp.c, FLINT 3.1.2,
140// returning both q and r.
141fn div_rem_precomputed_float_u64(a: u64, n: u64, npre: f64) -> (u64, u64) {
142    if a < n {
143        return (0, a);
144    }
145    if n.get_highest_bit() {
146        return (1, a.wrapping_sub(n));
147    }
148    let (mut q, r) = if n == 1 {
149        (a, 0)
150    } else {
151        let q = ((a as f64) * npre) as u64;
152        (q, a.wrapping_sub(q.wrapping_mul(n)))
153    };
154    let ri = i64::wrapping_from(r);
155    let ni = i64::wrapping_from(n);
156    if ri < ni.wrapping_neg() {
157        q -= ((-(ri as f64)) * npre) as u64;
158    } else if ri >= ni {
159        q += ((ri as f64) * npre) as u64;
160    } else if ri < 0 {
161        return (q - 1, r.wrapping_add(n));
162    } else {
163        return (q, r);
164    }
165    let r = a.wrapping_sub(q.wrapping_mul(n));
166    let ri = i64::wrapping_from(r);
167    if ri >= ni {
168        (q + 1, r.wrapping_sub(n))
169    } else if ri < 0 {
170        (q - 1, r.wrapping_add(n))
171    } else {
172        (q, r)
173    }
174}
175
176// This is n_remove2_precomp when FLINT64 is false, from ulong_extras/remove2_precomp.c, FLINT
177// 3.1.2, returning n and exp.
178fn remove_factor_precomputed_float_u32(mut n: u32, p: u32, inverse: f64) -> (u32, u8) {
179    if p == 2 {
180        let exp = n.trailing_zeros();
181        if exp != 0 {
182            n >>= exp;
183        }
184        (n, u8::wrapping_from(exp))
185    } else {
186        let mut exp = 0;
187        while n >= p {
188            let (q, r) = div_rem_precomputed_float_for_u32_factorization(n, p, inverse);
189            if r != 0 {
190                break;
191            }
192            exp += 1;
193            n = q;
194        }
195        (n, exp)
196    }
197}
198
199// This is n_remove2_precomp when FLINT64 is true, from ulong_extras/remove2_precomp.c, FLINT 3.1.2,
200// returning n and exp.
201fn remove_factor_precomputed_float_u64(mut n: u64, p: u64, inverse: f64) -> (u64, u8) {
202    if p == 2 {
203        let exp = u64::from(n.trailing_zeros());
204        if exp != 0 {
205            n >>= exp;
206        }
207        (n, u8::wrapping_from(exp))
208    } else {
209        let mut exp = 0;
210        while n >= p {
211            let (q, r) = div_rem_precomputed_float_u64(n, p, inverse);
212            if r != 0 {
213                break;
214            }
215            exp += 1;
216            n = q;
217        }
218        (n, exp)
219    }
220}
221
222// This is n_factor_trial_range when FLINT64 is false, from ulong_extras/factor_trial.c, FLINT
223// 3.1.2, where start == 0.
224fn factor_trial_range_u32(factors: &mut FactorsU32, mut n: u32, num_primes: usize) -> u32 {
225    for p in u32::primes().take(num_primes) {
226        if p.square() > n {
227            break;
228        }
229        let exp;
230        (n, exp) = remove_factor_precomputed_float_u32(n, p, 1.0 / f64::from(p));
231        if exp != 0 {
232            factors.insert(p, exp);
233        }
234    }
235    n
236}
237
238// This is n_factor_trial_range when FLINT64 is true, from ulong_extras/factor_trial.c, FLINT 3.1.2.
239fn factor_trial_range_u64(factors: &mut FactorsU64, mut n: u64, num_primes: usize) -> u64 {
240    for p in u64::primes().take(num_primes) {
241        if p.square() > n {
242            break;
243        }
244        let exp;
245        (n, exp) = remove_factor_precomputed_float_u64(n, p, 1.0 / (p as f64));
246        if exp != 0 {
247            factors.insert(p, exp);
248        }
249    }
250    n
251}
252
253const POWER235_MOD63: [u8; 63] = [
254    7, 7, 4, 0, 5, 4, 0, 5, 6, 5, 4, 4, 0, 4, 4, 0, 5, 4, 5, 4, 4, 0, 5, 4, 0, 5, 4, 6, 7, 4, 0, 4,
255    4, 0, 4, 6, 7, 5, 4, 0, 4, 4, 0, 5, 4, 4, 5, 4, 0, 5, 4, 0, 4, 4, 4, 6, 4, 0, 5, 4, 0, 4, 6,
256];
257const POWER235_MOD61: [u8; 61] = [
258    7, 7, 0, 3, 1, 1, 0, 0, 2, 3, 0, 6, 1, 5, 5, 1, 1, 0, 0, 1, 3, 4, 1, 2, 2, 1, 0, 3, 2, 4, 0, 0,
259    4, 2, 3, 0, 1, 2, 2, 1, 4, 3, 1, 0, 0, 1, 1, 5, 5, 1, 6, 0, 3, 2, 0, 0, 1, 1, 3, 0, 7,
260];
261const POWER235_MOD44: [u8; 44] = [
262    7, 7, 0, 2, 3, 3, 0, 2, 2, 3, 0, 6, 7, 2, 0, 2, 3, 2, 0, 2, 3, 6, 0, 6, 2, 3, 0, 2, 2, 2, 0, 2,
263    6, 7, 0, 2, 3, 3, 0, 2, 2, 2, 0, 6,
264];
265const POWER235_MOD31: [u8; 31] =
266    [7, 7, 3, 0, 3, 5, 4, 1, 3, 1, 1, 0, 0, 0, 1, 2, 3, 0, 1, 1, 1, 0, 0, 2, 0, 5, 4, 2, 1, 2, 6];
267
268// This is n_factor_power235 when FLINT64 is false, from ulong_extras/factor_power235.c, FLINT
269// 3.1.2, returning y and exp, and simplified to only include the branches used when factoring a
270// `u32`. In particular, only perfect squares are checked for.
271fn factor_square_u32(n: u32) -> (u32, u8) {
272    let mut t = POWER235_MOD31[(n % 31) as usize];
273    if t == 0 {
274        return (0, 0);
275    };
276    t &= POWER235_MOD44[(n % 44) as usize];
277    if t == 0 {
278        return (0, 0);
279    };
280    t &= POWER235_MOD61[(n % 61) as usize];
281    if t == 0 {
282        return (0, 0);
283    };
284    t &= POWER235_MOD63[(n % 63) as usize];
285    if t.odd() {
286        let (y, r) = n.sqrt_rem();
287        if r == 0 {
288            return (y, 2);
289        }
290    }
291    (0, 0)
292}
293
294// This is n_factor_power235 when FLINT64 is true, from ulong_extras/factor_power235.c, FLINT 3.1.2,
295// returning y and exp. Fifth powers are not checked for, because this function is only called on
296// values with no prime factor less than 27449, and 27449^5 is greater than 2^64.
297fn factor_power23_u64(n: u64) -> (u64, u8) {
298    let mut t = POWER235_MOD31[(n % 31) as usize];
299    if t == 0 {
300        return (0, 0);
301    };
302    t &= POWER235_MOD44[(n % 44) as usize];
303    if t == 0 {
304        return (0, 0);
305    };
306    t &= POWER235_MOD61[(n % 61) as usize];
307    if t == 0 {
308        return (0, 0);
309    };
310    t &= POWER235_MOD63[(n % 63) as usize];
311    if t.odd() {
312        let (y, r) = n.sqrt_rem();
313        if r == 0 {
314            return (y, 2);
315        }
316    }
317    if t & 2 != 0 {
318        let y = n.floor_root(3);
319        if n == y.pow(3) {
320            return (y, 3);
321        }
322    }
323    (0, 0)
324}
325
326const IS_SQUARE_MOD64: [bool; 64] = [
327    true, true, false, false, true, false, false, false, false, true, false, false, false, false,
328    false, false, true, true, false, false, false, false, false, false, false, true, false, false,
329    false, false, false, false, false, true, false, false, true, false, false, false, false, true,
330    false, false, false, false, false, false, false, true, false, false, false, false, false,
331    false, false, true, false, false, false, false, false, false,
332];
333
334const IS_SQUARE_MOD65: [bool; 65] = [
335    true, true, false, false, true, false, false, false, false, true, true, false, false, false,
336    true, false, true, false, false, false, false, false, false, false, false, true, true, false,
337    false, true, true, false, false, false, false, true, true, false, false, true, true, false,
338    false, false, false, false, false, false, false, true, false, true, false, false, false, true,
339    true, false, false, false, false, true, false, false, true,
340];
341
342const IS_SQUARE_MOD63: [bool; 63] = [
343    true, true, false, false, true, false, false, true, false, true, false, false, false, false,
344    true, false, true, false, true, false, false, false, true, false, false, true, false, false,
345    true, false, false, false, false, false, false, true, true, true, false, false, false, false,
346    false, true, false, false, true, false, false, true, false, false, false, false, false, false,
347    true, false, true, false, false, false, false,
348];
349
350// This is n_is_square when FLINT64 is false, from ulong_extras/is_square.c, FLINT 3.1.2.
351fn is_square_u64(x: u64) -> bool {
352    IS_SQUARE_MOD64[(x % 64) as usize]
353        && IS_SQUARE_MOD63[(x % 63) as usize]
354        && IS_SQUARE_MOD65[(x % 65) as usize]
355        && x.floor_sqrt().square() == x
356}
357
358const FLINT_ONE_LINE_MULTIPLIER: u32 = 480;
359
360// This is n_factor_one_line when FLINT64 is true, from ulong_extras/factor_one_line.c, FLINT 3.1.2.
361fn factor_one_line_u64(mut n: u64, iters: usize) -> u64 {
362    let orig_n = n;
363    n.wrapping_mul_assign(u64::from(FLINT_ONE_LINE_MULTIPLIER));
364    let mut iin = 0;
365    let mut inn = n;
366    for _ in 0..iters {
367        if iin >= inn {
368            break;
369        }
370        let mut sqrti = inn.floor_sqrt() + 1;
371        let square = sqrti.square();
372        let mmod = square - inn;
373        if is_square_u64(mmod) {
374            sqrti -= mmod.floor_sqrt();
375            let factor = orig_n.gcd(sqrti);
376            if factor != 1 {
377                return factor;
378            }
379        }
380        iin = inn;
381        inn.wrapping_add_assign(n);
382    }
383    0
384}
385
386fn wyhash64(seed: &mut u64) -> u64 {
387    seed.wrapping_add_assign(0x60bee2bee120fc15);
388    let tmp = u128::from(*seed) * 0xa3b195354a39b70d;
389    let tmp = ((tmp >> 64) ^ tmp).wrapping_mul(0x1b03738712fad5c9);
390    u64::wrapping_from((tmp >> 64) ^ tmp)
391}
392
393struct WyhashRandomU64s {
394    seed: u64,
395}
396
397impl WyhashRandomU64s {
398    const fn new() -> WyhashRandomU64s {
399        WyhashRandomU64s {
400            seed: 0x452aee49c457bbc3,
401        }
402    }
403}
404
405impl Iterator for WyhashRandomU64s {
406    type Item = u64;
407
408    fn next(&mut self) -> Option<u64> {
409        Some(wyhash64(&mut self.seed))
410    }
411}
412
413// This is n_factor_pp1_table from ulong_extras/factor_pp1.c, FLINT 3.1.2.
414const N_FACTOR_PP1_TABLE: [(u16, u8); 34] = [
415    (2784, 5),
416    (1208, 2),
417    (2924, 3),
418    (286, 5),
419    (58, 5),
420    (61, 4),
421    (815, 2),
422    (944, 2),
423    (61, 3),
424    (0, 0),
425    (0, 0),
426    (0, 0),
427    (0, 0),
428    (0, 0),
429    (0, 0),
430    (0, 0),
431    (0, 0),
432    (0, 0),
433    (0, 0),
434    (606, 1),
435    (2403, 1),
436    (2524, 1),
437    (2924, 1),
438    (3735, 2),
439    (669, 2),
440    (6092, 3),
441    (2179, 3),
442    (3922, 3),
443    (6717, 4),
444    (4119, 4),
445    (2288, 4),
446    (9004, 3),
447    (9004, 3),
448    (9004, 3),
449];
450
451// This is n_pp1_pow_ui when FLINT64 is true, from ulong_extras/factor_pp1.c, FLINT 3.1.2, returning
452// the new values of x and y. y is not passed in as its initial value is never used.
453fn pp1_pow_ui_u64(mut x: u64, exp: u64, n: u64, ninv: u64, norm: u64) -> (u64, u64) {
454    let x_orig = x;
455    let two = u64::power_of_2(norm + 1);
456    let mut y = mul_mod_helper::<u64, u128>(x, x, n, ninv, norm).mod_sub(two, n);
457    let mut bit = u64::power_of_2(exp.significant_bits() - 2);
458    while bit != 0 {
459        (x, y) = if exp & bit != 0 {
460            (
461                mul_mod_helper::<u64, u128>(x, y, n, ninv, norm).mod_sub(x_orig, n),
462                mul_mod_helper::<u64, u128>(y, y, n, ninv, norm).mod_sub(two, n),
463            )
464        } else {
465            (
466                mul_mod_helper::<u64, u128>(x, x, n, ninv, norm).mod_sub(two, n),
467                mul_mod_helper::<u64, u128>(y, x, n, ninv, norm).mod_sub(x_orig, n),
468            )
469        };
470        bit >>= 1;
471    }
472    (x, y)
473}
474
475// This is n_pp1_factor when FLINT64 is true, from ulong_extras/factor_pp1.c, FLINT 3.1.2.
476fn pp1_factor_u64(mut n: u64, mut x: u64, norm: u64) -> u64 {
477    if norm != 0 {
478        n >>= norm;
479        x >>= norm;
480    }
481    x.mod_sub_assign(2, n);
482    if x == 0 { 0 } else { n.gcd(x) }
483}
484
485// This is n_pp1_find_power when FLINT64 is true, from ulong_extras/factor_pp1.c, FLINT 3.1.2,
486// returning factor and the new values of x and y. y is not passed in as its initial value is never
487// used.
488fn pp1_find_power_u64(mut x: u64, p: u64, n: u64, ninv: u64, norm: u64) -> (u64, u64, u64) {
489    let mut factor = 1;
490    let mut y = 0;
491    while factor == 1 {
492        (x, y) = pp1_pow_ui_u64(x, p, n, ninv, norm);
493        factor = pp1_factor_u64(n, x, norm);
494    }
495    (factor, x, y)
496}
497
498// This is n_factor_pp1 when FLINT64 is false, from ulong_extras/factor_pp1.c, FLINT 3.1.2. It is
499// assumed that n is odd.
500fn factor_pp1_u64(mut n: u64, b1: u64, c: u64) -> u64 {
501    let mut primes = u64::primes();
502    let sqrt = b1.floor_sqrt();
503    let bits0 = b1.significant_bits();
504    let norm = LeadingZeros::leading_zeros(n);
505    n <<= norm;
506    let n_inverse = u64::precompute_mod_mul_data(&n);
507    let mut x = c << norm;
508    // mul by various prime powers
509    let mut p = 0;
510    let mut old_p = 0;
511    let mut i = 0;
512    let mut old_x = 0;
513    while p < b1 {
514        let j = i + 1024;
515        old_p = p;
516        old_x = x;
517        while i < j {
518            p = primes.next().unwrap();
519            x = if p < sqrt {
520                pp1_pow_ui_u64(
521                    x,
522                    p.pow(u32::wrapping_from(bits0 / p.significant_bits())),
523                    n,
524                    n_inverse,
525                    norm,
526                )
527                .0
528            } else {
529                pp1_pow_ui_u64(x, p, n, n_inverse, norm).0
530            };
531            i += 1;
532        }
533        let factor = pp1_factor_u64(n, x, norm);
534        if factor == 0 {
535            break;
536        }
537        if factor != 1 {
538            return factor;
539        }
540    }
541    if p < b1 {
542        // factor = 0
543        primes.jump_after(old_p);
544        x = old_x;
545        loop {
546            p = primes.next().unwrap();
547            old_x = x;
548            x = if p < sqrt {
549                pp1_pow_ui_u64(
550                    x,
551                    p.pow(u32::wrapping_from(bits0 / p.significant_bits())),
552                    n,
553                    n_inverse,
554                    norm,
555                )
556                .0
557            } else {
558                pp1_pow_ui_u64(x, p, n, n_inverse, norm).0
559            };
560            let factor = pp1_factor_u64(n, x, norm);
561            if factor == 0 {
562                break;
563            }
564            if factor != 1 {
565                return factor;
566            }
567        }
568    } else {
569        return 0;
570    }
571    // factor still 0
572    pp1_find_power_u64(old_x, p, n, n_inverse, norm).0
573}
574
575// This is n_factor_pp1_wrapper when FLINT64 is true, from ulong_extras/factor_pp1.c, FLINT 3.1.2.
576fn factor_pp1_wrapper_u64(n: u64) -> u64 {
577    let bits = n.significant_bits();
578    // silently fail if trial factoring would always succeed
579    if bits < 31 {
580        return 0;
581    }
582    let (b1, count) = N_FACTOR_PP1_TABLE[usize::wrapping_from(bits) - 31];
583    let b1 = u64::from(b1);
584    let mut state = WyhashRandomU64s::new();
585    let mask = u64::low_mask((n - 4).significant_bits());
586    let limit = n - 3;
587    for _ in 0..count {
588        let mut randint = u64::MAX;
589        while randint >= limit {
590            randint = state.next().unwrap() & mask;
591        }
592        let factor = factor_pp1_u64(n, b1, randint + 3);
593        if factor != 0 {
594            return factor;
595        }
596    }
597    0
598}
599
600// This is equivalent to `mpn_sqrtrem` from `mpn/generic/sqrtrem.c`, GMP 6.2.1, where `rp` is not
601// `NULL` and `Limb == u64`, and the input has two limbs. One limb of the square root and two limbs
602// of the remainder are returned.
603#[doc(hidden)]
604fn limbs_sqrt_rem_to_out_u64(xs_hi: u64, xs_lo: u64) -> (u64, u64, u64, usize) {
605    let high = if xs_hi == 0 { xs_lo } else { xs_hi };
606    assert_ne!(high, 0);
607    let shift = LeadingZeros::leading_zeros(high) >> 1;
608    let two_shift = shift << 1;
609    if xs_hi == 0 {
610        let (sqrt_lo, rem_lo) = if shift == 0 {
611            sqrt_rem_newton::<u64, i64>(high)
612        } else {
613            let sqrt = sqrt_rem_newton::<u64, i64>(high << two_shift).0 >> shift;
614            (sqrt, high - sqrt.square())
615        };
616        (sqrt_lo, 0, rem_lo, usize::from(rem_lo != 0))
617    } else if shift == 0 {
618        let (sqrt_lo, rem_hi, rem_lo) = sqrt_rem_2_newton::<u64, i64>(xs_hi, xs_lo);
619        if rem_hi {
620            (sqrt_lo, 1, rem_lo, 2)
621        } else {
622            (sqrt_lo, 0, rem_lo, usize::from(rem_lo != 0))
623        }
624    } else {
625        let mut lo = xs_lo;
626        let hi = (high << two_shift) | (lo >> (u64::WIDTH - two_shift));
627        let sqrt_lo = sqrt_rem_2_newton::<u64, i64>(hi, lo << two_shift).0 >> shift;
628        lo.wrapping_sub_assign(sqrt_lo.wrapping_square());
629        (sqrt_lo, 0, lo, usize::from(lo != 0))
630    }
631}
632
633const FACTOR_SQUFOF_ITERS: usize = 50_000;
634const FACTOR_ONE_LINE_ITERS: usize = 40_000;
635
636// This is _ll_factor_SQUFOF when FLINT64 is true, from ulong_extras/factor_SQUFOF.c, FLINT 3.1.2.
637fn ll_factor_squfof_u64(n_hi: u64, n_lo: u64, max_iters: usize) -> u64 {
638    let (mut sqrt_lo, mut rem_lo, num) = if n_hi != 0 {
639        let (sqrt_lo, _, rem_lo, size) = limbs_sqrt_rem_to_out_u64(n_hi, n_lo);
640        (sqrt_lo, rem_lo, size)
641    } else {
642        let (sqrt_lo, rem_lo) = n_lo.sqrt_rem();
643        (sqrt_lo, rem_lo, usize::from(sqrt_lo != 0))
644    };
645    let sqroot = sqrt_lo;
646    let mut p = sqroot;
647    let mut q = rem_lo;
648    if q == 0 || num == 0 {
649        return sqroot;
650    }
651    let l = 1 + ((p << 1).floor_sqrt() << 1);
652    let l2 = l >> 1;
653    let mut qupto = 0;
654    let mut qlast = 1u64;
655    let mut qarr = [0; 50];
656    let mut r = 0;
657    let mut finished_loop = true;
658    for i in 0..max_iters {
659        let iq = (sqroot + p) / q;
660        let pnext = iq * q - p;
661        if q <= l {
662            if q.even() {
663                qarr[qupto] = q >> 1;
664                qupto += 1;
665                if qupto >= 50 {
666                    return 0;
667                }
668            } else if q <= l2 {
669                qarr[qupto] = q;
670                qupto += 1;
671                if qupto >= 50 {
672                    return 0;
673                }
674            }
675        }
676        let t = qlast.wrapping_add(iq.wrapping_mul(p.wrapping_sub(pnext)));
677        qlast = q;
678        q = t;
679        p = pnext;
680        if i.odd() || !is_square_u64(q) {
681            continue;
682        }
683        r = q.floor_sqrt();
684        if qupto == 0 {
685            finished_loop = false;
686            break;
687        }
688        let mut done = true;
689        for &q in &qarr[..qupto] {
690            if r == q {
691                done = false;
692                break;
693            }
694        }
695        if done {
696            finished_loop = false;
697            break;
698        }
699        if r == 1 {
700            return 0;
701        }
702    }
703    if finished_loop {
704        return 0;
705    }
706    qlast = r;
707    p = p + r * ((sqroot - p) / r);
708    let rem_hi;
709    (rem_hi, rem_lo) = u64::x_mul_y_to_zz(p, p);
710    let sqrt_hi;
711    (sqrt_hi, sqrt_lo) = u64::xx_sub_yy_to_zz(n_hi, n_lo, rem_hi, rem_lo);
712    q = if sqrt_hi != 0 {
713        let norm = LeadingZeros::leading_zeros(qlast);
714        u64::xx_div_mod_y_to_qr(
715            (sqrt_hi << norm) + (sqrt_lo >> (u64::WIDTH - norm)),
716            sqrt_lo << norm,
717            qlast << norm,
718        )
719        .0
720    } else {
721        sqrt_lo / qlast
722    };
723    let mut finished_loop = true;
724    for _ in 0..max_iters {
725        let iq = (sqroot + p) / q;
726        let pnext = iq * q - p;
727        if p == pnext {
728            finished_loop = false;
729            break;
730        }
731        let t = qlast.wrapping_add(iq.wrapping_mul(p.wrapping_sub(pnext)));
732        qlast = q;
733        q = t;
734        p = pnext;
735    }
736    if finished_loop {
737        0
738    } else if q.even() {
739        q >> 1
740    } else {
741        q
742    }
743}
744
745// This is n_factor_SQUFOF when FLINT64 is true, from ulong_extras/factor_SQUFOF.c, FLINT 3.1.2.
746fn factor_squfof_u64(n: u64, iters: usize) -> u64 {
747    let mut factor = ll_factor_squfof_u64(0, n, iters);
748    let mut finished_loop = true;
749    for &p in &SMALL_PRIMES[1..] {
750        if factor != 0 {
751            finished_loop = false;
752            break;
753        }
754        let multiplier = u64::from(p);
755        let (multn_1, multn_0) = u64::x_mul_y_to_zz(multiplier, n);
756        factor = ll_factor_squfof_u64(multn_1, multn_0, iters);
757        if factor != 0 {
758            let (quot, rem) = factor.div_mod(multiplier);
759            if rem == 0 {
760                factor = quot;
761            }
762            if factor == 1 || factor == n {
763                factor = 0;
764            }
765        }
766    }
767    if finished_loop { 0 } else { factor }
768}
769
770const FACTOR_TRIAL_PRIMES: usize = 3000;
771const FACTOR_TRIAL_CUTOFF: u32 = 27449 * 27449;
772
773impl Factor for u8 {
774    type FACTORS = FactorsU8;
775
776    /// Returns the prime factorization of a `u8`. The return value is iterable, and produces pairs
777    /// $(p,e)$ of type `(u8, u8)`, where the $p$ is prime and $e$ is the exponent of $p$. The
778    /// primes are in ascending order.
779    ///
780    /// # Worst-case complexity
781    /// Constant time and additional memory.
782    ///
783    /// # Panics
784    /// Panics if `self` is 0.
785    ///
786    /// # Examples
787    /// ```
788    /// use itertools::Itertools;
789    /// use malachite_base::num::factorization::traits::Factor;
790    ///
791    /// assert_eq!(251u8.factor().into_iter().collect_vec(), &[(251, 1)]);
792    /// assert_eq!(
793    ///     120u8.factor().into_iter().collect_vec(),
794    ///     &[(2, 3), (3, 1), (5, 1)]
795    /// );
796    /// ```
797    fn factor(&self) -> FactorsU8 {
798        assert_ne!(*self, 0);
799        let mut n = *self;
800        let mut factors = FactorsU8::new();
801        if n == 1 {
802            return factors;
803        }
804        let zeros = n.trailing_zeros();
805        if zeros != 0 {
806            factors.insert(2, zeros as u8);
807            n >>= zeros;
808            if n == 1 {
809                return factors;
810            }
811        }
812        let mut e;
813        let (q, r) = n.div_mod(3);
814        if r == 0 {
815            e = 1;
816            n = q;
817            let (q, r) = n.div_mod(3);
818            if r == 0 {
819                e = 2;
820                n = q;
821                let (q, r) = n.div_mod(3);
822                if r == 0 {
823                    e = 3;
824                    n = q;
825                    let (q, r) = n.div_mod(3);
826                    if r == 0 {
827                        e = 4;
828                        n = q;
829                        if n == 3 {
830                            e = 5;
831                            n = 1;
832                        }
833                    }
834                }
835            }
836            factors.insert(3, e);
837            if n == 1 {
838                return factors;
839            }
840        }
841        let (q, r) = n.div_mod(5);
842        if r == 0 {
843            e = 1;
844            n = q;
845            let (q, r) = n.div_mod(5);
846            if r == 0 {
847                e = 2;
848                n = q;
849                if n == 5 {
850                    e = 3;
851                    n = 1;
852                }
853            }
854            factors.insert(5, e);
855            if n == 1 {
856                return factors;
857            }
858        }
859        let (q, r) = n.div_mod(7);
860        if r == 0 {
861            e = 1;
862            n = q;
863            if n == 7 {
864                e = 2;
865                n = 1;
866            }
867            factors.insert(7, e);
868            if n == 1 {
869                return factors;
870            }
871        }
872        match n {
873            121 => {
874                factors.insert(11, 2);
875            }
876            143 => {
877                factors.insert(11, 1);
878                factors.insert(13, 1);
879            }
880            169 => {
881                factors.insert(13, 2);
882            }
883            187 => {
884                factors.insert(11, 1);
885                factors.insert(17, 1);
886            }
887            209 => {
888                factors.insert(11, 1);
889                factors.insert(19, 1);
890            }
891            221 => {
892                factors.insert(13, 1);
893                factors.insert(17, 1);
894            }
895            247 => {
896                factors.insert(13, 1);
897                factors.insert(19, 1);
898            }
899            253 => {
900                factors.insert(11, 1);
901                factors.insert(23, 1);
902            }
903            _ => {
904                factors.insert(n, 1);
905            }
906        }
907        factors
908    }
909}
910
911impl Factor for u16 {
912    type FACTORS = FactorsU16;
913
914    /// Returns the prime factorization of a `u16`. The return value is iterable, and produces pairs
915    /// $(p,e)$ of type `(u16, u8)`, where the $p$ is prime and $e$ is the exponent of $p$. The
916    /// primes are in ascending order.
917    ///
918    /// # Worst-case complexity
919    /// $T(n) = O(2^{n/4})$
920    ///
921    /// $M(n) = O(2^n)$
922    ///
923    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
924    ///
925    /// # Panics
926    /// Panics if `self` is 0.
927    ///
928    /// # Examples
929    /// ```
930    /// use itertools::Itertools;
931    /// use malachite_base::num::factorization::traits::Factor;
932    ///
933    /// assert_eq!(65521u16.factor().into_iter().collect_vec(), &[(65521, 1)]);
934    /// assert_eq!(
935    ///     40320u16.factor().into_iter().collect_vec(),
936    ///     &[(2, 7), (3, 2), (5, 1), (7, 1)]
937    /// );
938    /// ```
939    fn factor(&self) -> FactorsU16 {
940        let mut factors = FactorsU16::new();
941        for (f, e) in u32::from(*self).factor() {
942            factors.insert(f as u16, e);
943        }
944        factors
945    }
946}
947
948impl Factor for u32 {
949    type FACTORS = FactorsU32;
950
951    /// Returns the prime factorization of a `u32`. The return value is iterable, and produces pairs
952    /// $(p,e)$ of type `(u32, u8)`, where the $p$ is prime and $e$ is the exponent of $p$. The
953    /// primes are in ascending order.
954    ///
955    /// # Worst-case complexity
956    /// $T(n) = O(2^{n/4})$
957    ///
958    /// $M(n) = O(2^n)$
959    ///
960    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
961    ///
962    /// # Panics
963    /// Panics if `self` is 0.
964    ///
965    /// # Examples
966    /// ```
967    /// use itertools::Itertools;
968    /// use malachite_base::num::factorization::traits::Factor;
969    ///
970    /// assert_eq!(
971    ///     4294967291u32.factor().into_iter().collect_vec(),
972    ///     &[(4294967291, 1)]
973    /// );
974    /// assert_eq!(
975    ///     479001600u32.factor().into_iter().collect_vec(),
976    ///     &[(2, 10), (3, 5), (5, 2), (7, 1), (11, 1)]
977    /// );
978    /// ```
979    ///
980    /// This is n_factor when FLINT64 is false, from ulong_extras/factor.c, FLINT 3.1.2.
981    fn factor(&self) -> FactorsU32 {
982        let n = *self;
983        assert_ne!(n, 0);
984        let mut factors = FactorsU32::new();
985        let cofactor = factor_trial_range_u32(&mut factors, n, FACTOR_TRIAL_PRIMES);
986        if cofactor == 1 {
987            return factors;
988        }
989        if cofactor.is_prime() {
990            factors.insert(cofactor, 1);
991            return factors;
992        }
993        let mut factor_arr = [0; MAX_FACTORS_IN_U32];
994        let mut exp_arr = [0; MAX_FACTORS_IN_U32];
995        factor_arr[0] = cofactor;
996        let mut factors_left = 1;
997        exp_arr[0] = 1;
998        let cutoff = FACTOR_TRIAL_CUTOFF;
999        while factors_left != 0 {
1000            let mut factor = factor_arr[factors_left - 1];
1001            if factor >= cutoff {
1002                let (mut cofactor, exp) = factor_square_u32(factor);
1003                if cofactor != 0 {
1004                    exp_arr[factors_left - 1] *= exp;
1005                    factor = cofactor;
1006                    factor_arr[factors_left - 1] = factor;
1007                }
1008                if factor >= cutoff && !factor.is_prime() {
1009                    cofactor = u32::exact_from(factor_one_line_u64(
1010                        u64::from(factor),
1011                        FACTOR_ONE_LINE_ITERS,
1012                    ));
1013                    exp_arr[factors_left] = exp_arr[factors_left - 1];
1014                    factor_arr[factors_left] = cofactor;
1015                    factor_arr[factors_left - 1] /= cofactor;
1016                    factors_left += 1;
1017                } else {
1018                    factors.insert(factor, exp_arr[factors_left - 1]);
1019                    factors_left -= 1;
1020                }
1021            } else {
1022                factors.insert(factor, exp_arr[factors_left - 1]);
1023                factors_left -= 1;
1024            }
1025        }
1026        factors
1027    }
1028}
1029
1030const FACTOR_ONE_LINE_MAX: u64 = 1 << 39;
1031
1032impl Factor for u64 {
1033    type FACTORS = FactorsU64;
1034
1035    /// Returns the prime factorization of a `u64`. The return value is iterable, and produces pairs
1036    /// $(p,e)$ of type `(u64, u8)`, where the $p$ is prime and $e$ is the exponent of $p$. The
1037    /// primes are in ascending order.
1038    ///
1039    /// # Worst-case complexity
1040    /// $T(n) = O(2^{n/4})$
1041    ///
1042    /// $M(n) = O(2^n)$
1043    ///
1044    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
1045    ///
1046    /// # Panics
1047    /// Panics if `self` is 0.
1048    ///
1049    /// # Examples
1050    /// ```
1051    /// use itertools::Itertools;
1052    /// use malachite_base::num::factorization::traits::Factor;
1053    ///
1054    /// assert_eq!(
1055    ///     18446744073709551557u64.factor().into_iter().collect_vec(),
1056    ///     &[(18446744073709551557, 1)]
1057    /// );
1058    /// assert_eq!(
1059    ///     2432902008176640000u64.factor().into_iter().collect_vec(),
1060    ///     &[(2, 18), (3, 8), (5, 4), (7, 2), (11, 1), (13, 1), (17, 1), (19, 1)]
1061    /// );
1062    /// ```
1063    ///
1064    /// This is n_factor when FLINT64 is true, from ulong_extras/factor.c, FLINT 3.1.2.
1065    fn factor(&self) -> FactorsU64 {
1066        let n = *self;
1067        assert_ne!(n, 0);
1068        let mut factors = FactorsU64::new();
1069        let cofactor = factor_trial_range_u64(&mut factors, n, FACTOR_TRIAL_PRIMES);
1070        if cofactor == 1 {
1071            return factors;
1072        }
1073        if cofactor.is_prime() {
1074            factors.insert(cofactor, 1);
1075            return factors;
1076        }
1077        let mut factor_arr = [0; MAX_FACTORS_IN_U64];
1078        let mut exp_arr = [0; MAX_FACTORS_IN_U64];
1079        factor_arr[0] = cofactor;
1080        let mut factors_left = 1;
1081        exp_arr[0] = 1;
1082        const CUTOFF: u64 = FACTOR_TRIAL_CUTOFF as u64;
1083        while factors_left != 0 {
1084            let mut factor = factor_arr[factors_left - 1];
1085            if factor >= CUTOFF {
1086                let (mut cofactor, exp) = factor_power23_u64(factor);
1087                if cofactor != 0 {
1088                    exp_arr[factors_left - 1] *= exp;
1089                    factor = cofactor;
1090                    factor_arr[factors_left - 1] = factor;
1091                }
1092                if factor >= CUTOFF && !factor.is_prime() {
1093                    cofactor = 0;
1094                    if factor < FACTOR_ONE_LINE_MAX {
1095                        cofactor = factor_one_line_u64(factor, FACTOR_ONE_LINE_ITERS);
1096                    }
1097                    if cofactor == 0 {
1098                        cofactor = factor_pp1_wrapper_u64(factor);
1099                        if cofactor == 0 {
1100                            cofactor = factor_squfof_u64(factor, FACTOR_SQUFOF_ITERS);
1101                            assert_ne!(cofactor, 0);
1102                        }
1103                    }
1104                    exp_arr[factors_left] = exp_arr[factors_left - 1];
1105                    factor_arr[factors_left] = cofactor;
1106                    factor_arr[factors_left - 1] /= cofactor;
1107                    factors_left += 1;
1108                } else {
1109                    factors.insert(factor, exp_arr[factors_left - 1]);
1110                    factors_left -= 1;
1111                }
1112            } else {
1113                factors.insert(factor, exp_arr[factors_left - 1]);
1114                factors_left -= 1;
1115            }
1116        }
1117        factors
1118    }
1119}
1120
1121impl Factor for usize {
1122    type FACTORS = FactorsUsize;
1123
1124    /// Returns the prime factorization of a `usize`. The return value is iterable, and produces
1125    /// pairs $(p,e)$ of type `(usize, u8)`, where the $p$ is prime and $e$ is the exponent of $p$.
1126    /// The primes are in ascending order.
1127    ///
1128    /// # Worst-case complexity
1129    /// $T(n) = O(2^{n/4})$
1130    ///
1131    /// $M(n) = O(2^n)$
1132    ///
1133    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
1134    ///
1135    /// # Panics
1136    /// Panics if `self` is 0.
1137    ///
1138    /// # Examples
1139    /// ```
1140    /// use itertools::Itertools;
1141    /// use malachite_base::num::factorization::traits::Factor;
1142    ///
1143    /// assert_eq!(
1144    ///     4294967291usize.factor().into_iter().collect_vec(),
1145    ///     &[(4294967291, 1)]
1146    /// );
1147    /// assert_eq!(
1148    ///     479001600usize.factor().into_iter().collect_vec(),
1149    ///     &[(2, 10), (3, 5), (5, 2), (7, 1), (11, 1)]
1150    /// );
1151    /// ```
1152    fn factor(&self) -> FactorsUsize {
1153        let mut factors = FactorsUsize::new();
1154        if USIZE_IS_U32 {
1155            for (f, e) in (*self as u32).factor() {
1156                factors.insert(f as usize, e);
1157            }
1158        } else {
1159            for (f, e) in (*self as u64).factor() {
1160                factors.insert(f as usize, e);
1161            }
1162        }
1163        factors
1164    }
1165}