Home | History | Annotate | Line # | Download | only in generic
      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.1.2  mrg 
     41  1.1.1.2  mrg #if HAVE_NATIVE_mpn_rsblsh1_n || HAVE_NATIVE_mpn_sublsh1_n
     42  1.1.1.2  mrg #else
     43      1.1  mrg /* Stores |{ap,n}-{bp,n}| in {rp,n},
     44      1.1  mrg    returns the sign of {ap,n}-{bp,n}. */
     45      1.1  mrg static int
     46      1.1  mrg abs_sub_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
     47      1.1  mrg {
     48      1.1  mrg   mp_limb_t  x, y;
     49      1.1  mrg   while (--n >= 0)
     50      1.1  mrg     {
     51      1.1  mrg       x = ap[n];
     52      1.1  mrg       y = bp[n];
     53      1.1  mrg       if (x != y)
     54      1.1  mrg         {
     55      1.1  mrg           ++n;
     56      1.1  mrg           if (x > y)
     57      1.1  mrg             {
     58      1.1  mrg               ASSERT_NOCARRY (mpn_sub_n (rp, ap, bp, n));
     59      1.1  mrg               return 1;
     60      1.1  mrg             }
     61      1.1  mrg           else
     62      1.1  mrg             {
     63      1.1  mrg               ASSERT_NOCARRY (mpn_sub_n (rp, bp, ap, n));
     64      1.1  mrg               return -1;
     65      1.1  mrg             }
     66      1.1  mrg         }
     67      1.1  mrg       rp[n] = 0;
     68      1.1  mrg     }
     69      1.1  mrg   return 0;
     70      1.1  mrg }
     71  1.1.1.2  mrg #endif
     72      1.1  mrg 
     73      1.1  mrg /* Computes at most count terms of the sequence needed by the
     74      1.1  mrg    Lucas-Lehmer-Riesel test, indexing backward:
     75      1.1  mrg    L_i = L_{i+1}^2 - 2
     76      1.1  mrg 
     77      1.1  mrg    The sequence is computed modulo M = {mp, mn}.
     78      1.1  mrg    The starting point is given in L_{count+1} = {lp, mn}.
     79      1.1  mrg    The scratch pointed by sp, needs a space of at least 3 * mn + 1 limbs.
     80      1.1  mrg 
     81      1.1  mrg    Returns the index i>0 if L_i = 0 (mod M) is found within the
     82      1.1  mrg    computed count terms of the sequence.  Otherwise it returns zero.
     83      1.1  mrg 
     84      1.1  mrg    Note: (+/-2)^2-2=2, (+/-1)^2-2=-1, 0^2-2=-2
     85      1.1  mrg  */
     86      1.1  mrg 
     87      1.1  mrg static mp_bitcnt_t
     88      1.1  mrg mpn_llriter (mp_ptr lp, mp_srcptr mp, mp_size_t mn, mp_bitcnt_t count, mp_ptr sp)
     89      1.1  mrg {
     90      1.1  mrg   do
     91      1.1  mrg     {
     92      1.1  mrg       mpn_sqr (sp, lp, mn);
     93      1.1  mrg       mpn_tdiv_qr (sp + 2 * mn, lp, 0, sp, 2 * mn, mp, mn);
     94      1.1  mrg       if (lp[0] < 5)
     95      1.1  mrg 	{
     96      1.1  mrg 	  /* If L^2 % M < 5, |L^2 % M - 2| <= 2 */
     97      1.1  mrg 	  if (mn == 1 || mpn_zero_p (lp + 1, mn - 1))
     98      1.1  mrg 	    return (lp[0] == 2) ? count : 0;
     99      1.1  mrg 	  else
    100      1.1  mrg 	    MPN_DECR_U (lp, mn, 2);
    101      1.1  mrg 	}
    102      1.1  mrg       else
    103      1.1  mrg 	lp[0] -= 2;
    104      1.1  mrg     } while (--count != 0);
    105      1.1  mrg   return 0;
    106      1.1  mrg }
    107      1.1  mrg 
    108      1.1  mrg /* Store the Lucas' number L[n] at lp (maybe), computed modulo m.  lp
    109      1.1  mrg    and scratch should have room for mn*2+1 limbs.
    110      1.1  mrg 
    111      1.1  mrg    Returns the size of L[n] normally.
    112      1.1  mrg 
    113      1.1  mrg    If F[n] is zero modulo m, or L[n] is, returns 0 and lp is
    114      1.1  mrg    undefined.
    115      1.1  mrg */
    116      1.1  mrg 
    117      1.1  mrg static mp_size_t
    118      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)
    119      1.1  mrg {
    120      1.1  mrg   int		neg;
    121      1.1  mrg   mp_limb_t	cy;
    122      1.1  mrg 
    123      1.1  mrg   ASSERT (! MPN_OVERLAP_P (lp, MAX(2*mn+1,5), scratch, MAX(2*mn+1,5)));
    124      1.1  mrg   ASSERT (nn > 0);
    125      1.1  mrg 
    126      1.1  mrg   neg = mpn_fib2m (lp, scratch, np, nn, mp, mn);
    127      1.1  mrg 
    128      1.1  mrg   /* F[n] = +/-{lp, mn}, F[n-1] = +/-{scratch, mn} */
    129      1.1  mrg   if (mpn_zero_p (lp, mn))
    130      1.1  mrg     return 0;
    131      1.1  mrg 
    132      1.1  mrg   if (neg) /* One sign is opposite, use sub instead of add. */
    133      1.1  mrg     {
    134      1.1  mrg #if HAVE_NATIVE_mpn_rsblsh1_n || HAVE_NATIVE_mpn_sublsh1_n
    135      1.1  mrg #if HAVE_NATIVE_mpn_rsblsh1_n
    136      1.1  mrg       cy = mpn_rsblsh1_n (lp, lp, scratch, mn); /* L[n] = +/-(2F[n-1]-(-F[n])) */
    137      1.1  mrg #else
    138      1.1  mrg       cy = mpn_sublsh1_n (lp, lp, scratch, mn); /* L[n] = -/+(F[n]-(-2F[n-1])) */
    139      1.1  mrg       if (cy != 0)
    140      1.1  mrg 	cy = mpn_add_n (lp, lp, mp, mn) - cy;
    141      1.1  mrg #endif
    142      1.1  mrg       if (cy > 1)
    143      1.1  mrg 	cy += mpn_add_n (lp, lp, mp, mn);
    144      1.1  mrg #else
    145      1.1  mrg       cy = mpn_lshift (scratch, scratch, mn, 1); /* 2F[n-1] */
    146      1.1  mrg       if (UNLIKELY (cy))
    147      1.1  mrg 	cy -= mpn_sub_n (lp, scratch, lp, mn); /* L[n] = +/-(2F[n-1]-(-F[n])) */
    148      1.1  mrg       else
    149      1.1  mrg 	abs_sub_n (lp, lp, scratch, mn);
    150      1.1  mrg #endif
    151      1.1  mrg       ASSERT (cy <= 1);
    152      1.1  mrg     }
    153      1.1  mrg   else
    154      1.1  mrg     {
    155      1.1  mrg #if HAVE_NATIVE_mpn_addlsh1_n
    156      1.1  mrg       cy = mpn_addlsh1_n (lp, lp, scratch, mn); /* L[n] = +/-(2F[n-1]+F[n])) */
    157      1.1  mrg #else
    158      1.1  mrg       cy = mpn_lshift (scratch, scratch, mn, 1);
    159      1.1  mrg       cy+= mpn_add_n (lp, lp, scratch, mn);
    160      1.1  mrg #endif
    161      1.1  mrg       ASSERT (cy <= 2);
    162      1.1  mrg     }
    163      1.1  mrg   while (cy || mpn_cmp (lp, mp, mn) >= 0)
    164      1.1  mrg     cy -= mpn_sub_n (lp, lp, mp, mn);
    165      1.1  mrg   MPN_NORMALIZE (lp, mn);
    166      1.1  mrg   return mn;
    167      1.1  mrg }
    168      1.1  mrg 
    169      1.1  mrg int
    170      1.1  mrg mpn_strongfibo (mp_srcptr mp, mp_size_t mn, mp_ptr scratch)
    171      1.1  mrg {
    172      1.1  mrg   mp_ptr	lp, sp;
    173      1.1  mrg   mp_size_t	en;
    174      1.1  mrg   mp_bitcnt_t	b0;
    175      1.1  mrg   TMP_DECL;
    176      1.1  mrg 
    177      1.1  mrg #if GMP_NUMB_BITS % 4 == 0
    178      1.1  mrg   b0 = mpn_scan0 (mp, 0);
    179      1.1  mrg #else
    180      1.1  mrg   {
    181      1.1  mrg     mpz_t m = MPZ_ROINIT_N(mp, mn);
    182      1.1  mrg     b0 = mpz_scan0 (m, 0);
    183      1.1  mrg   }
    184      1.1  mrg   if (UNLIKELY (b0 == mn * GMP_NUMB_BITS))
    185      1.1  mrg     {
    186      1.1  mrg       en = 1;
    187      1.1  mrg       scratch [0] = 1;
    188      1.1  mrg     }
    189      1.1  mrg   else
    190      1.1  mrg #endif
    191      1.1  mrg     {
    192      1.1  mrg       int cnt = b0 % GMP_NUMB_BITS;
    193      1.1  mrg       en = b0 / GMP_NUMB_BITS;
    194      1.1  mrg       if (LIKELY (cnt != 0))
    195      1.1  mrg 	mpn_rshift (scratch, mp + en, mn - en, cnt);
    196      1.1  mrg       else
    197      1.1  mrg 	MPN_COPY (scratch, mp + en, mn - en);
    198      1.1  mrg       en = mn - en;
    199      1.1  mrg       scratch [0] |= 1;
    200      1.1  mrg       en -= scratch [en - 1] == 0;
    201      1.1  mrg     }
    202      1.1  mrg   TMP_MARK;
    203      1.1  mrg 
    204      1.1  mrg   lp = TMP_ALLOC_LIMBS (4 * mn + 6);
    205      1.1  mrg   sp = lp + 2 * mn + 3;
    206      1.1  mrg   en = mpn_lucm (sp, scratch, en, mp, mn, lp);
    207      1.1  mrg   if (en != 0 && LIKELY (--b0 != 0))
    208      1.1  mrg     {
    209      1.1  mrg       mpn_sqr (lp, sp, en);
    210      1.1  mrg       lp [0] |= 2; /* V^2 + 2 */
    211      1.1  mrg       if (LIKELY (2 * en >= mn))
    212      1.1  mrg 	mpn_tdiv_qr (sp, lp, 0, lp, 2 * en, mp, mn);
    213      1.1  mrg       else
    214      1.1  mrg 	MPN_ZERO (lp + 2 * en, mn - 2 * en);
    215      1.1  mrg       if (! mpn_zero_p (lp, mn) && LIKELY (--b0 != 0))
    216      1.1  mrg 	b0 = mpn_llriter (lp, mp, mn, b0, lp + mn + 1);
    217      1.1  mrg     }
    218      1.1  mrg   TMP_FREE;
    219      1.1  mrg   return (b0 != 0);
    220      1.1  mrg }
    221