github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/mpn/generic/fib2_ui.c (about)

     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
    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
   136  	  fp[size] = mpn_rsblsh2_n (fp, fp, xp, size);
   137  	  if ((n & mask) == 0)
   138  	    MPN_INCR_U(fp, size + 1, 2);	/* possible +2 */
   139  	  else
   140  	  {
   141  	    ASSERT (fp[0] >= 2);
   142  	    fp[0] -= 2;				/* possible -2 */
   143  	  }
   144  #else
   145  	  {
   146  	    mp_limb_t  c;
   147  
   148  	    c = mpn_lshift (xp, xp, size, 2);
   149  	    xp[0] |= (n & mask ? 0 : 2);	/* possible +2 */
   150  	    c -= mpn_sub_n (fp, xp, fp, size);
   151  	    ASSERT (n & mask ? fp[0] != 0 && fp[0] != 1 : 1);
   152  	    fp[0] -= (n & mask ? 2 : 0);	/* possible -2 */
   153  	    fp[size] = c;
   154  	  }
   155  #endif
   156  	  ASSERT (alloc >= size+1);
   157  	  size += (fp[size] != 0);
   158  
   159  	  /* now n&mask is the new bit of n being considered */
   160  	  mask >>= 1;
   161  
   162  	  /* Calculate F[2k] = F[2k+1] - F[2k-1], replacing the unwanted one of
   163  	     F[2k+1] and F[2k-1].  */
   164  	  if (n & mask)
   165  	    ASSERT_NOCARRY (mpn_sub_n (f1p, fp, f1p, size));
   166  	  else {
   167  	    ASSERT_NOCARRY (mpn_sub_n ( fp, fp, f1p, size));
   168  
   169  	    /* Can have a high zero after replacing F[2k+1] with F[2k].
   170  	       f1p will have a high zero if fp does. */
   171  	    ASSERT (fp[size-1] != 0 || f1p[size-1] == 0);
   172  	    size -= (fp[size-1] == 0);
   173  	  }
   174  	}
   175        while (mask != 1);
   176  
   177        TMP_FREE;
   178      }
   179  
   180    TRACE (printf ("done size=%ld\n", size);
   181  	 mpn_trace ("fp ", fp, size);
   182  	 mpn_trace ("f1p", f1p, size));
   183  
   184    return size;
   185  }