File Coverage

lucas_seq.c
Criterion Covered Total %
statement 190 195 97.4
branch 148 174 85.0
condition n/a
subroutine n/a
pod n/a
total 338 369 91.6


line stmt bran cond sub pod time code
1             #include
2             #include
3             #include
4             #include
5              
6             #include "ptypes.h"
7             #include "lucas_seq.h"
8             #include "mulmod.h"
9             #include "util.h"
10              
11             /* TODO: primality.c might be able to call these more often */
12              
13             /* TODO: montmath version of fastest, e.g. lucasvmod */
14              
15              
16              
17             /******************************************************************************/
18              
19             /* Alternate modular lucas sequence code.
20             * A bit slower than the normal one, but works with even valued n. */
21 26373           static void alt_lucas_seq(UV* Uret, UV* Vret, UV n, UV Pmod, UV Qmod, UV k)
22             {
23             UV Uh, Vl, Vh, Ql, Qh;
24             int j, s, m;
25              
26 26373           Uh = 1; Vl = 2; Vh = Pmod; Ql = 1; Qh = 1;
27 26373           s = 0; m = 0;
28 78548 100         { UV v = k; while (!(v & 1)) { v >>= 1; s++; } }
29 392659 100         { UV v = k; while (v >>= 1) m++; }
30              
31 26373 100         if (Pmod == 1 && Qmod == (n-1)) {
    50          
32 26357           int Sl = Ql, Sh = Qh;
33 340423 100         for (j = m; j > s; j--) {
34 314066           Sl *= Sh;
35 314066 100         Ql = (Sl==1) ? 1 : n-1;
36 314066 100         if ( (k >> j) & UVCONST(1) ) {
37 169406           Sh = -Sl;
38 169406           Uh = mulmod(Uh, Vh, n);
39 169406           Vl = submod(mulmod(Vh, Vl, n), Ql, n);
40 169406 100         Vh = submod(sqrmod(Vh, n), (Sh==1) ? 2 : n-2, n);
41             } else {
42 144660           Sh = Sl;
43 144660           Uh = submod(mulmod(Uh, Vl, n), Ql, n);
44 144660           Vh = submod(mulmod(Vh, Vl, n), Ql, n);
45 144660 100         Vl = submod(sqrmod(Vl, n), (Sl==1) ? 2 : n-2, n);
46             }
47             }
48 26357           Sl *= Sh;
49 26357 100         Ql = (Sl==1) ? 1 : n-1;
50 26357           Uh = submod(mulmod(Uh, Vl, n), Ql, n);
51 26357           Vl = submod(mulmod(Vh, Vl, n), Ql, n);
52 78507 100         for (j = 0; j < s; j++) {
53 52150           Uh = mulmod(Uh, Vl, n);
54 52150 100         Vl = submod(sqrmod(Vl, n), (j>0) ? 2 : n-2, n);
55             }
56 26357           *Uret = Uh;
57 26357           *Vret = Vl;
58 26357           return;
59             }
60              
61 61 100         for (j = m; j > s; j--) {
62 45           Ql = mulmod(Ql, Qh, n);
63 45 100         if ( (k >> j) & UVCONST(1) ) {
64 19           Qh = mulmod(Ql, Qmod, n);
65 19           Uh = mulmod(Uh, Vh, n);
66 19           Vl = submod(mulmod(Vh, Vl, n), mulmod(Pmod, Ql, n), n);
67 19           Vh = submod(sqrmod(Vh, n), addmod(Qh,Qh,n), n);
68             } else {
69 26           Qh = Ql;
70 26           Uh = submod(mulmod(Uh, Vl, n), Ql, n);
71 26           Vh = submod(mulmod(Vh, Vl, n), mulmod(Pmod, Ql, n), n);
72 26           Vl = submod(sqrmod(Vl, n), addmod(Ql, Ql, n), n);
73             }
74             }
75 16           Ql = mulmod(Ql, Qh, n);
76 16           Qh = mulmod(Ql, Qmod, n);
77 16           Uh = submod(mulmod(Uh, Vl, n), Ql, n);
78 16           Vl = submod(mulmod(Vh, Vl, n), mulmod(Pmod, Ql, n), n);
79 16           Ql = mulmod(Ql, Qh, n);
80 41 100         for (j = 0; j < s; j++) {
81 25           Uh = mulmod(Uh, Vl, n);
82 25           Vl = submod(sqrmod(Vl, n), addmod(Ql, Ql, n), n);
83 25           Ql = sqrmod(Ql, n);
84             }
85 16           *Uret = Uh;
86 16           *Vret = Vl;
87             }
88              
89             /* Generic Lucas sequence for any appropriate P and Q */
90 0           void lucas_seq(UV* Uret, UV* Vret, UV* Qkret, UV n, IV P, IV Q, UV k)
91             {
92 0 0         MPUassert(n > 0, "lucas_sequence: modulus n must be > 0");
93 0 0         if (n == 1) { *Uret = *Vret = *Qkret = 0; return; }
94              
95 0           lucasuvmod(Uret, Vret, ivmod(P,n), ivmod(Q,n), k, n);
96 0           *Qkret = powmod(ivmod(Q,n), k, n);
97             }
98              
99              
100 26791           void lucasuvmod(UV* Uret, UV* Vret, UV P, UV Q, UV k, UV n)
101             {
102             UV U, V, b, D, invD;
103              
104 26791 50         MPUassert(n > 0, "lucasuvmod: modulus n must be > 0");
105 26850 100         if (n == 1) { *Uret = *Vret = 0; return; }
106              
107 26789 100         if (k == 0) {
108 32           *Uret = 0;
109 32           *Vret = 2 % n;
110 32           return;
111             }
112              
113 26757 50         if (P >= n) P %= n;
114 26757 50         if (Q >= n) Q %= n;
115 26757           D = submod( mulmod(P, P, n), mulmod(4, Q, n), n);
116              
117 26757 100         if (D == 0 && (b = divmod(P,2,n)) != 0) {
    100          
118 27           *Uret = mulmod(k, powmod(b, k-1, n), n);
119 27           *Vret = mulmod(2, powmod(b, k, n), n);
120 27           return;
121             }
122              
123 394433 100         { UV v = k; b = 0; while (v >>= 1) b++; }
124 26730           U = 1;
125 26730           V = P;
126 26730           invD = modinverse(D, n);
127              
128 26730 100         if (Q == 1 && invD != 0) { /* Inverting D: 2 mulmods/bit instead of 2-5 */
    100          
129 12           U = mulsubmod(P,P,2,n);
130 85 100         while (b--) {
131 73           UV T = mulsubmod(U, V, P, n);
132 73 100         if ( (k >> b) & UVCONST(1) ) {
133 22           V = T;
134 22           U = mulsubmod(U, U, 2, n);
135             } else {
136 51           U = T;
137 51           V = mulsubmod(V, V, 2, n);
138             }
139             }
140 12           U = addmod(U,U,n);
141 12           U = submod(U, mulmod(V,P,n), n);
142 12           U = mulmod(U, invD, n);
143 26718 100         } else if (P == 1 && Q == (n-1)) { /* code for P=1 Q=-1 in here */
    100          
144 26356           alt_lucas_seq(&U, &V, n, P, Q, k);
145 523 100         } else if ((n & 1) && (Q == 1 || (Q == (n-1)))) {
    100          
    100          
146 161           int qs = (Q==1);
147 863 100         while (b--) {
148 702           U = mulmod(U, V, n);
149 702 100         V = muladdmod(V, V, (qs) ? n-2 : 2, n);
150 702           qs = 1;
151 702 100         if ( (k >> b) & UVCONST(1) ) {
152 327           UV t2 = mulmod(U, D, n);
153 327 50         if (P != 1) U = mulmod(U, P, n);
154 327           U = addmod(U, V, n);
155 327 100         if (U & 1) { U = (n>>1) + (U>>1) + 1; } else { U >>= 1; }
156 327 50         if (P != 1) V = mulmod(V, P, n);
157 327           V = addmod(V, t2, n);
158 327 100         if (V & 1) { V = (n>>1) + (V>>1) + 1; } else { V >>= 1; }
159 327           qs = (Q==1);
160             }
161             }
162 201 100         } else if (n & 1) {
163 187           UV Qk = Q;
164 862 100         while (b--) {
165 675           U = mulmod(U, V, n);
166 675           V = mulsubmod(V, V, addmod(Qk,Qk,n), n);
167 675           Qk = sqrmod(Qk, n);
168 675 100         if ( (k >> b) & UVCONST(1) ) {
169 296           UV t2 = mulmod(U, D, n);
170 296           U = muladdmod(U, P, V, n);
171 296 100         if (U & 1) { U = (n>>1) + (U>>1) + 1; } else { U >>= 1; }
172 296           V = muladdmod(V, P, t2, n);
173 296 100         if (V & 1) { V = (n>>1) + (V>>1) + 1; } else { V >>= 1; }
174 296           Qk = mulmod(Qk, Q, n);
175             }
176             }
177             } else {
178             /* This handles everything */
179 14           alt_lucas_seq(&U, &V, n, P, Q, k);
180             }
181 26730           *Uret = U;
182 26730           *Vret = V;
183             }
184              
185 227           UV lucasvmod(UV P, UV Q, UV k, UV n)
186             {
187             UV D, b, U, V, Qk;
188              
189 227 50         MPUassert(n > 0, "lucas_sequence: modulus n must be > 0");
190 227 50         if (n == 1) return 0;
191 227 100         if (k == 0) return 2 % n;
192 226 50         if (P >= n) P = P % n;
193 226 50         if (Q >= n) Q = Q % n;
194              
195 226           D = submod(mulmod(P, P, n), mulmod(4, Q, n), n);
196 226 100         if (D == 0 && (b = divmod(P,2,n)) != 0)
    100          
197 5           return mulmod(2, powmod(b, k, n), n);
198              
199 1698 100         { UV v = k; b = 0; while (v >>= 1) b++; }
200              
201 221 100         if (Q == 1) {
202              
203 106           V = P;
204 106           U = mulsubmod(P, P, 2, n);
205 864 100         while (b--) {
206 758           UV T = mulsubmod(U, V, P, n);
207 758 100         if ( (k >> b) & UVCONST(1) ) {
208 395           V = T;
209 395           U = mulsubmod(U, U, 2, n);
210             } else {
211 363           U = T;
212 363           V = mulsubmod(V, V, 2, n);
213             }
214             }
215              
216 115 100         } else if ((n % 2) == 0) {
217              
218 3           alt_lucas_seq(&U, &V, n, P, Q, k);
219              
220             } else {
221              
222 112           U = 1;
223 112           V = P;
224 112           Qk = Q;
225 798 100         while (b--) {
226 686           U = mulmod(U, V, n);
227 686           V = mulsubmod(V, V, addmod(Qk,Qk,n), n);
228 686           Qk = sqrmod(Qk, n);
229 686 100         if ( (k >> b) & UVCONST(1) ) {
230 326           UV t2 = mulmod(U, D, n);
231 326           U = muladdmod(U, P, V, n);
232 326 100         if (U & 1) { U = (n>>1) + (U>>1) + 1; } else { U >>= 1; }
233 326           V = muladdmod(V, P, t2, n);
234 326 100         if (V & 1) { V = (n>>1) + (V>>1) + 1; } else { V >>= 1; }
235 326           Qk = mulmod(Qk, Q, n);
236             }
237             }
238              
239             }
240 221           return V;
241             }
242              
243 26258           UV lucasumod(UV P, UV Q, UV k, UV n)
244             {
245             UV U, V;
246 26258           lucasuvmod(&U, &V, P, Q, k, n);
247 26258           return U;
248             }
249              
250              
251              
252              
253             #define OVERHALF(v) ( (UV)((v>=0)?v:-v) > (UVCONST(1) << (BITS_PER_WORD/2-1)) )
254 693           bool lucasuv(IV* U, IV *V, IV P, IV Q, UV k)
255             {
256             IV Uh, Vl, Vh, Ql, Qh;
257             int j, s, n;
258              
259 693 100         if (k == 0) {
260 28 50         if (U) *U = 0;
261 28 50         if (V) *V = 2;
262 28           return 1;
263             }
264              
265 665           Uh = 1; Vl = 2; Vh = P; Ql = 1; Qh = 1;
266 665           s = 0; n = 0;
267 1243 100         { UV v = k; while (!(v & 1)) { v >>= 1; s++; } }
268 3034 100         { UV v = k; while (v >>= 1) n++; }
269              
270 2399 100         for (j = n; j > s; j--) {
271 1761 100         if (OVERHALF(Uh) || OVERHALF(Vh) || OVERHALF(Vl) || OVERHALF(Ql) || OVERHALF(Qh)) return 0;
    100          
    50          
    50          
    50          
272 1734           Ql *= Qh;
273 1734 100         if ( (k >> j) & UVCONST(1) ) {
274 1034           Qh = Ql * Q;
275 1034           Uh = Uh * Vh;
276 1034           Vl = Vh * Vl - P * Ql;
277 1034           Vh = Vh * Vh - 2 * Qh;
278             } else {
279 700           Qh = Ql;
280 700           Uh = Uh * Vl - Ql;
281 700           Vh = Vh * Vl - P * Ql;
282 700           Vl = Vl * Vl - 2 * Ql;
283             }
284             }
285 638 100         if (OVERHALF(Ql) || OVERHALF(Qh)) return 0;
    50          
286 635           Ql = Ql * Qh;
287 635           Qh = Ql * Q;
288 635 100         if (OVERHALF(Uh) || OVERHALF(Vh) || OVERHALF(Vl) || OVERHALF(Ql) || OVERHALF(Qh)) return 0;
    100          
    50          
    50          
    50          
289 617           Uh = Uh * Vl - Ql;
290 617           Vl = Vh * Vl - P * Ql;
291 617           Ql = Ql * Qh;
292 1159 100         for (j = 0; j < s; j++) {
293 566 100         if (OVERHALF(Uh) || OVERHALF(Vl) || OVERHALF(Ql)) return 0;
    100          
    50          
294 542           Uh *= Vl;
295 542           Vl = Vl * Vl - 2 * Ql;
296 542           Ql *= Ql;
297             }
298 593 50         if (U) *U = Uh;
299 593 50         if (V) *V = Vl;
300 593           return 1;
301             }