Blame mpn/generic/divis.c

Packit 5c3484
/* mpn_divisible_p -- mpn by mpn divisibility test
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, 2014 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 "gmp.h"
Packit 5c3484
#include "gmp-impl.h"
Packit 5c3484
#include "longlong.h"
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* Determine whether A={ap,an} is divisible by D={dp,dn}.  Must have both
Packit 5c3484
   operands normalized, meaning high limbs non-zero, except that an==0 is
Packit 5c3484
   allowed.
Packit 5c3484
Packit 5c3484
   There usually won't be many low zero bits on D, but the checks for this
Packit 5c3484
   are fast and might pick up a few operand combinations, in particular they
Packit 5c3484
   might reduce D to fit the single-limb mod_1/modexact_1 code.
Packit 5c3484
Packit 5c3484
   Future:
Packit 5c3484
Packit 5c3484
   Getting the remainder limb by limb would make an early exit possible on
Packit 5c3484
   finding a non-zero.  This would probably have to be bdivmod style so
Packit 5c3484
   there's no addback, but it would need a multi-precision inverse and so
Packit 5c3484
   might be slower than the plain method (on small sizes at least).
Packit 5c3484
Packit 5c3484
   When D must be normalized (shifted to low bit set), it's possible to
Packit 5c3484
   suppress the bit-shifting of A down, as long as it's already been checked
Packit 5c3484
   that A has at least as many trailing zero bits as D.  */
Packit 5c3484
Packit 5c3484
int
Packit 5c3484
mpn_divisible_p (mp_srcptr ap, mp_size_t an,
Packit 5c3484
		 mp_srcptr dp, mp_size_t dn)
