-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfermat_factorization_improved.sf
91 lines (69 loc) · 1.93 KB
/
fermat_factorization_improved.sf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#!/usr/bin/ruby
# An improved version of the Fermat's factorization method, combined with the following two identities:
# a = sqrt(a*b - |b-a| * a)
# b = sqrt(a*b + |b-a| * b)
# Example:
# 43 = sqrt(43*97 - (97-43) * 43)
# 97 = sqrt(43*97 + (97-43) * 97)
# When `n+q` or `n-q` is a square, there is a chance that gcd(n, q) is a non-trivial factor of n.
func fermat_factorization_improved (n) {
# Check for primes and negative numbers
return [] if (n <= 1)
return [n] if n.is_prime
# Check for perfect squares
if (n.is_square) {
return (__FUNC__(n.isqrt) * 2 -> sort)
}
# Check for divisibility by 2
if (n.is_even) {
var v = n.valuation(2)
return (v.of(2) + __FUNC__(n >> v))
}
var (a, b) = n.isqrtrem
var p = b
var q = ((a+1)**2 - n)
var g = 1
var t = 1
loop {
# Fermat's factorization method
if (q.is_square) {
var s = q.isqrt
var u = (a + (t+1)/2)
return (
__FUNC__(u + s) +
__FUNC__(u - s) -> sort
)
}
# n+q is a perfect square
g = gcd(n, q)
if (g > 1) {
return (
__FUNC__(g) +
__FUNC__(n/g) -> sort
)
}
# n-p is a perfect square
g = gcd(n, p)
if (g > 1) {
return (
__FUNC__(g) +
__FUNC__(n/g) -> sort
)
}
p += (2*a - t)
q += (2*a + t+2)
t += 2
}
}
for n in ([160587846247027, 5040, 65127835124, 6469693230]) {
var factors = fermat_factorization_improved(n)
say "#{factors.join(' * ')} = #{n}"
assert(factors.all { .is_prime })
assert_eq(factors.prod, n)
}
for n in (2..1000) {
var factors = fermat_factorization_improved(n)
#say "#{factors.join(' * ')} = #{n}"
assert(factors.all { .is_prime })
assert_eq(factors.prod, n)
}