version 1.1, 2000/01/10 15:35:27 |
version 1.1.1.3, 2003/08/25 16:06:33 |
|
|
/* mpz_scan0(op, startbit) -- Scan for the next set bit, starting at startbit. |
/* mpz_scan0 -- search for a 0 bit. |
|
|
Copyright (C) 1996 Free Software Foundation, Inc. |
Copyright 2000, 2001, 2002 Free Software Foundation, Inc. |
|
|
This file is part of the GNU MP Library. |
This file is part of the GNU MP Library. |
|
|
The GNU MP Library is free software; you can redistribute it and/or modify |
The GNU MP Library is free software; you can redistribute it and/or modify |
it under the terms of the GNU Library General Public License as published by |
it under the terms of the GNU Lesser General Public License as published by |
the Free Software Foundation; either version 2 of the License, or (at your |
the Free Software Foundation; either version 2.1 of the License, or (at your |
option) any later version. |
option) any later version. |
|
|
The GNU MP Library is distributed in the hope that it will be useful, but |
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 |
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public |
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
License for more details. |
License for more details. |
|
|
You should have received a copy of the GNU Library General Public License |
You should have received a copy of the GNU Lesser General Public License |
along with the GNU MP Library; see the file COPYING.LIB. If not, write to |
along with the GNU MP Library; see the file COPYING.LIB. If not, write to |
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
MA 02111-1307, USA. */ |
MA 02111-1307, USA. */ |
|
|
#include "gmp.h" |
#include "gmp.h" |
#include "gmp-impl.h" |
#include "gmp-impl.h" |
|
#include "longlong.h" |
|
|
unsigned long int |
|
#if __STDC__ |
/* mpn_scan0 can't be used for the u>0 search since there might not be a 0 |
mpz_scan0 (mpz_srcptr u, unsigned long int starting_bit) |
bit before the end of the data. mpn_scan1 could be used for the inverted |
#else |
search under u<0, but usually the search won't go very far so it seems |
mpz_scan0 (u, starting_bit) |
reasonable to inline that code. */ |
mpz_srcptr u; |
|
unsigned long int starting_bit; |
unsigned long |
#endif |
mpz_scan0 (mpz_srcptr u, unsigned long starting_bit) |
{ |
{ |
return mpn_scan0 (u->_mp_d, starting_bit); |
mp_srcptr u_ptr = PTR(u); |
|
mp_size_t size = SIZ(u); |
|
mp_size_t abs_size = ABS(size); |
|
mp_srcptr u_end = u_ptr + abs_size; |
|
unsigned long starting_limb = starting_bit / GMP_NUMB_BITS; |
|
mp_srcptr p = u_ptr + starting_limb; |
|
mp_limb_t limb; |
|
int cnt; |
|
|
|
/* When past end, there's an immediate 0 bit for u>=0, or no 0 bits for |
|
u<0. Notice this test picks up all cases of u==0 too. */ |
|
if (starting_limb >= abs_size) |
|
return (size >= 0 ? starting_bit : ULONG_MAX); |
|
|
|
limb = *p; |
|
|
|
if (size >= 0) |
|
{ |
|
/* Mask to 1 all bits before starting_bit, thus ignoring them. */ |
|
limb |= (CNST_LIMB(1) << (starting_bit % GMP_NUMB_BITS)) - 1; |
|
|
|
/* Search for a limb which isn't all ones. If the end is reached then |
|
the zero bit immediately past the end is returned. */ |
|
while (limb == GMP_NUMB_MAX) |
|
{ |
|
p++; |
|
if (p == u_end) |
|
return (unsigned long) abs_size * GMP_NUMB_BITS; |
|
limb = *p; |
|
} |
|
|
|
/* Now seek low 1 bit. */ |
|
limb = ~limb; |
|
} |
|
else |
|
{ |
|
mp_srcptr q; |
|
|
|
/* If there's a non-zero limb before ours then we're in the ones |
|
complement region. Search from *(p-1) downwards since that might |
|
give better cache locality, and since a non-zero in the middle of a |
|
number is perhaps a touch more likely than at the end. */ |
|
q = p; |
|
while (q != u_ptr) |
|
{ |
|
q--; |
|
if (*q != 0) |
|
goto inverted; |
|
} |
|
|
|
/* Adjust so ~limb implied by searching for 1 bit below becomes -limb. |
|
If limb==0 here then this isn't the beginning of twos complement |
|
inversion, but that doesn't matter because limb==0 is a zero bit |
|
immediately (-1 is all ones for below). */ |
|
limb--; |
|
|
|
inverted: |
|
/* Now seeking a 1 bit. */ |
|
|
|
/* Mask to 0 all bits before starting_bit, thus ignoring them. */ |
|
limb &= (MP_LIMB_T_MAX << (starting_bit % GMP_NUMB_BITS)); |
|
|
|
if (limb == 0) |
|
{ |
|
/* If the high limb is zero after masking, then no 1 bits past |
|
starting_bit. */ |
|
p++; |
|
if (p == u_end) |
|
return ULONG_MAX; |
|
|
|
/* Search further for a non-zero limb. The high limb is non-zero, |
|
if nothing else. */ |
|
for (;;) |
|
{ |
|
limb = *p; |
|
if (limb != 0) |
|
break; |
|
p++; |
|
ASSERT (p < u_end); |
|
} |
|
} |
|
} |
|
|
|
/* Mask to 0 all bits above the lowest 1 bit. */ |
|
ASSERT (limb != 0); |
|
limb &= -limb; |
|
|
|
count_leading_zeros (cnt, limb); |
|
return (p - u_ptr) * GMP_NUMB_BITS + GMP_LIMB_BITS - 1 - cnt; |
} |
} |