| 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; |
| |
} |
| } |
} |