blob: ead0ddd23b44c063a065f8635b7ba7a77881d62a [file] [log] [blame]
/* mpz_divisible_ui_p -- mpz by ulong divisibility test.
Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of the GNU MP Library.
The GNU MP Library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or (at your
option) any later version.
The GNU MP Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
#include "gmp.h"
#include "gmp-impl.h"
#include "longlong.h"
int
mpz_divisible_ui_p (mpz_srcptr a, unsigned long d)
{
mp_size_t asize;
mp_ptr ap;
unsigned twos;
asize = SIZ(a);
if (UNLIKELY (d == 0))
return (asize == 0);
if (asize == 0) /* 0 divisible by any d */
return 1;
/* For nails don't try to be clever if d is bigger than a limb, just fake
up an mpz_t and go to the main mpz_divisible_p. */
if (d > GMP_NUMB_MAX)
{
mp_limb_t dlimbs[2];
mpz_t dz;
ALLOC(dz) = 2;
PTR(dz) = dlimbs;
mpz_set_ui (dz, d);
return mpz_divisible_p (a, dz);
}
ap = PTR(a);
asize = ABS(asize); /* ignore sign of a */
if (BELOW_THRESHOLD (asize, MODEXACT_1_ODD_THRESHOLD))
return mpn_mod_1 (ap, asize, (mp_limb_t) d) == 0;
if (! (d & 1))
{
/* Strip low zero bits to get odd d required by modexact. If d==e*2^n
and a is divisible by 2^n and by e, then it's divisible by d. */
if ((ap[0] & LOW_ZEROS_MASK (d)) != 0)
return 0;
count_trailing_zeros (twos, (mp_limb_t) d);
d >>= twos;
}
return mpn_modexact_1_odd (ap, asize, (mp_limb_t) d) == 0;
}