Blame mpn/generic/fib2_ui.c

Packit 5c3484
/* mpn_fib2_ui -- calculate Fibonacci numbers.
Packit 5c3484
Packit 5c3484
   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
Packit 5c3484
   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
Packit 5c3484
   FUTURE GNU MP RELEASES.
Packit 5c3484
Packit 5c3484
Copyright 2001, 2002, 2005, 2009 Free Software Foundation, Inc.
Packit 5c3484
Packit 5c3484
This file is part of the GNU MP Library.
Packit 5c3484
Packit 5c3484
The GNU MP Library is free software; you can redistribute it and/or modify
Packit 5c3484
it under the terms of either:
Packit 5c3484
Packit 5c3484
  * the GNU Lesser General Public License as published by the Free
Packit 5c3484
    Software Foundation; either version 3 of the License, or (at your
Packit 5c3484
    option) any later version.
Packit 5c3484
Packit 5c3484
or
Packit 5c3484
Packit 5c3484
  * the GNU General Public License as published by the Free Software
Packit 5c3484
    Foundation; either version 2 of the License, or (at your option) any
Packit 5c3484
    later version.
Packit 5c3484
Packit 5c3484
or both in parallel, as here.
Packit 5c3484
Packit 5c3484
The GNU MP Library is distributed in the hope that it will be useful, but
Packit 5c3484
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit 5c3484
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit 5c3484
for more details.
Packit 5c3484
Packit 5c3484
You should have received copies of the GNU General Public License and the
Packit 5c3484
GNU Lesser General Public License along with the GNU MP Library.  If not,
Packit 5c3484
see https://www.gnu.org/licenses/.  */
Packit 5c3484
Packit 5c3484
#include <stdio.h>
Packit 5c3484
#include "gmp.h"
Packit 5c3484
#include "gmp-impl.h"
Packit 5c3484
Packit 5c3484
/* change this to "#define TRACE(x) x" for diagnostics */
Packit 5c3484
#define TRACE(x)
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* Store F[n] at fp and F[n-1] at f1p.  fp and f1p should have room for
Packit 5c3484
   MPN_FIB2_SIZE(n) limbs.
Packit 5c3484
Packit 5c3484
   The return value is the actual number of limbs stored, this will be at
Packit 5c3484
   least 1.  fp[size-1] will be non-zero, except when n==0, in which case
Packit 5c3484
   fp[0] is 0 and f1p[0] is 1.  f1p[size-1] can be zero, since F[n-1]
Packit 5c3484
   (for n>0).
Packit 5c3484
Packit 5c3484
   Notes:
Packit 5c3484
Packit 5c3484
   In F[2k+1] with k even, +2 is applied to 4*F[k]^2 just by ORing into the
Packit 5c3484
   low limb.
Packit 5c3484
Packit 5c3484
   In F[2k+1] with k odd, -2 is applied to the low limb of 4*F[k]^2 -
Packit 5c3484
   F[k-1]^2.  This F[2k+1] is an F[4m+3] and such numbers are congruent to
Packit 5c3484
   1, 2 or 5 mod 8, which means no underflow reaching it with a -2 (since
Packit 5c3484
   that would leave 6 or 7 mod 8).
Packit 5c3484
Packit 5c3484
   This property of F[4m+3] can be verified by induction on F[4m+3] =
Packit 5c3484
   7*F[4m-1] - F[4m-5], that formula being a standard lucas sequence
Packit 5c3484
   identity U[i+j] = U[i]*V[j] - U[i-j]*Q^j.
