version 1.1.1.2, 2000/09/09 14:12:53 |
version 1.1.1.3, 2003/08/25 16:06:33 |
|
|
/* mpz_hamdist(mpz_ptr op1, mpz_ptr op2) -- Compute the hamming distance |
/* mpz_hamdist -- calculate hamming distance. |
between OP1 and OP2. If one of the operands is negative, return ~0. (We |
|
could make the function well-defined when both operands are negative, but |
|
that would probably not be worth the trouble. |
|
|
|
Copyright (C) 1994, 1996 Free Software Foundation, Inc. |
Copyright 1994, 1996, 2001, 2002 Free Software Foundation, Inc. |
|
|
This file is part of the GNU MP Library. |
This file is part of the GNU MP Library. |
|
|
Line 25 MA 02111-1307, USA. */ |
|
Line 22 MA 02111-1307, USA. */ |
|
#include "gmp.h" |
#include "gmp.h" |
#include "gmp-impl.h" |
#include "gmp-impl.h" |
|
|
unsigned long int |
|
#if __STDC__ |
unsigned long |
mpz_hamdist (mpz_srcptr u, mpz_srcptr v) |
mpz_hamdist (mpz_srcptr u, mpz_srcptr v) |
#else |
|
mpz_hamdist (u, v) |
|
mpz_srcptr u; |
|
mpz_srcptr v; |
|
#endif |
|
{ |
{ |
mp_srcptr up, vp; |
mp_srcptr up, vp; |
mp_size_t usize, vsize, size; |
mp_size_t usize, vsize; |
unsigned long int count; |
unsigned long count; |
|
|
usize = u->_mp_size; |
usize = SIZ(u); |
vsize = v->_mp_size; |
vsize = SIZ(v); |
|
|
if ((usize | vsize) < 0) |
up = PTR(u); |
return ~ (unsigned long int) 0; |
vp = PTR(v); |
|
|
up = u->_mp_d; |
if (usize >= 0) |
vp = v->_mp_d; |
|
|
|
if (usize > vsize) |
|
{ |
{ |
count = mpn_popcount (up + vsize, usize - vsize); |
if (vsize < 0) |
size = vsize; |
return ~ (unsigned long) 0; |
|
|
|
/* positive/positive */ |
|
|
|
if (usize < vsize) |
|
MPN_SRCPTR_SWAP (up,usize, vp,vsize); |
|
|
|
count = 0; |
|
if (vsize != 0) |
|
count = mpn_hamdist (up, vp, vsize); |
|
|
|
usize -= vsize; |
|
if (usize != 0) |
|
count += mpn_popcount (up + vsize, usize); |
|
|
|
return count; |
} |
} |
else |
else |
{ |
{ |
count = mpn_popcount (vp + usize, vsize - usize); |
mp_limb_t ulimb, vlimb; |
size = usize; |
mp_size_t old_vsize, step; |
} |
|
|
|
return count + mpn_hamdist (up, vp, size); |
if (vsize >= 0) |
|
return ~ (unsigned long) 0; |
|
|
|
/* negative/negative */ |
|
|
|
usize = -usize; |
|
vsize = -vsize; |
|
|
|
/* skip common low zeros */ |
|
for (;;) |
|
{ |
|
ASSERT (usize > 0); |
|
ASSERT (vsize > 0); |
|
|
|
usize--; |
|
vsize--; |
|
|
|
ulimb = *up++; |
|
vlimb = *vp++; |
|
|
|
if (ulimb != 0) |
|
break; |
|
|
|
if (vlimb != 0) |
|
{ |
|
MPN_SRCPTR_SWAP (up,usize, vp,vsize); |
|
ulimb = vlimb; |
|
vlimb = 0; |
|
break; |
|
} |
|
} |
|
|
|
/* twos complement first non-zero limbs (ulimb is non-zero, but vlimb |
|
might be zero) */ |
|
ulimb = -ulimb; |
|
vlimb = -vlimb; |
|
popc_limb (count, (ulimb ^ vlimb) & GMP_NUMB_MASK); |
|
|
|
if (vlimb == 0) |
|
{ |
|
unsigned long twoscount; |
|
|
|
/* first non-zero of v */ |
|
old_vsize = vsize; |
|
do |
|
{ |
|
ASSERT (vsize > 0); |
|
vsize--; |
|
vlimb = *vp++; |
|
} |
|
while (vlimb == 0); |
|
|
|
/* part of u corresponding to skipped v zeros */ |
|
step = old_vsize - vsize - 1; |
|
count += step * GMP_NUMB_BITS; |
|
step = MIN (step, usize); |
|
if (step != 0) |
|
{ |
|
count -= mpn_popcount (up, step); |
|
usize -= step; |
|
up += step; |
|
} |
|
|
|
/* First non-zero vlimb as twos complement, xor with ones |
|
complement ulimb. Note -v^(~0^u) == (v-1)^u. */ |
|
vlimb--; |
|
if (usize != 0) |
|
{ |
|
usize--; |
|
vlimb ^= *up++; |
|
} |
|
popc_limb (twoscount, vlimb); |
|
count += twoscount; |
|
} |
|
|
|
/* Overlapping part of u and v, if any. Ones complement both, so just |
|
plain hamdist. */ |
|
step = MIN (usize, vsize); |
|
if (step != 0) |
|
{ |
|
count += mpn_hamdist (up, vp, step); |
|
usize -= step; |
|
vsize -= step; |
|
up += step; |
|
vp += step; |
|
} |
|
|
|
/* Remaining high part of u or v, if any, ones complement but xor |
|
against all ones in the other, so plain popcount. */ |
|
if (usize != 0) |
|
{ |
|
remaining: |
|
count += mpn_popcount (up, usize); |
|
} |
|
else if (vsize != 0) |
|
{ |
|
up = vp; |
|
usize = vsize; |
|
goto remaining; |
|
} |
|
return count; |
|
} |
} |
} |