Home | History | Annotate | Line # | Download | only in mpz
      1      1.1  mrg /* mpz_hamdist -- calculate hamming distance.
      2      1.1  mrg 
      3  1.1.1.3  mrg Copyright 1994, 1996, 2001, 2002, 2009-2011 Free Software Foundation, Inc.
      4      1.1  mrg 
      5      1.1  mrg This file is part of the GNU MP Library.
      6      1.1  mrg 
      7      1.1  mrg The GNU MP Library is free software; you can redistribute it and/or modify
      8  1.1.1.3  mrg it under the terms of either:
      9  1.1.1.3  mrg 
     10  1.1.1.3  mrg   * the GNU Lesser General Public License as published by the Free
     11  1.1.1.3  mrg     Software Foundation; either version 3 of the License, or (at your
     12  1.1.1.3  mrg     option) any later version.
     13  1.1.1.3  mrg 
     14  1.1.1.3  mrg or
     15  1.1.1.3  mrg 
     16  1.1.1.3  mrg   * the GNU General Public License as published by the Free Software
     17  1.1.1.3  mrg     Foundation; either version 2 of the License, or (at your option) any
     18  1.1.1.3  mrg     later version.
     19  1.1.1.3  mrg 
     20  1.1.1.3  mrg or both in parallel, as here.
     21      1.1  mrg 
     22      1.1  mrg The GNU MP Library is distributed in the hope that it will be useful, but
     23      1.1  mrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     24  1.1.1.3  mrg or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     25  1.1.1.3  mrg for more details.
     26      1.1  mrg 
     27  1.1.1.3  mrg You should have received copies of the GNU General Public License and the
     28  1.1.1.3  mrg GNU Lesser General Public License along with the GNU MP Library.  If not,
     29  1.1.1.3  mrg see https://www.gnu.org/licenses/.  */
     30      1.1  mrg 
     31      1.1  mrg #include "gmp-impl.h"
     32      1.1  mrg 
     33      1.1  mrg 
     34      1.1  mrg mp_bitcnt_t
     35  1.1.1.2  mrg mpz_hamdist (mpz_srcptr u, mpz_srcptr v) __GMP_NOTHROW
     36      1.1  mrg {
     37      1.1  mrg   mp_srcptr      up, vp;
     38      1.1  mrg   mp_size_t      usize, vsize;
     39      1.1  mrg   mp_bitcnt_t    count;
     40      1.1  mrg 
     41      1.1  mrg   usize = SIZ(u);
     42      1.1  mrg   vsize = SIZ(v);
     43      1.1  mrg 
     44      1.1  mrg   up = PTR(u);
     45      1.1  mrg   vp = PTR(v);
     46      1.1  mrg 
     47      1.1  mrg   if (usize >= 0)
     48      1.1  mrg     {
     49      1.1  mrg       if (vsize < 0)
     50  1.1.1.2  mrg 	return ~ (mp_bitcnt_t) 0;
     51      1.1  mrg 
     52      1.1  mrg       /* positive/positive */
     53      1.1  mrg 
     54      1.1  mrg       if (usize < vsize)
     55  1.1.1.2  mrg 	MPN_SRCPTR_SWAP (up,usize, vp,vsize);
     56      1.1  mrg 
     57      1.1  mrg       count = 0;
     58      1.1  mrg       if (vsize != 0)
     59  1.1.1.2  mrg 	count = mpn_hamdist (up, vp, vsize);
     60      1.1  mrg 
     61      1.1  mrg       usize -= vsize;
     62      1.1  mrg       if (usize != 0)
     63  1.1.1.2  mrg 	count += mpn_popcount (up + vsize, usize);
     64      1.1  mrg 
     65      1.1  mrg       return count;
     66      1.1  mrg     }
     67      1.1  mrg   else
     68      1.1  mrg     {
     69      1.1  mrg       mp_limb_t  ulimb, vlimb;
     70      1.1  mrg       mp_size_t  old_vsize, step;
     71      1.1  mrg 
     72      1.1  mrg       if (vsize >= 0)
     73  1.1.1.2  mrg 	return ~ (mp_bitcnt_t) 0;
     74      1.1  mrg 
     75      1.1  mrg       /* negative/negative */
     76      1.1  mrg 
     77      1.1  mrg       usize = -usize;
     78      1.1  mrg       vsize = -vsize;
     79      1.1  mrg 
     80      1.1  mrg       /* skip common low zeros */
     81      1.1  mrg       for (;;)
     82  1.1.1.2  mrg 	{
     83  1.1.1.2  mrg 	  ASSERT (usize > 0);
     84  1.1.1.2  mrg 	  ASSERT (vsize > 0);
     85  1.1.1.2  mrg 
     86  1.1.1.2  mrg 	  usize--;
     87  1.1.1.2  mrg 	  vsize--;
     88  1.1.1.2  mrg 
     89  1.1.1.2  mrg 	  ulimb = *up++;
     90  1.1.1.2  mrg 	  vlimb = *vp++;
     91  1.1.1.2  mrg 
     92  1.1.1.2  mrg 	  if (ulimb != 0)
     93  1.1.1.2  mrg 	    break;
     94  1.1.1.2  mrg 
     95  1.1.1.2  mrg 	  if (vlimb != 0)
     96  1.1.1.2  mrg 	    {
     97  1.1.1.2  mrg 	      MPN_SRCPTR_SWAP (up,usize, vp,vsize);
     98  1.1.1.2  mrg 	      ulimb = vlimb;
     99  1.1.1.2  mrg 	      vlimb = 0;
    100  1.1.1.2  mrg 	      break;
    101  1.1.1.2  mrg 	    }
    102  1.1.1.2  mrg 	}
    103      1.1  mrg 
    104      1.1  mrg       /* twos complement first non-zero limbs (ulimb is non-zero, but vlimb
    105  1.1.1.2  mrg 	 might be zero) */
    106      1.1  mrg       ulimb = -ulimb;
    107      1.1  mrg       vlimb = -vlimb;
    108      1.1  mrg       popc_limb (count, (ulimb ^ vlimb) & GMP_NUMB_MASK);
    109      1.1  mrg 
    110      1.1  mrg       if (vlimb == 0)
    111  1.1.1.2  mrg 	{
    112  1.1.1.2  mrg 	  mp_bitcnt_t  twoscount;
    113      1.1  mrg 
    114  1.1.1.2  mrg 	  /* first non-zero of v */
    115  1.1.1.2  mrg 	  old_vsize = vsize;
    116  1.1.1.2  mrg 	  do
    117  1.1.1.2  mrg 	    {
    118  1.1.1.2  mrg 	      ASSERT (vsize > 0);
    119  1.1.1.2  mrg 	      vsize--;
    120  1.1.1.2  mrg 	      vlimb = *vp++;
    121  1.1.1.2  mrg 	    }
    122  1.1.1.2  mrg 	  while (vlimb == 0);
    123  1.1.1.2  mrg 
    124  1.1.1.2  mrg 	  /* part of u corresponding to skipped v zeros */
    125  1.1.1.2  mrg 	  step = old_vsize - vsize - 1;
    126  1.1.1.2  mrg 	  count += step * GMP_NUMB_BITS;
    127  1.1.1.2  mrg 	  step = MIN (step, usize);
    128  1.1.1.2  mrg 	  if (step != 0)
    129  1.1.1.2  mrg 	    {
    130  1.1.1.2  mrg 	      count -= mpn_popcount (up, step);
    131  1.1.1.2  mrg 	      usize -= step;
    132  1.1.1.2  mrg 	      up += step;
    133  1.1.1.2  mrg 	    }
    134  1.1.1.2  mrg 
    135  1.1.1.2  mrg 	  /* First non-zero vlimb as twos complement, xor with ones
    136  1.1.1.2  mrg 	     complement ulimb.  Note -v^(~0^u) == (v-1)^u. */
    137  1.1.1.2  mrg 	  vlimb--;
    138  1.1.1.2  mrg 	  if (usize != 0)
    139  1.1.1.2  mrg 	    {
    140  1.1.1.2  mrg 	      usize--;
    141  1.1.1.2  mrg 	      vlimb ^= *up++;
    142  1.1.1.2  mrg 	    }
    143  1.1.1.2  mrg 	  popc_limb (twoscount, vlimb);
    144  1.1.1.2  mrg 	  count += twoscount;
    145  1.1.1.2  mrg 	}
    146      1.1  mrg 
    147      1.1  mrg       /* Overlapping part of u and v, if any.  Ones complement both, so just
    148  1.1.1.2  mrg 	 plain hamdist. */
    149      1.1  mrg       step = MIN (usize, vsize);
    150      1.1  mrg       if (step != 0)
    151  1.1.1.2  mrg 	{
    152  1.1.1.2  mrg 	  count += mpn_hamdist (up, vp, step);
    153  1.1.1.2  mrg 	  usize -= step;
    154  1.1.1.2  mrg 	  vsize -= step;
    155  1.1.1.2  mrg 	  up += step;
    156  1.1.1.2  mrg 	  vp += step;
    157  1.1.1.2  mrg 	}
    158      1.1  mrg 
    159      1.1  mrg       /* Remaining high part of u or v, if any, ones complement but xor
    160  1.1.1.2  mrg 	 against all ones in the other, so plain popcount. */
    161      1.1  mrg       if (usize != 0)
    162  1.1.1.2  mrg 	{
    163  1.1.1.2  mrg 	remaining:
    164  1.1.1.2  mrg 	  count += mpn_popcount (up, usize);
    165  1.1.1.2  mrg 	}
    166      1.1  mrg       else if (vsize != 0)
    167  1.1.1.2  mrg 	{
    168  1.1.1.2  mrg 	  up = vp;
    169  1.1.1.2  mrg 	  usize = vsize;
    170  1.1.1.2  mrg 	  goto remaining;
    171  1.1.1.2  mrg 	}
    172      1.1  mrg       return count;
    173      1.1  mrg     }
    174      1.1  mrg }
    175