Packit 5c3484
{
Packit 5c3484
  mp_limb_t  alow, dlow, dmask;
Packit 5c3484
  mp_ptr     qp, rp, tp;
Packit 5c3484
  mp_size_t  i;
Packit 5c3484
  mp_limb_t di;
Packit 5c3484
  unsigned  twos;
Packit 5c3484
  TMP_DECL;
Packit 5c3484
Packit 5c3484
  ASSERT (an >= 0);
Packit 5c3484
  ASSERT (an == 0 || ap[an-1] != 0);
Packit 5c3484
  ASSERT (dn >= 1);
Packit 5c3484
  ASSERT (dp[dn-1] != 0);
Packit 5c3484
  ASSERT_MPN (ap, an);
Packit 5c3484
  ASSERT_MPN (dp, dn);
Packit 5c3484
Packit 5c3484
  /* When a
Packit 5c3484
     Notice this test covers all cases of an==0. */
Packit 5c3484
  if (an < dn)
Packit 5c3484
    return (an == 0);
Packit 5c3484
Packit 5c3484
  /* Strip low zero limbs from d, requiring a==0 on those. */
Packit 5c3484
  for (;;)
Packit 5c3484
    {
Packit 5c3484
      alow = *ap;
Packit 5c3484
      dlow = *dp;
Packit 5c3484
Packit 5c3484
      if (dlow != 0)
Packit 5c3484
	break;
Packit 5c3484
Packit 5c3484
      if (alow != 0)
Packit 5c3484
	return 0;  /* a has fewer low zero limbs than d, so not divisible */
Packit 5c3484
Packit 5c3484
      /* a!=0 and d!=0 so won't get to n==0 */
Packit 5c3484
      an--; ASSERT (an >= 1);
Packit 5c3484
      dn--; ASSERT (dn >= 1);
Packit 5c3484
      ap++;
Packit 5c3484
      dp++;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  /* a must have at least as many low zero bits as d */
Packit 5c3484
  dmask = LOW_ZEROS_MASK (dlow);
Packit 5c3484
  if ((alow & dmask) != 0)
Packit 5c3484
    return 0;
Packit 5c3484
Packit 5c3484
  if (dn == 1)
Packit 5c3484
    {
Packit 5c3484
      if (ABOVE_THRESHOLD (an, BMOD_1_TO_MOD_1_THRESHOLD))
Packit 5c3484
	return mpn_mod_1 (ap, an, dlow) == 0;
Packit 5c3484
Packit 5c3484
      count_trailing_zeros (twos, dlow);
Packit 5c3484
      dlow >>= twos;
Packit 5c3484
      return mpn_modexact_1_odd (ap, an, dlow) == 0;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  count_trailing_zeros (twos, dlow);
Packit 5c3484
  if (dn == 2)
Packit 5c3484
    {
Packit 5c3484
      mp_limb_t  dsecond = dp[1];
Packit 5c3484
      if (dsecond <= dmask)
Packit 5c3484
	{
Packit 5c3484
	  dlow = (dlow >> twos) | (dsecond << (GMP_NUMB_BITS-twos));
Packit 5c3484
	  ASSERT_LIMB (dlow);
Packit 5c3484
	  return MPN_MOD_OR_MODEXACT_1_ODD (ap, an, dlow) == 0;
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  /* Should we compute Q = A * D^(-1) mod B^k,
Packit 5c3484
                       R = A - Q * D  mod B^k
Packit 5c3484
     here, for some small values of k?  Then check if R = 0 (mod B^k).  */
Packit 5c3484
Packit 5c3484
  /* We could also compute A' = A mod T and D' = D mod P, for some
Packit 5c3484
     P = 3 * 5 * 7 * 11 ..., and then check if any prime factor from P
Packit 5c3484
     dividing D' also divides A'.  */
Packit 5c3484
Packit 5c3484
  TMP_MARK;
Packit 5c3484
Packit 5c3484
  TMP_ALLOC_LIMBS_2 (rp, an + 1,
Packit 5c3484
		     qp, an - dn + 1); /* FIXME: Could we avoid this? */
Packit 5c3484
Packit 5c3484
  if (twos != 0)
Packit 5c3484
    {
Packit 5c3484
      tp = TMP_ALLOC_LIMBS (dn);
Packit 5c3484
      ASSERT_NOCARRY (mpn_rshift (tp, dp, dn, twos));
Packit 5c3484
      dp = tp;
Packit 5c3484
Packit 5c3484
      ASSERT_NOCARRY (mpn_rshift (rp, ap, an, twos));
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
      MPN_COPY (rp, ap, an);
Packit 5c3484
    }
Packit 5c3484
  if (rp[an - 1] >= dp[dn - 1])
Packit 5c3484
    {
Packit 5c3484
      rp[an] = 0;
Packit 5c3484
      an++;
Packit 5c3484
    }
Packit 5c3484
  else if (an == dn)
Packit 5c3484
    {
Packit 5c3484
      TMP_FREE;
Packit 5c3484
      return 0;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  ASSERT (an > dn);		/* requirement of functions below */
Packit 5c3484
Packit 5c3484
  if (BELOW_THRESHOLD (dn, DC_BDIV_QR_THRESHOLD) ||
Packit 5c3484
      BELOW_THRESHOLD (an - dn, DC_BDIV_QR_THRESHOLD))
Packit 5c3484
    {
Packit 5c3484
      binvert_limb (di, dp[0]);
Packit 5c3484
      mpn_sbpi1_bdiv_qr (qp, rp, an, dp, dn, -di);
Packit 5c3484
      rp += an - dn;
Packit 5c3484
    }
Packit 5c3484
  else if (BELOW_THRESHOLD (dn, MU_BDIV_QR_THRESHOLD))
Packit 5c3484
    {
Packit 5c3484
      binvert_limb (di, dp[0]);
Packit 5c3484
      mpn_dcpi1_bdiv_qr (qp, rp, an, dp, dn, -di);
Packit 5c3484
      rp += an - dn;
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
      tp = TMP_ALLOC_LIMBS (mpn_mu_bdiv_qr_itch (an, dn));
Packit 5c3484
      mpn_mu_bdiv_qr (qp, rp, rp, an, dp, dn, tp);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  /* test for {rp,dn} zero or non-zero */
Packit 5c3484
  i = 0;
Packit 5c3484
  do
Packit 5c3484
    {
Packit 5c3484
      if (rp[i] != 0)
Packit 5c3484
	{
Packit 5c3484
	  TMP_FREE;
Packit 5c3484
	  return 0;
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
  while (++i < dn);
Packit 5c3484
Packit 5c3484
  TMP_FREE;
Packit 5c3484
  return 1;
Packit 5c3484
}