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