1 /* mpn_fib2_ui -- calculate Fibonacci numbers.
2 
3    THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
4    CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
5    FUTURE GNU MP RELEASES.
6 
7 Copyright 2001, 2002, 2005, 2009 Free Software Foundation, Inc.
8 
9 This file is part of the GNU MP Library.
10 
11 The GNU MP Library is free software; you can redistribute it and/or modify
12 it under the terms of either:
13 
14   * the GNU Lesser General Public License as published by the Free
15     Software Foundation; either version 3 of the License, or (at your
16     option) any later version.
17 
18 or
19 
20   * the GNU General Public License as published by the Free Software
21     Foundation; either version 2 of the License, or (at your option) any
22     later version.
23 
24 or both in parallel, as here.
25 
26 The GNU MP Library is distributed in the hope that it will be useful, but
27 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
28 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
29 for more details.
30 
31 You should have received copies of the GNU General Public License and the
32 GNU Lesser General Public License along with the GNU MP Library.  If not,
33 see https://www.gnu.org/licenses/.  */
34 
35 #include <stdio.h>
36 #include "gmp.h"
37 #include "gmp-impl.h"
38 
39 /* change this to "#define TRACE(x) x" for diagnostics */
40 #define TRACE(x)
41 
42 
43 /* Store F[n] at fp and F[n-1] at f1p.  fp and f1p should have room for
44    MPN_FIB2_SIZE(n) limbs.
45 
46    The return value is the actual number of limbs stored, this will be at
47    least 1.  fp[size-1] will be non-zero, except when n==0, in which case
48    fp[0] is 0 and f1p[0] is 1.  f1p[size-1] can be zero, since F[n-1]<F[n]
49    (for n>0).
50 
51    Notes:
52 
53    In F[2k+1] with k even, +2 is applied to 4*F[k]^2 just by ORing into the
54    low limb.
55 
56    In F[2k+1] with k odd, -2 is applied to the low limb of 4*F[k]^2 -
57    F[k-1]^2.  This F[2k+1] is an F[4m+3] and such numbers are congruent to
58    1, 2 or 5 mod 8, which means no underflow reaching it with a -2 (since
59    that would leave 6 or 7 mod 8).
60 
61    This property of F[4m+3] can be verified by induction on F[4m+3] =
62    7*F[4m-1] - F[4m-5], that formula being a standard lucas sequence
63    identity U[i+j] = U[i]*V[j] - U[i-j]*Q^j.
64 */
65 
66 mp_size_t
mpn_fib2_ui(mp_ptr fp,mp_ptr f1p,unsigned long int n)67 mpn_fib2_ui (mp_ptr fp, mp_ptr f1p, unsigned long int n)
68 {
69   mp_size_t      size;
70   unsigned long  nfirst, mask;
71 
72   TRACE (printf ("mpn_fib2_ui n=%lu\n", n));
73 
74   ASSERT (! MPN_OVERLAP_P (fp, MPN_FIB2_SIZE(n), f1p, MPN_FIB2_SIZE(n)));
75 
76   /* Take a starting pair from the table. */
77   mask = 1;
78   for (nfirst = n; nfirst > FIB_TABLE_LIMIT; nfirst /= 2)
79     mask <<= 1;
80   TRACE (printf ("nfirst=%lu mask=0x%lX\n", nfirst, mask));
81 
82   f1p[0] = FIB_TABLE ((int) nfirst - 1);
83   fp[0]  = FIB_TABLE (nfirst);
84   size = 1;
85 
86   /* Skip to the end if the table lookup gives the final answer. */
87   if (mask != 1)
88     {
89       mp_size_t  alloc;
90       mp_ptr        xp;
91       TMP_DECL;
92 
93       TMP_MARK;
94       alloc = MPN_FIB2_SIZE (n);
95       xp = TMP_ALLOC_LIMBS (alloc);
96 
97       do
98 	{
99 	  /* Here fp==F[k] and f1p==F[k-1], with k being the bits of n from
100 	     n&mask upwards.
101 
102 	     The next bit of n is n&(mask>>1) and we'll double to the pair
103 	     fp==F[2k],f1p==F[2k-1] or fp==F[2k+1],f1p==F[2k], according as
104 	     that bit is 0 or 1 respectively.  */
105 
106 	  TRACE (printf ("k=%lu mask=0x%lX size=%ld alloc=%ld\n",
107 			 n >> refmpn_count_trailing_zeros(mask),
108 			 mask, size, alloc);
109 		 mpn_trace ("fp ", fp, size);
110 		 mpn_trace ("f1p", f1p, size));
111 
112 	  /* fp normalized, f1p at most one high zero */
113 	  ASSERT (fp[size-1] != 0);
114 	  ASSERT (f1p[size-1] != 0 || f1p[size-2] != 0);
115 
116 	  /* f1p[size-1] might be zero, but this occurs rarely, so it's not
117 	     worth bothering checking for it */
118 	  ASSERT (alloc >= 2*size);
119 	  mpn_sqr (xp, fp,  size);
120 	  mpn_sqr (fp, f1p, size);
121 	  size *= 2;
122 
123 	  /* Shrink if possible.  Since fp was normalized there'll be at
124 	     most one high zero on xp (and if there is then there's one on
125 	     yp too).  */
126 	  ASSERT (xp[size-1] != 0 || fp[size-1] == 0);
127 	  size -= (xp[size-1] == 0);
128 	  ASSERT (xp[size-1] != 0);  /* only one xp high zero */
129 
130 	  /* Calculate F[2k-1] = F[k]^2 + F[k-1]^2. */
131 	  f1p[size] = mpn_add_n (f1p, xp, fp, size);
132 
133 	  /* Calculate F[2k+1] = 4*F[k]^2 - F[k-1]^2 + 2*(-1)^k.
134 	     n&mask is the low bit of our implied k.  */
135 #if HAVE_NATIVE_mpn_rsblsh2_n || HAVE_NATIVE_mpn_rsblsh_n
136 #if HAVE_NATIVE_mpn_rsblsh2_n
137 	  fp[size] = mpn_rsblsh2_n (fp, fp, xp, size);
138 #else /* HAVE_NATIVE_mpn_rsblsh_n */
139 	  fp[size] = mpn_rsblsh_n (fp, fp, xp, size, 2);
140 #endif
141 	  if ((n & mask) == 0)
142 	    MPN_INCR_U(fp, size + 1, 2);	/* possible +2 */
143 	  else
144 	  {
145 	    ASSERT (fp[0] >= 2);
146 	    fp[0] -= 2;				/* possible -2 */
147 	  }
148 #else
149 	  {
150 	    mp_limb_t  c;
151 
152 	    c = mpn_lshift (xp, xp, size, 2);
153 	    xp[0] |= (n & mask ? 0 : 2);	/* possible +2 */
154 	    c -= mpn_sub_n (fp, xp, fp, size);
155 	    ASSERT (n & mask ? fp[0] != 0 && fp[0] != 1 : 1);
156 	    fp[0] -= (n & mask ? 2 : 0);	/* possible -2 */
157 	    fp[size] = c;
158 	  }
159 #endif
160 	  ASSERT (alloc >= size+1);
161 	  size += (fp[size] != 0);
162 
163 	  /* now n&mask is the new bit of n being considered */
164 	  mask >>= 1;
165 
166 	  /* Calculate F[2k] = F[2k+1] - F[2k-1], replacing the unwanted one of
167 	     F[2k+1] and F[2k-1].  */
168 	  if (n & mask)
169 	    ASSERT_NOCARRY (mpn_sub_n (f1p, fp, f1p, size));
170 	  else {
171 	    ASSERT_NOCARRY (mpn_sub_n ( fp, fp, f1p, size));
172 
173 	    /* Can have a high zero after replacing F[2k+1] with F[2k].
174 	       f1p will have a high zero if fp does. */
175 	    ASSERT (fp[size-1] != 0 || f1p[size-1] == 0);
176 	    size -= (fp[size-1] == 0);
177 	  }
178 	}
179       while (mask != 1);
180 
181       TMP_FREE;
182     }
183 
184   TRACE (printf ("done size=%ld\n", size);
185 	 mpn_trace ("fp ", fp, size);
186 	 mpn_trace ("f1p", f1p, size));
187 
188   return size;
189 }
190