Skip to main content

coreutils_rs/factor/
core.rs

1/// Prime factorization using trial division for small factors and
2/// Pollard's rho algorithm with Miller-Rabin primality testing for larger factors.
3/// Supports numbers up to u128.
4///
5/// Uses a u64 fast path for numbers ≤ u64::MAX (hardware div is ~5x faster
6/// than the software __udivti3 needed for u128).
7///
8/// For numbers ≤ SPF_LIMIT, uses a smallest-prime-factor sieve for O(log n)
9/// factorization — eliminates trial division and Miller-Rabin entirely.
10// Primes up to 251 (54 primes) for Miller-Rabin quick-check.
11const SMALL_PRIMES_U64: [u64; 54] = [
12    2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
13    101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193,
14    197, 199, 211, 223, 227, 229, 233, 239, 241, 251,
15];
16
17// Extended primes for u128 trial division (up to 997, covering sqrt up to ~994009).
18const PRIMES_TO_997: [u64; 168] = [
19    2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
20    101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193,
21    197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307,
22    311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421,
23    431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547,
24    557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
25    661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797,
26    809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929,
27    937, 941, 947, 953, 967, 971, 977, 983, 991, 997,
28];
29
30// ── u64 fast path ────────────────────────────────────────────────────────
31
32/// Modular multiplication for u64 using u128 intermediate.
33#[inline(always)]
34fn mod_mul_u64(a: u64, b: u64, m: u64) -> u64 {
35    ((a as u128) * (b as u128) % (m as u128)) as u64
36}
37
38/// Modular exponentiation for u64.
39#[inline]
40fn mod_pow_u64(mut base: u64, mut exp: u64, m: u64) -> u64 {
41    if m == 1 {
42        return 0;
43    }
44    let mut result: u64 = 1;
45    base %= m;
46    while exp > 0 {
47        if exp & 1 == 1 {
48            result = mod_mul_u64(result, base, m);
49        }
50        exp >>= 1;
51        base = mod_mul_u64(base, base, m);
52    }
53    result
54}
55
56/// Deterministic Miller-Rabin for u64. Uses minimal witness set.
57fn is_prime_u64(n: u64) -> bool {
58    if n < 2 {
59        return false;
60    }
61    if n < 4 {
62        return true;
63    }
64    if n.is_multiple_of(2) || n.is_multiple_of(3) {
65        return false;
66    }
67    for &p in &SMALL_PRIMES_U64[2..15] {
68        if n == p {
69            return true;
70        }
71        if n.is_multiple_of(p) {
72            return false;
73        }
74    }
75    if n < 2809 {
76        return true;
77    }
78
79    let mut d = n - 1;
80    let mut r = 0u32;
81    while d.is_multiple_of(2) {
82        d /= 2;
83        r += 1;
84    }
85
86    let witnesses: &[u64] = if n < 3_215_031_751 {
87        &[2, 3, 5, 7]
88    } else {
89        &[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]
90    };
91
92    'witness: for &a in witnesses {
93        if a >= n {
94            continue;
95        }
96        let mut x = mod_pow_u64(a, d, n);
97        if x == 1 || x == n - 1 {
98            continue;
99        }
100        for _ in 0..r - 1 {
101            x = mod_mul_u64(x, x, n);
102            if x == n - 1 {
103                continue 'witness;
104            }
105        }
106        return false;
107    }
108    true
109}
110
111/// GCD for u64 using binary algorithm.
112fn gcd_u64(mut a: u64, mut b: u64) -> u64 {
113    if a == 0 {
114        return b;
115    }
116    if b == 0 {
117        return a;
118    }
119    let shift = (a | b).trailing_zeros();
120    a >>= a.trailing_zeros();
121    loop {
122        b >>= b.trailing_zeros();
123        if a > b {
124            std::mem::swap(&mut a, &mut b);
125        }
126        b -= a;
127        if b == 0 {
128            break;
129        }
130    }
131    a << shift
132}
133
134/// Pollard's rho for u64 with Brent's variant + batch GCD.
135fn pollard_rho_u64(n: u64) -> u64 {
136    if n.is_multiple_of(2) {
137        return 2;
138    }
139
140    for c_offset in 1u64..n {
141        let c = c_offset;
142        let mut x: u64 = c_offset.wrapping_mul(6364136223846793005).wrapping_add(1) % n;
143        let mut y = x;
144        let mut ys = x;
145        let mut q: u64 = 1;
146        let mut r: u64 = 1;
147        let mut d: u64 = 1;
148
149        while d == 1 {
150            x = y;
151            for _ in 0..r {
152                y = (mod_mul_u64(y, y, n)).wrapping_add(c) % n;
153            }
154            let mut k: u64 = 0;
155            while k < r && d == 1 {
156                ys = y;
157                let m = (r - k).min(128);
158                for _ in 0..m {
159                    y = (mod_mul_u64(y, y, n)).wrapping_add(c) % n;
160                    q = mod_mul_u64(q, x.abs_diff(y), n);
161                }
162                d = gcd_u64(q, n);
163                k += m;
164            }
165            r *= 2;
166        }
167
168        if d == n {
169            loop {
170                ys = (mod_mul_u64(ys, ys, n)).wrapping_add(c) % n;
171                d = gcd_u64(x.abs_diff(ys), n);
172                if d > 1 {
173                    break;
174                }
175            }
176        }
177
178        if d != n {
179            return d;
180        }
181    }
182    n
183}
184
185/// Recursive factorization for u64.
186fn factor_recursive_u64(n: u64, factors: &mut Vec<u128>) {
187    if n <= 1 {
188        return;
189    }
190    if is_prime_u64(n) {
191        factors.push(n as u128);
192        return;
193    }
194    let d = pollard_rho_u64(n);
195    if d == n {
196        let mut d = 2u64;
197        while d * d <= n {
198            if n.is_multiple_of(d) {
199                factor_recursive_u64(d, factors);
200                factor_recursive_u64(n / d, factors);
201                return;
202            }
203            d += 1;
204        }
205        factors.push(n as u128);
206        return;
207    }
208    factor_recursive_u64(d, factors);
209    factor_recursive_u64(n / d, factors);
210}
211
212/// Fast factorization for u64 numbers. Uses hardware div throughout.
213fn factorize_u64(n: u64) -> Vec<u128> {
214    if n <= 1 {
215        return vec![];
216    }
217
218    let mut factors = Vec::new();
219    let mut n = n;
220
221    // Special-case 2: bit shift is faster than hardware div
222    while n & 1 == 0 {
223        factors.push(2);
224        n >>= 1;
225    }
226
227    // Trial division by odd primes 3..997 (covers sqrt up to ~994009)
228    for &p in &PRIMES_TO_997[1..] {
229        if p as u128 * p as u128 > n as u128 {
230            break;
231        }
232        while n.is_multiple_of(p) {
233            factors.push(p as u128);
234            n /= p;
235        }
236    }
237
238    if n > 1 {
239        if n <= 994009 || is_prime_u64(n) {
240            factors.push(n as u128);
241        } else {
242            factor_recursive_u64(n, &mut factors);
243            factors.sort();
244        }
245    }
246
247    factors
248}
249
250// ── u128 path (for numbers > u64::MAX) ───────────────────────────────────
251
252/// Modular multiplication for u128.
253/// Uses schoolbook method (O(128) iterations) which is correct for all u128 values.
254fn mod_mul(a: u128, b: u128, m: u128) -> u128 {
255    // Direct path if product won't overflow
256    if a.leading_zeros() + b.leading_zeros() >= 128 {
257        return (a * b) % m;
258    }
259    mod_mul_schoolbook(a, b, m)
260}
261
262/// Schoolbook modular multiplication (O(128) iterations). Fallback only.
263fn mod_mul_schoolbook(mut a: u128, mut b: u128, m: u128) -> u128 {
264    a %= m;
265    b %= m;
266    let mut result: u128 = 0;
267    while b > 0 {
268        if b & 1 == 1 {
269            result = result.wrapping_add(a);
270            if result >= m {
271                result -= m;
272            }
273        }
274        a <<= 1;
275        if a >= m {
276            a -= m;
277        }
278        b >>= 1;
279    }
280    result
281}
282
283/// Modular exponentiation for u128 using Montgomery form.
284fn mod_pow(base: u128, mut exp: u128, m: u128) -> u128 {
285    if m == 1 {
286        return 0;
287    }
288    let mut result: u128 = 1;
289    let mut b = base % m;
290    while exp > 0 {
291        if exp & 1 == 1 {
292            result = mod_mul_schoolbook(result, b, m);
293        }
294        exp >>= 1;
295        if exp > 0 {
296            b = mod_mul_schoolbook(b, b, m);
297        }
298    }
299    result
300}
301
302/// Deterministic Miller-Rabin primality test for u128.
303fn is_prime_miller_rabin(n: u128) -> bool {
304    if n < 2 {
305        return false;
306    }
307    if n <= u64::MAX as u128 {
308        return is_prime_u64(n as u64);
309    }
310    if n.is_multiple_of(2) || n.is_multiple_of(3) {
311        return false;
312    }
313
314    for &p in &PRIMES_TO_997[3..] {
315        if n == p as u128 {
316            return true;
317        }
318        if n.is_multiple_of(p as u128) {
319            return false;
320        }
321    }
322
323    let mut d = n - 1;
324    let mut r = 0u32;
325    while d.is_multiple_of(2) {
326        d /= 2;
327        r += 1;
328    }
329
330    let witnesses: &[u128] = &[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37];
331
332    'witness: for &a in witnesses {
333        if a >= n {
334            continue;
335        }
336        let mut x = mod_pow(a, d, n);
337        if x == 1 || x == n - 1 {
338            continue;
339        }
340        for _ in 0..r - 1 {
341            x = mod_mul(x, x, n);
342            if x == n - 1 {
343                continue 'witness;
344            }
345        }
346        return false;
347    }
348    true
349}
350
351/// GCD for u128.
352fn gcd(mut a: u128, mut b: u128) -> u128 {
353    if a == 0 {
354        return b;
355    }
356    if b == 0 {
357        return a;
358    }
359    let shift = (a | b).trailing_zeros();
360    a >>= a.trailing_zeros();
361    loop {
362        b >>= b.trailing_zeros();
363        if a > b {
364            std::mem::swap(&mut a, &mut b);
365        }
366        b -= a;
367        if b == 0 {
368            break;
369        }
370    }
371    a << shift
372}
373
374/// Pollard's rho for u128 using Montgomery arithmetic.
375fn pollard_rho(n: u128) -> u128 {
376    if n.is_multiple_of(2) {
377        return 2;
378    }
379
380    for c_offset in 1u128..n {
381        let c = c_offset % n;
382        let mut x: u128 = c_offset.wrapping_mul(6364136223846793005).wrapping_add(1) % n;
383        let mut y = x;
384        let mut ys = x;
385        let mut q: u128 = 1;
386        let mut r: u128 = 1;
387        let mut d: u128 = 1;
388
389        while d == 1 {
390            x = y;
391            for _ in 0..r {
392                y = mod_mul_schoolbook(y, y, n);
393                y = y.wrapping_add(c);
394                if y >= n {
395                    y -= n;
396                }
397            }
398            let mut k: u128 = 0;
399            while k < r && d == 1 {
400                ys = y;
401                let m = (r - k).min(128);
402                for _ in 0..m {
403                    y = mod_mul_schoolbook(y, y, n);
404                    y = y.wrapping_add(c);
405                    if y >= n {
406                        y -= n;
407                    }
408                    q = mod_mul_schoolbook(q, x.abs_diff(y), n);
409                }
410                d = gcd(q, n);
411                k += m;
412            }
413            r *= 2;
414        }
415
416        if d == n {
417            loop {
418                ys = mod_mul_schoolbook(ys, ys, n);
419                ys = ys.wrapping_add(c);
420                if ys >= n {
421                    ys -= n;
422                }
423                d = gcd(x.abs_diff(ys), n);
424                if d > 1 {
425                    break;
426                }
427            }
428        }
429
430        if d != n {
431            return d;
432        }
433    }
434    n
435}
436
437/// Recursively factor n (u128 path).
438fn factor_recursive(n: u128, factors: &mut Vec<u128>) {
439    if n <= 1 {
440        return;
441    }
442    if n <= u64::MAX as u128 {
443        factor_recursive_u64(n as u64, factors);
444        return;
445    }
446    if is_prime_miller_rabin(n) {
447        factors.push(n);
448        return;
449    }
450
451    let mut d = pollard_rho(n);
452    if d == n {
453        d = 2;
454        while d * d <= n {
455            if n.is_multiple_of(d) {
456                break;
457            }
458            d += 1;
459        }
460        if d * d > n {
461            factors.push(n);
462            return;
463        }
464    }
465    factor_recursive(d, factors);
466    factor_recursive(n / d, factors);
467}
468
469// ── Public API ───────────────────────────────────────────────────────────
470
471/// Return the sorted list of prime factors of n (with repetition).
472pub fn factorize(n: u128) -> Vec<u128> {
473    if n <= u64::MAX as u128 {
474        return factorize_u64(n as u64);
475    }
476
477    let mut factors = Vec::new();
478    let mut n = n;
479
480    // Trial division by precomputed primes
481    for &p in &PRIMES_TO_997 {
482        let p128 = p as u128;
483        if p128 * p128 > n {
484            break;
485        }
486        while n.is_multiple_of(p128) {
487            factors.push(p128);
488            n /= p128;
489        }
490    }
491
492    if n > 1 {
493        factor_recursive(n, &mut factors);
494        factors.sort();
495    }
496
497    factors
498}
499
500/// Format a factorization result as "NUMBER: FACTOR FACTOR ..." matching GNU factor output.
501pub fn format_factors(n: u128) -> String {
502    let factors = factorize(n);
503    let mut result = String::with_capacity(64);
504    if n <= u64::MAX as u128 {
505        let mut buf = itoa::Buffer::new();
506        result.push_str(buf.format(n as u64));
507    } else {
508        use std::fmt::Write;
509        let _ = write!(result, "{}", n);
510    }
511    result.push(':');
512    for f in &factors {
513        result.push(' ');
514        if *f <= u64::MAX as u128 {
515            let mut buf = itoa::Buffer::new();
516            result.push_str(buf.format(*f as u64));
517        } else {
518            use std::fmt::Write;
519            let _ = write!(result, "{}", f);
520        }
521    }
522    result
523}
524
525/// Write factorization of a u64 directly to a buffer.
526/// Zero-allocation hot path for the common case (numbers up to 2^64-1).
527pub fn write_factors_u64(n: u64, out: &mut Vec<u8>) {
528    let mut buf = itoa::Buffer::new();
529    out.extend_from_slice(buf.format(n).as_bytes());
530    out.push(b':');
531    if n <= 1 {
532        out.push(b'\n');
533        return;
534    }
535    write_factors_u64_inline(n, out);
536    out.push(b'\n');
537}
538
539/// Write factorization of a u128 to a buffer.
540pub fn write_factors(n: u128, out: &mut Vec<u8>) {
541    if n <= u64::MAX as u128 {
542        write_factors_u64(n as u64, out);
543        return;
544    }
545    let mut buf = itoa::Buffer::new();
546    {
547        use std::fmt::Write;
548        let mut s = String::new();
549        let _ = write!(s, "{}", n);
550        out.extend_from_slice(s.as_bytes());
551    }
552    out.push(b':');
553
554    let factors = factorize(n);
555    for f in &factors {
556        out.push(b' ');
557        if *f <= u64::MAX as u128 {
558            out.extend_from_slice(buf.format(*f as u64).as_bytes());
559        } else {
560            use std::fmt::Write;
561            let mut s = String::new();
562            let _ = write!(s, "{}", *f);
563            out.extend_from_slice(s.as_bytes());
564        }
565    }
566    out.push(b'\n');
567}
568
569/// Inline factoring + direct writing for u64 numbers.
570/// Trial division by precomputed primes, falls back to Pollard's rho for large composites.
571fn write_factors_u64_inline(mut n: u64, out: &mut Vec<u8>) {
572    let mut buf = itoa::Buffer::new();
573
574    // Special-case 2: bit shift is faster than hardware div
575    while n & 1 == 0 {
576        out.extend_from_slice(b" 2");
577        n >>= 1;
578    }
579    if n <= 1 {
580        return;
581    }
582
583    // Trial division by odd primes 3..997 (covers sqrt up to ~994009)
584    // p² ≤ 994009 always fits in u64, so no u128 cast needed
585    for &p in &PRIMES_TO_997[1..] {
586        if p * p > n {
587            break;
588        }
589        while n.is_multiple_of(p) {
590            out.push(b' ');
591            out.extend_from_slice(buf.format(p).as_bytes());
592            n /= p;
593        }
594    }
595
596    if n <= 1 {
597        return;
598    }
599
600    // After trial division by primes up to 997:
601    // - If n <= 994009, it must be prime (no factor ≤ sqrt exists)
602    // - Otherwise, use Miller-Rabin + Pollard's rho
603    if n <= 994009 || is_prime_u64(n) {
604        out.push(b' ');
605        out.extend_from_slice(buf.format(n).as_bytes());
606    } else {
607        let mut factors = Vec::new();
608        factor_recursive_u64(n, &mut factors);
609        factors.sort();
610        for f in &factors {
611            out.push(b' ');
612            out.extend_from_slice(buf.format(*f as u64).as_bytes());
613        }
614    }
615}