xref: /dflybsd-src/contrib/gmp/mpn/generic/trialdiv.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /* mpn_trialdiv -- find small factors of an mpn number using trial division.
286d7f5d3SJohn Marino 
386d7f5d3SJohn Marino    Contributed to the GNU project by Torbjorn Granlund.
486d7f5d3SJohn Marino 
586d7f5d3SJohn Marino    THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
686d7f5d3SJohn Marino    SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
786d7f5d3SJohn Marino    GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
886d7f5d3SJohn Marino 
986d7f5d3SJohn Marino Copyright 2009 Free Software Foundation, Inc.
1086d7f5d3SJohn Marino 
1186d7f5d3SJohn Marino This file is part of the GNU MP Library.
1286d7f5d3SJohn Marino 
1386d7f5d3SJohn Marino The GNU MP Library is free software; you can redistribute it and/or modify
1486d7f5d3SJohn Marino it under the terms of the GNU Lesser General Public License as published by
1586d7f5d3SJohn Marino the Free Software Foundation; either version 3 of the License, or (at your
1686d7f5d3SJohn Marino option) any later version.
1786d7f5d3SJohn Marino 
1886d7f5d3SJohn Marino The GNU MP Library is distributed in the hope that it will be useful, but
1986d7f5d3SJohn Marino WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
2086d7f5d3SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
2186d7f5d3SJohn Marino License for more details.
2286d7f5d3SJohn Marino 
2386d7f5d3SJohn Marino You should have received a copy of the GNU Lesser General Public License
2486d7f5d3SJohn Marino along with the GNU MP Library.	If not, see http://www.gnu.org/licenses/.  */
2586d7f5d3SJohn Marino 
2686d7f5d3SJohn Marino /*
2786d7f5d3SJohn Marino    Fast, division-free trial division for GMP.
2886d7f5d3SJohn Marino 
2986d7f5d3SJohn Marino    This function will find the first (smallest) factor represented in
3086d7f5d3SJohn Marino    trialdivtab.h.  It does not stop the factoring effort just because it has
3186d7f5d3SJohn Marino    reached some sensible limit, such as the square root of the input number.
3286d7f5d3SJohn Marino 
3386d7f5d3SJohn Marino    The caller can limit the factoring effort by passing NPRIMES.  The function
3486d7f5d3SJohn Marino    well then divide to *at least* that limit.  A position which only
3586d7f5d3SJohn Marino    mpn_trialdiv can make sense of is returned in the WHERE parameter.  It can
3686d7f5d3SJohn Marino    be used for restarting the factoring effort; the first call should pass 0
3786d7f5d3SJohn Marino    here.
3886d7f5d3SJohn Marino */
3986d7f5d3SJohn Marino 
4086d7f5d3SJohn Marino #include "gmp.h"
4186d7f5d3SJohn Marino #include "gmp-impl.h"
4286d7f5d3SJohn Marino 
4386d7f5d3SJohn Marino struct gmp_primes_dtab {
4486d7f5d3SJohn Marino   mp_limb_t binv;
4586d7f5d3SJohn Marino   mp_limb_t lim;
4686d7f5d3SJohn Marino };
4786d7f5d3SJohn Marino 
4886d7f5d3SJohn Marino struct gmp_primes_ptab {
4986d7f5d3SJohn Marino   mp_limb_t ppp;	/* primes, multiplied together */
5086d7f5d3SJohn Marino   mp_limb_t cps[7];	/* ppp values pre-computed for mpn_mod_1s_4p */
5186d7f5d3SJohn Marino   unsigned int idx:24;	/* index of  first primes in dtab */
5286d7f5d3SJohn Marino   unsigned int np :8;	/* number of primes related to this entry */
5386d7f5d3SJohn Marino };
5486d7f5d3SJohn Marino 
5586d7f5d3SJohn Marino #define P(p,inv,lim) {inv,lim}
5686d7f5d3SJohn Marino 
5786d7f5d3SJohn Marino #include "trialdivtab.h"
5886d7f5d3SJohn Marino 
5986d7f5d3SJohn Marino #define PTAB_LINES (sizeof (gmp_primes_ptab) / sizeof (gmp_primes_ptab[0]))
6086d7f5d3SJohn Marino 
6186d7f5d3SJohn Marino /* Attempt to find a factor of T using trial division.
6286d7f5d3SJohn Marino    Input: A non-negative number T.
6386d7f5d3SJohn Marino    Output: non-zero if we found a factor, zero otherwise.  To get the actual
6486d7f5d3SJohn Marino    prime factor, compute the mod B inverse of the return value.  */
6586d7f5d3SJohn Marino /* FIXME: We could optimize out one of the outer loop conditions if we
6686d7f5d3SJohn Marino    had a final ptab entry with a huge nd field.  */
6786d7f5d3SJohn Marino mp_limb_t
mpn_trialdiv(mp_srcptr tp,mp_size_t tn,mp_size_t nprimes,int * where)6886d7f5d3SJohn Marino mpn_trialdiv (mp_srcptr tp, mp_size_t tn, mp_size_t nprimes, int *where)
6986d7f5d3SJohn Marino {
7086d7f5d3SJohn Marino   mp_limb_t ppp;
7186d7f5d3SJohn Marino   mp_limb_t *cps;
7286d7f5d3SJohn Marino   struct gmp_primes_dtab *dp;
7386d7f5d3SJohn Marino   long i, j, idx, np;
7486d7f5d3SJohn Marino   mp_limb_t r, q;
7586d7f5d3SJohn Marino 
7686d7f5d3SJohn Marino   ASSERT (tn >= 1);
7786d7f5d3SJohn Marino 
7886d7f5d3SJohn Marino   for (i = *where; i < PTAB_LINES; i++)
7986d7f5d3SJohn Marino     {
8086d7f5d3SJohn Marino       ppp = gmp_primes_ptab[i].ppp;
8186d7f5d3SJohn Marino       cps = gmp_primes_ptab[i].cps;
8286d7f5d3SJohn Marino 
8386d7f5d3SJohn Marino #if __GNU_MP_VERSION == 4 && __GNU_MP_VERSION_MINOR < 4
8486d7f5d3SJohn Marino       if (tn < 4)
8586d7f5d3SJohn Marino 	r = mpn_mod_1 (tp, tn, ppp); /* FIXME */
8686d7f5d3SJohn Marino       else
8786d7f5d3SJohn Marino #endif
8886d7f5d3SJohn Marino 	r = mpn_mod_1s_4p (tp, tn, ppp << cps[1], cps);
8986d7f5d3SJohn Marino 
9086d7f5d3SJohn Marino       idx = gmp_primes_ptab[i].idx;
9186d7f5d3SJohn Marino       np = gmp_primes_ptab[i].np;
9286d7f5d3SJohn Marino 
9386d7f5d3SJohn Marino       /* Check divisibility by individual primes.  */
9486d7f5d3SJohn Marino       dp = &gmp_primes_dtab[idx] + np;
9586d7f5d3SJohn Marino       for (j = -np; j < 0; j++)
9686d7f5d3SJohn Marino 	{
9786d7f5d3SJohn Marino 	  q = r * dp[j].binv;
9886d7f5d3SJohn Marino 	  if (q <= dp[j].lim)
9986d7f5d3SJohn Marino 	    {
10086d7f5d3SJohn Marino 	      *where = i;
10186d7f5d3SJohn Marino 	      return dp[j].binv;
10286d7f5d3SJohn Marino 	    }
10386d7f5d3SJohn Marino 	}
10486d7f5d3SJohn Marino 
10586d7f5d3SJohn Marino       nprimes -= np;
10686d7f5d3SJohn Marino       if (nprimes <= 0)
10786d7f5d3SJohn Marino 	return 0;
10886d7f5d3SJohn Marino     }
10986d7f5d3SJohn Marino   return 0;
11086d7f5d3SJohn Marino }
111