Packit 5c3484
*/
Packit 5c3484
Packit 5c3484
mp_size_t
Packit 5c3484
mpn_fib2_ui (mp_ptr fp, mp_ptr f1p, unsigned long int n)
Packit 5c3484
{
Packit 5c3484
  mp_size_t      size;
Packit 5c3484
  unsigned long  nfirst, mask;
Packit 5c3484
Packit 5c3484
  TRACE (printf ("mpn_fib2_ui n=%lu\n", n));
Packit 5c3484
Packit 5c3484
  ASSERT (! MPN_OVERLAP_P (fp, MPN_FIB2_SIZE(n), f1p, MPN_FIB2_SIZE(n)));
Packit 5c3484
Packit 5c3484
  /* Take a starting pair from the table. */
Packit 5c3484
  mask = 1;
Packit 5c3484
  for (nfirst = n; nfirst > FIB_TABLE_LIMIT; nfirst /= 2)
Packit 5c3484
    mask <<= 1;
Packit 5c3484
  TRACE (printf ("nfirst=%lu mask=0x%lX\n", nfirst, mask));
Packit 5c3484
Packit 5c3484
  f1p[0] = FIB_TABLE ((int) nfirst - 1);
Packit 5c3484
  fp[0]  = FIB_TABLE (nfirst);
Packit 5c3484
  size = 1;
Packit 5c3484
Packit 5c3484
  /* Skip to the end if the table lookup gives the final answer. */
Packit 5c3484
  if (mask != 1)
Packit 5c3484
    {
Packit 5c3484
      mp_size_t  alloc;
Packit 5c3484
      mp_ptr        xp;
Packit 5c3484
      TMP_DECL;
Packit 5c3484
Packit 5c3484
      TMP_MARK;
Packit 5c3484
      alloc = MPN_FIB2_SIZE (n);
Packit 5c3484
      xp = TMP_ALLOC_LIMBS (alloc);
Packit 5c3484
Packit 5c3484
      do
Packit 5c3484
	{
Packit 5c3484
	  /* Here fp==F[k] and f1p==F[k-1], with k being the bits of n from
Packit 5c3484
	     n&mask upwards.
Packit 5c3484
Packit 5c3484
	     The next bit of n is n&(mask>>1) and we'll double to the pair
Packit 5c3484
	     fp==F[2k],f1p==F[2k-1] or fp==F[2k+1],f1p==F[2k], according as
Packit 5c3484
	     that bit is 0 or 1 respectively.  */
Packit 5c3484
Packit 5c3484
	  TRACE (printf ("k=%lu mask=0x%lX size=%ld alloc=%ld\n",
Packit 5c3484
			 n >> refmpn_count_trailing_zeros(mask),
Packit 5c3484
			 mask, size, alloc);
Packit 5c3484
		 mpn_trace ("fp ", fp, size);
Packit 5c3484
		 mpn_trace ("f1p", f1p, size));
Packit 5c3484
Packit 5c3484
	  /* fp normalized, f1p at most one high zero */
Packit 5c3484
	  ASSERT (fp[size-1] != 0);
Packit 5c3484
	  ASSERT (f1p[size-1] != 0 || f1p[size-2] != 0);
Packit 5c3484
Packit 5c3484
	  /* f1p[size-1] might be zero, but this occurs rarely, so it's not
Packit 5c3484
	     worth bothering checking for it */
Packit 5c3484
	  ASSERT (alloc >= 2*size);
Packit 5c3484
	  mpn_sqr (xp, fp,  size);
Packit 5c3484
	  mpn_sqr (fp, f1p, size);
Packit 5c3484
	  size *= 2;
Packit 5c3484
Packit 5c3484
	  /* Shrink if possible.  Since fp was normalized there'll be at
Packit 5c3484
	     most one high zero on xp (and if there is then there's one on
Packit 5c3484
	     yp too).  */
Packit 5c3484
	  ASSERT (xp[size-1] != 0 || fp[size-1] == 0);
Packit 5c3484
	  size -= (xp[size-1] == 0);
Packit 5c3484
	  ASSERT (xp[size-1] != 0);  /* only one xp high zero */
Packit 5c3484
Packit 5c3484
	  /* Calculate F[2k-1] = F[k]^2 + F[k-1]^2. */
Packit 5c3484
	  f1p[size] = mpn_add_n (f1p, xp, fp, size);
Packit 5c3484
Packit 5c3484
	  /* Calculate F[2k+1] = 4*F[k]^2 - F[k-1]^2 + 2*(-1)^k.
Packit 5c3484
	     n&mask is the low bit of our implied k.  */
Packit 5c3484
#if HAVE_NATIVE_mpn_rsblsh2_n
Packit 5c3484
	  fp[size] = mpn_rsblsh2_n (fp, fp, xp, size);
Packit 5c3484
	  if ((n & mask) == 0)
Packit 5c3484
	    MPN_INCR_U(fp, size + 1, 2);	/* possible +2 */
Packit 5c3484
	  else
Packit 5c3484
	  {
Packit 5c3484
	    ASSERT (fp[0] >= 2);
Packit 5c3484
	    fp[0] -= 2;				/* possible -2 */
Packit 5c3484
	  }
Packit 5c3484
#else
Packit 5c3484
	  {
Packit 5c3484
	    mp_limb_t  c;
Packit 5c3484
Packit 5c3484
	    c = mpn_lshift (xp, xp, size, 2);
Packit 5c3484
	    xp[0] |= (n & mask ? 0 : 2);	/* possible +2 */
Packit 5c3484
	    c -= mpn_sub_n (fp, xp, fp, size);
Packit 5c3484
	    ASSERT (n & mask ? fp[0] != 0 && fp[0] != 1 : 1);
Packit 5c3484
	    fp[0] -= (n & mask ? 2 : 0);	/* possible -2 */
Packit 5c3484
	    fp[size] = c;
Packit 5c3484
	  }
Packit 5c3484
#endif
Packit 5c3484
	  ASSERT (alloc >= size+1);
Packit 5c3484
	  size += (fp[size] != 0);
Packit 5c3484
Packit 5c3484
	  /* now n&mask is the new bit of n being considered */
Packit 5c3484
	  mask >>= 1;
Packit 5c3484
Packit 5c3484
	  /* Calculate F[2k] = F[2k+1] - F[2k-1], replacing the unwanted one of
Packit 5c3484
	     F[2k+1] and F[2k-1].  */
Packit 5c3484
	  if (n & mask)
Packit 5c3484
	    ASSERT_NOCARRY (mpn_sub_n (f1p, fp, f1p, size));
Packit 5c3484
	  else {
Packit 5c3484
	    ASSERT_NOCARRY (mpn_sub_n ( fp, fp, f1p, size));
Packit 5c3484
Packit 5c3484
	    /* Can have a high zero after replacing F[2k+1] with F[2k].
Packit 5c3484
	       f1p will have a high zero if fp does. */
Packit 5c3484
	    ASSERT (fp[size-1] != 0 || f1p[size-1] == 0);
Packit 5c3484
	    size -= (fp[size-1] == 0);
Packit 5c3484
	  }
Packit 5c3484
	}
Packit 5c3484
      while (mask != 1);
Packit 5c3484
Packit 5c3484
      TMP_FREE;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  TRACE (printf ("done size=%ld\n", size);
Packit 5c3484
	 mpn_trace ("fp ", fp, size);
Packit 5c3484
	 mpn_trace ("f1p", f1p, size));
Packit 5c3484
Packit 5c3484
  return size;
Packit 5c3484
}