Coverage Report

Created: 2025-03-09 06:52

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