strongfibo.c revision 1.1 1 1.1 mrg /* mpn_fib2m -- calculate Fibonacci numbers, modulo m.
2 1.1 mrg
3 1.1 mrg Contributed to the GNU project by Marco Bodrato.
4 1.1 mrg
5 1.1 mrg THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY. THEY'RE ALMOST
6 1.1 mrg CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
7 1.1 mrg FUTURE GNU MP RELEASES.
8 1.1 mrg
9 1.1 mrg Copyright 2001, 2002, 2005, 2009, 2018 Free Software Foundation, Inc.
10 1.1 mrg
11 1.1 mrg This file is part of the GNU MP Library.
12 1.1 mrg
13 1.1 mrg The GNU MP Library is free software; you can redistribute it and/or modify
14 1.1 mrg it under the terms of either:
15 1.1 mrg
16 1.1 mrg * the GNU Lesser General Public License as published by the Free
17 1.1 mrg Software Foundation; either version 3 of the License, or (at your
18 1.1 mrg option) any later version.
19 1.1 mrg
20 1.1 mrg or
21 1.1 mrg
22 1.1 mrg * the GNU General Public License as published by the Free Software
23 1.1 mrg Foundation; either version 2 of the License, or (at your option) any
24 1.1 mrg later version.
25 1.1 mrg
26 1.1 mrg or both in parallel, as here.
27 1.1 mrg
28 1.1 mrg The GNU MP Library is distributed in the hope that it will be useful, but
29 1.1 mrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
30 1.1 mrg or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
31 1.1 mrg for more details.
32 1.1 mrg
33 1.1 mrg You should have received copies of the GNU General Public License and the
34 1.1 mrg GNU Lesser General Public License along with the GNU MP Library. If not,
35 1.1 mrg see https://www.gnu.org/licenses/. */
36 1.1 mrg
37 1.1 mrg #include <stdio.h>
38 1.1 mrg #include "gmp-impl.h"
39 1.1 mrg
40 1.1 mrg /* Stores |{ap,n}-{bp,n}| in {rp,n},
41 1.1 mrg returns the sign of {ap,n}-{bp,n}. */
42 1.1 mrg static int
43 1.1 mrg abs_sub_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
44 1.1 mrg {
45 1.1 mrg mp_limb_t x, y;
46 1.1 mrg while (--n >= 0)
47 1.1 mrg {
48 1.1 mrg x = ap[n];
49 1.1 mrg y = bp[n];
50 1.1 mrg if (x != y)
51 1.1 mrg {
52 1.1 mrg ++n;
53 1.1 mrg if (x > y)
54 1.1 mrg {
55 1.1 mrg ASSERT_NOCARRY (mpn_sub_n (rp, ap, bp, n));
56 1.1 mrg return 1;
57 1.1 mrg }
58 1.1 mrg else
59 1.1 mrg {
60 1.1 mrg ASSERT_NOCARRY (mpn_sub_n (rp, bp, ap, n));
61 1.1 mrg return -1;
62 1.1 mrg }
63 1.1 mrg }
64 1.1 mrg rp[n] = 0;
65 1.1 mrg }
66 1.1 mrg return 0;
67 1.1 mrg }
68 1.1 mrg
69 1.1 mrg /* Computes at most count terms of the sequence needed by the
70 1.1 mrg Lucas-Lehmer-Riesel test, indexing backward:
71 1.1 mrg L_i = L_{i+1}^2 - 2
72 1.1 mrg
73 1.1 mrg The sequence is computed modulo M = {mp, mn}.
74 1.1 mrg The starting point is given in L_{count+1} = {lp, mn}.
75 1.1 mrg The scratch pointed by sp, needs a space of at least 3 * mn + 1 limbs.
76 1.1 mrg
77 1.1 mrg Returns the index i>0 if L_i = 0 (mod M) is found within the
78 1.1 mrg computed count terms of the sequence. Otherwise it returns zero.
79 1.1 mrg
80 1.1 mrg Note: (+/-2)^2-2=2, (+/-1)^2-2=-1, 0^2-2=-2
81 1.1 mrg */
82 1.1 mrg
83 1.1 mrg static mp_bitcnt_t
84 1.1 mrg mpn_llriter (mp_ptr lp, mp_srcptr mp, mp_size_t mn, mp_bitcnt_t count, mp_ptr sp)
85 1.1 mrg {
86 1.1 mrg do
87 1.1 mrg {
88 1.1 mrg mpn_sqr (sp, lp, mn);
89 1.1 mrg mpn_tdiv_qr (sp + 2 * mn, lp, 0, sp, 2 * mn, mp, mn);
90 1.1 mrg if (lp[0] < 5)
91 1.1 mrg {
92 1.1 mrg /* If L^2 % M < 5, |L^2 % M - 2| <= 2 */
93 1.1 mrg if (mn == 1 || mpn_zero_p (lp + 1, mn - 1))
94 1.1 mrg return (lp[0] == 2) ? count : 0;
95 1.1 mrg else
96 1.1 mrg MPN_DECR_U (lp, mn, 2);
97 1.1 mrg }
98 1.1 mrg else
99 1.1 mrg lp[0] -= 2;
100 1.1 mrg } while (--count != 0);
101 1.1 mrg return 0;
102 1.1 mrg }
103 1.1 mrg
104 1.1 mrg /* Store the Lucas' number L[n] at lp (maybe), computed modulo m. lp
105 1.1 mrg and scratch should have room for mn*2+1 limbs.
106 1.1 mrg
107 1.1 mrg Returns the size of L[n] normally.
108 1.1 mrg
109 1.1 mrg If F[n] is zero modulo m, or L[n] is, returns 0 and lp is
110 1.1 mrg undefined.
111 1.1 mrg */
112 1.1 mrg
113 1.1 mrg static mp_size_t
114 1.1 mrg mpn_lucm (mp_ptr lp, mp_srcptr np, mp_size_t nn, mp_srcptr mp, mp_size_t mn, mp_ptr scratch)
115 1.1 mrg {
116 1.1 mrg int neg;
117 1.1 mrg mp_limb_t cy;
118 1.1 mrg
119 1.1 mrg ASSERT (! MPN_OVERLAP_P (lp, MAX(2*mn+1,5), scratch, MAX(2*mn+1,5)));
120 1.1 mrg ASSERT (nn > 0);
121 1.1 mrg
122 1.1 mrg neg = mpn_fib2m (lp, scratch, np, nn, mp, mn);
123 1.1 mrg
124 1.1 mrg /* F[n] = +/-{lp, mn}, F[n-1] = +/-{scratch, mn} */
125 1.1 mrg if (mpn_zero_p (lp, mn))
126 1.1 mrg return 0;
127 1.1 mrg
128 1.1 mrg if (neg) /* One sign is opposite, use sub instead of add. */
129 1.1 mrg {
130 1.1 mrg #if HAVE_NATIVE_mpn_rsblsh1_n || HAVE_NATIVE_mpn_sublsh1_n
131 1.1 mrg #if HAVE_NATIVE_mpn_rsblsh1_n
132 1.1 mrg cy = mpn_rsblsh1_n (lp, lp, scratch, mn); /* L[n] = +/-(2F[n-1]-(-F[n])) */
133 1.1 mrg #else
134 1.1 mrg cy = mpn_sublsh1_n (lp, lp, scratch, mn); /* L[n] = -/+(F[n]-(-2F[n-1])) */
135 1.1 mrg if (cy != 0)
136 1.1 mrg cy = mpn_add_n (lp, lp, mp, mn) - cy;
137 1.1 mrg #endif
138 1.1 mrg if (cy > 1)
139 1.1 mrg cy += mpn_add_n (lp, lp, mp, mn);
140 1.1 mrg #else
141 1.1 mrg cy = mpn_lshift (scratch, scratch, mn, 1); /* 2F[n-1] */
142 1.1 mrg if (UNLIKELY (cy))
143 1.1 mrg cy -= mpn_sub_n (lp, scratch, lp, mn); /* L[n] = +/-(2F[n-1]-(-F[n])) */
144 1.1 mrg else
145 1.1 mrg abs_sub_n (lp, lp, scratch, mn);
146 1.1 mrg #endif
147 1.1 mrg ASSERT (cy <= 1);
148 1.1 mrg }
149 1.1 mrg else
150 1.1 mrg {
151 1.1 mrg #if HAVE_NATIVE_mpn_addlsh1_n
152 1.1 mrg cy = mpn_addlsh1_n (lp, lp, scratch, mn); /* L[n] = +/-(2F[n-1]+F[n])) */
153 1.1 mrg #else
154 1.1 mrg cy = mpn_lshift (scratch, scratch, mn, 1);
155 1.1 mrg cy+= mpn_add_n (lp, lp, scratch, mn);
156 1.1 mrg #endif
157 1.1 mrg ASSERT (cy <= 2);
158 1.1 mrg }
159 1.1 mrg while (cy || mpn_cmp (lp, mp, mn) >= 0)
160 1.1 mrg cy -= mpn_sub_n (lp, lp, mp, mn);
161 1.1 mrg MPN_NORMALIZE (lp, mn);
162 1.1 mrg return mn;
163 1.1 mrg }
164 1.1 mrg
165 1.1 mrg int
166 1.1 mrg mpn_strongfibo (mp_srcptr mp, mp_size_t mn, mp_ptr scratch)
167 1.1 mrg {
168 1.1 mrg mp_ptr lp, sp;
169 1.1 mrg mp_size_t en;
170 1.1 mrg mp_bitcnt_t b0;
171 1.1 mrg TMP_DECL;
172 1.1 mrg
173 1.1 mrg #if GMP_NUMB_BITS % 4 == 0
174 1.1 mrg b0 = mpn_scan0 (mp, 0);
175 1.1 mrg #else
176 1.1 mrg {
177 1.1 mrg mpz_t m = MPZ_ROINIT_N(mp, mn);
178 1.1 mrg b0 = mpz_scan0 (m, 0);
179 1.1 mrg }
180 1.1 mrg if (UNLIKELY (b0 == mn * GMP_NUMB_BITS))
181 1.1 mrg {
182 1.1 mrg en = 1;
183 1.1 mrg scratch [0] = 1;
184 1.1 mrg }
185 1.1 mrg else
186 1.1 mrg #endif
187 1.1 mrg {
188 1.1 mrg int cnt = b0 % GMP_NUMB_BITS;
189 1.1 mrg en = b0 / GMP_NUMB_BITS;
190 1.1 mrg if (LIKELY (cnt != 0))
191 1.1 mrg mpn_rshift (scratch, mp + en, mn - en, cnt);
192 1.1 mrg else
193 1.1 mrg MPN_COPY (scratch, mp + en, mn - en);
194 1.1 mrg en = mn - en;
195 1.1 mrg scratch [0] |= 1;
196 1.1 mrg en -= scratch [en - 1] == 0;
197 1.1 mrg }
198 1.1 mrg TMP_MARK;
199 1.1 mrg
200 1.1 mrg lp = TMP_ALLOC_LIMBS (4 * mn + 6);
201 1.1 mrg sp = lp + 2 * mn + 3;
202 1.1 mrg en = mpn_lucm (sp, scratch, en, mp, mn, lp);
203 1.1 mrg if (en != 0 && LIKELY (--b0 != 0))
204 1.1 mrg {
205 1.1 mrg mpn_sqr (lp, sp, en);
206 1.1 mrg lp [0] |= 2; /* V^2 + 2 */
207 1.1 mrg if (LIKELY (2 * en >= mn))
208 1.1 mrg mpn_tdiv_qr (sp, lp, 0, lp, 2 * en, mp, mn);
209 1.1 mrg else
210 1.1 mrg MPN_ZERO (lp + 2 * en, mn - 2 * en);
211 1.1 mrg if (! mpn_zero_p (lp, mn) && LIKELY (--b0 != 0))
212 1.1 mrg b0 = mpn_llriter (lp, mp, mn, b0, lp + mn + 1);
213 1.1 mrg }
214 1.1 mrg TMP_FREE;
215 1.1 mrg return (b0 != 0);
216 1.1 mrg }
217