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