/src/gmp-6.2.1/mpz/lucnum_ui.c
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /* mpz_lucnum_ui -- calculate Lucas number.  | 
2  |  |  | 
3  |  | Copyright 2001, 2003, 2005, 2011, 2012, 2015, 2016 Free Software Foundation, Inc.  | 
4  |  |  | 
5  |  | This file is part of the GNU MP Library.  | 
6  |  |  | 
7  |  | The GNU MP Library is free software; you can redistribute it and/or modify  | 
8  |  | it under the terms of either:  | 
9  |  |  | 
10  |  |   * the GNU Lesser General Public License as published by the Free  | 
11  |  |     Software Foundation; either version 3 of the License, or (at your  | 
12  |  |     option) any later version.  | 
13  |  |  | 
14  |  | or  | 
15  |  |  | 
16  |  |   * the GNU General Public License as published by the Free Software  | 
17  |  |     Foundation; either version 2 of the License, or (at your option) any  | 
18  |  |     later version.  | 
19  |  |  | 
20  |  | or both in parallel, as here.  | 
21  |  |  | 
22  |  | The GNU MP Library is distributed in the hope that it will be useful, but  | 
23  |  | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY  | 
24  |  | or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License  | 
25  |  | for more details.  | 
26  |  |  | 
27  |  | You should have received copies of the GNU General Public License and the  | 
28  |  | GNU Lesser General Public License along with the GNU MP Library.  If not,  | 
29  |  | see https://www.gnu.org/licenses/.  */  | 
30  |  |  | 
31  |  | #include <stdio.h>  | 
32  |  | #include "gmp-impl.h"  | 
33  |  |  | 
34  |  |  | 
35  |  | /* change this to "#define TRACE(x) x" for diagnostics */  | 
36  |  | #define TRACE(x)  | 
37  |  |  | 
38  |  |  | 
39  |  | /* Notes:  | 
40  |  |  | 
41  |  |    For the +4 in L[2k+1] when k is even, all L[4m+3] == 4, 5 or 7 mod 8, so  | 
42  |  |    there can't be an overflow applying +4 to just the low limb (since that  | 
43  |  |    would leave 0, 1, 2 or 3 mod 8).  | 
44  |  |  | 
45  |  |    For the -4 in L[2k+1] when k is even, it seems (no proof) that  | 
46  |  |    L[3*2^(b-2)-3] == -4 mod 2^b, so for instance with a 32-bit limb  | 
47  |  |    L[0xBFFFFFFD] == 0xFFFFFFFC mod 2^32, and this implies a borrow from the  | 
48  |  |    low limb.  Obviously L[0xBFFFFFFD] is a huge number, but it's at least  | 
49  |  |    conceivable to calculate it, so it probably should be handled.  | 
50  |  |  | 
51  |  |    For the -2 in L[2k] with k even, it seems (no proof) L[2^(b-1)] == -1 mod  | 
52  |  |    2^b, so for instance in 32-bits L[0x80000000] has a low limb of  | 
53  |  |    0xFFFFFFFF so there would have been a borrow.  Again L[0x80000000] is  | 
54  |  |    obviously huge, but probably should be made to work.  */  | 
55  |  |  | 
56  |  | void  | 
57  |  | mpz_lucnum_ui (mpz_ptr ln, unsigned long n)  | 
58  | 0  | { | 
59  | 0  |   mp_size_t  lalloc, xalloc, lsize, xsize;  | 
60  | 0  |   mp_ptr     lp, xp;  | 
61  | 0  |   mp_limb_t  c;  | 
62  | 0  |   int        zeros;  | 
63  | 0  |   TMP_DECL;  | 
64  |  | 
  | 
65  | 0  |   TRACE (printf ("mpn_lucnum_ui n=%lu\n", n)); | 
66  |  | 
  | 
67  | 0  |   if (n <= FIB_TABLE_LUCNUM_LIMIT)  | 
68  | 0  |     { | 
69  |  |       /* L[n] = F[n] + 2F[n-1] */  | 
70  | 0  |       MPZ_NEWALLOC (ln, 1)[0] = FIB_TABLE(n) + 2 * FIB_TABLE ((int) n - 1);  | 
71  | 0  |       SIZ(ln) = 1;  | 
72  | 0  |       return;  | 
73  | 0  |     }  | 
74  |  |  | 
75  |  |   /* +1 since L[n]=F[n]+2F[n-1] might be 1 limb bigger than F[n], further +1  | 
76  |  |      since square or mul used below might need an extra limb over the true  | 
77  |  |      size */  | 
78  | 0  |   lalloc = MPN_FIB2_SIZE (n) + 2;  | 
79  | 0  |   lp = MPZ_NEWALLOC (ln, lalloc);  | 
80  |  | 
  | 
81  | 0  |   TMP_MARK;  | 
82  | 0  |   xalloc = lalloc;  | 
83  | 0  |   xp = TMP_ALLOC_LIMBS (xalloc);  | 
84  |  |  | 
85  |  |   /* Strip trailing zeros from n, until either an odd number is reached  | 
86  |  |      where the L[2k+1] formula can be used, or until n fits within the  | 
87  |  |      FIB_TABLE data.  The table is preferred of course.  */  | 
88  | 0  |   zeros = 0;  | 
89  | 0  |   for (;;)  | 
90  | 0  |     { | 
91  | 0  |       if (n & 1)  | 
92  | 0  |   { | 
93  |  |     /* L[2k+1] = 5*F[k-1]*(2*F[k]+F[k-1]) - 4*(-1)^k */  | 
94  |  | 
  | 
95  | 0  |     mp_size_t  yalloc, ysize;  | 
96  | 0  |     mp_ptr     yp;  | 
97  |  | 
  | 
98  | 0  |     TRACE (printf ("  initial odd n=%lu\n", n)); | 
99  |  | 
  | 
100  | 0  |     yalloc = MPN_FIB2_SIZE (n/2);  | 
101  | 0  |     yp = TMP_ALLOC_LIMBS (yalloc);  | 
102  | 0  |     ASSERT (xalloc >= yalloc);  | 
103  |  |  | 
104  | 0  |     xsize = mpn_fib2_ui (xp, yp, n/2);  | 
105  |  |  | 
106  |  |     /* possible high zero on F[k-1] */  | 
107  | 0  |     ysize = xsize;  | 
108  | 0  |     ysize -= (yp[ysize-1] == 0);  | 
109  | 0  |     ASSERT (yp[ysize-1] != 0);  | 
110  |  |  | 
111  |  |     /* xp = 2*F[k] + F[k-1] */  | 
112  | 0  | #if HAVE_NATIVE_mpn_addlsh1_n  | 
113  | 0  |     c = mpn_addlsh1_n (xp, yp, xp, xsize);  | 
114  |  | #else  | 
115  |  |     c = mpn_lshift (xp, xp, xsize, 1);  | 
116  |  |     c += mpn_add_n (xp, xp, yp, xsize);  | 
117  |  | #endif  | 
118  | 0  |     ASSERT (xalloc >= xsize+1);  | 
119  | 0  |     xp[xsize] = c;  | 
120  | 0  |     xsize += (c != 0);  | 
121  | 0  |     ASSERT (xp[xsize-1] != 0);  | 
122  |  |  | 
123  | 0  |     ASSERT (lalloc >= xsize + ysize);  | 
124  | 0  |     c = mpn_mul (lp, xp, xsize, yp, ysize);  | 
125  | 0  |     lsize = xsize + ysize;  | 
126  | 0  |     lsize -= (c == 0);  | 
127  |  |  | 
128  |  |     /* lp = 5*lp */  | 
129  | 0  | #if HAVE_NATIVE_mpn_addlsh2_n  | 
130  | 0  |     c = mpn_addlsh2_n (lp, lp, lp, lsize);  | 
131  |  | #else  | 
132  |  |     /* FIXME: Is this faster than mpn_mul_1 ? */  | 
133  |  |     c = mpn_lshift (xp, lp, lsize, 2);  | 
134  |  |     c += mpn_add_n (lp, lp, xp, lsize);  | 
135  |  | #endif  | 
136  | 0  |     ASSERT (lalloc >= lsize+1);  | 
137  | 0  |     lp[lsize] = c;  | 
138  | 0  |     lsize += (c != 0);  | 
139  |  |  | 
140  |  |     /* lp = lp - 4*(-1)^k */  | 
141  | 0  |     if (n & 2)  | 
142  | 0  |       { | 
143  |  |         /* no overflow, see comments above */  | 
144  | 0  |         ASSERT (lp[0] <= MP_LIMB_T_MAX-4);  | 
145  | 0  |         lp[0] += 4;  | 
146  | 0  |       }  | 
147  | 0  |     else  | 
148  | 0  |       { | 
149  |  |         /* won't go negative */  | 
150  | 0  |         MPN_DECR_U (lp, lsize, CNST_LIMB(4));  | 
151  | 0  |       }  | 
152  |  |  | 
153  | 0  |     TRACE (mpn_trace ("  l",lp, lsize)); | 
154  | 0  |     break;  | 
155  | 0  |   }  | 
156  |  |  | 
157  | 0  |       MP_PTR_SWAP (xp, lp); /* balance the swaps wanted in the L[2k] below */  | 
158  | 0  |       zeros++;  | 
159  | 0  |       n /= 2;  | 
160  |  | 
  | 
161  | 0  |       if (n <= FIB_TABLE_LUCNUM_LIMIT)  | 
162  | 0  |   { | 
163  |  |     /* L[n] = F[n] + 2F[n-1] */  | 
164  | 0  |     lp[0] = FIB_TABLE (n) + 2 * FIB_TABLE ((int) n - 1);  | 
165  | 0  |     lsize = 1;  | 
166  |  | 
  | 
167  | 0  |     TRACE (printf ("  initial small n=%lu\n", n); | 
168  | 0  |      mpn_trace ("  l",lp, lsize)); | 
169  | 0  |     break;  | 
170  | 0  |   }  | 
171  | 0  |     }  | 
172  |  |  | 
173  | 0  |   for ( ; zeros != 0; zeros--)  | 
174  | 0  |     { | 
175  |  |       /* L[2k] = L[k]^2 + 2*(-1)^k */  | 
176  |  | 
  | 
177  | 0  |       TRACE (printf ("  zeros=%d\n", zeros)); | 
178  |  | 
  | 
179  | 0  |       ASSERT (xalloc >= 2*lsize);  | 
180  | 0  |       mpn_sqr (xp, lp, lsize);  | 
181  | 0  |       lsize *= 2;  | 
182  | 0  |       lsize -= (xp[lsize-1] == 0);  | 
183  |  |  | 
184  |  |       /* First time around the loop k==n determines (-1)^k, after that k is  | 
185  |  |    always even and we set n=0 to indicate that.  */  | 
186  | 0  |       if (n & 1)  | 
187  | 0  |   { | 
188  |  |     /* L[n]^2 == 0 or 1 mod 4, like all squares, so +2 gives no carry */  | 
189  | 0  |     ASSERT (xp[0] <= MP_LIMB_T_MAX-2);  | 
190  | 0  |     xp[0] += 2;  | 
191  | 0  |     n = 0;  | 
192  | 0  |   }  | 
193  | 0  |       else  | 
194  | 0  |   { | 
195  |  |     /* won't go negative */  | 
196  | 0  |     MPN_DECR_U (xp, lsize, CNST_LIMB(2));  | 
197  | 0  |   }  | 
198  |  |  | 
199  | 0  |       MP_PTR_SWAP (xp, lp);  | 
200  | 0  |       ASSERT (lp[lsize-1] != 0);  | 
201  | 0  |     }  | 
202  |  |  | 
203  |  |   /* should end up in the right spot after all the xp/lp swaps */  | 
204  | 0  |   ASSERT (lp == PTR(ln));  | 
205  | 0  |   SIZ(ln) = lsize;  | 
206  |  | 
  | 
207  | 0  |   TMP_FREE;  | 
208  | 0  | }  |