-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmodular_lucas_sequence_V.sf
68 lines (47 loc) · 1.52 KB
/
modular_lucas_sequence_V.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
#!/usr/bin/ruby
# Algorithm due to Aleksey Koval for efficiently computing the modular Lucas V sequence.
# See also:
# https://en.wikipedia.org/wiki/Lucas_sequence
# https://file.scirp.org/pdf/IJCNS20101200011_90376712.pdf
func lucasVmod(P, Q, n, m) {
var(V1 = 2, V2 = P)
var(Q1 = 1, Q2 = 1)
var s = n.valuation(2)
for bit in ((n>>(s+1)).as_bin.chars) {
Q1 = mulmod(Q1, Q2, m)
if (bit) {
Q2 = mulmod(Q1, Q, m)
V1 = mulsubmulmod(V2, V1, P, Q1, m)
V2 = mulsubmulmod(V2, V2, 2, Q2, m)
}
else {
Q2 = Q1
V2 = mulsubmulmod(V2, V1, P, Q1, m)
V1 = mulsubmulmod(V1, V1, 2, Q2, m)
}
}
Q1 = mulmod(Q1, Q2, m)
Q2 = mulmod(Q1, Q, m)
V1 = mulsubmulmod(V2, V1, P, Q1, m)
Q1 = mulmod(Q1, Q2, m)
s.times {
V1 = mulsubmulmod(V1, V1, 2, Q1, m)
Q1 = mulmod(Q1, Q1, m)
}
return V1
}
#--------------------------------------------------------
say {|n| lucasVmod(1, -1, n, n) }.map(1..30) # Lucas(n) modulo n
say 25.by {|n| lucasVmod(1, -1, n, n) == 1 } # First 25 prime numbers
#--------------------------------------------------------
for k in (1..20) { # run some tests
var p = 1e30.random_prime
assert_eq(lucasVmod(1, -1, p, p), 1)
var n = 1e30.irand
var m = 1e30.irand
var P = (100.irand * [-1,1].rand)
var Q = (100.irand * [-1,1].rand)
var V1 = lucasVmod(P, Q, n, m)
var V2 = ::LucasVmod(P, Q, n, m)
assert_eq(V1, V2)
}