xref: /dflybsd-src/contrib/gmp/mpz/hamdist.c (revision d365564473a20a528d07c59cad8ee2f4bea5546f)
14b6a78b7SSimon Schubert /* mpz_hamdist -- calculate hamming distance.
24b6a78b7SSimon Schubert 
3*d2d4b659SJohn Marino Copyright 1994, 1996, 2001, 2002, 2009, 2010, 2011 Free Software Foundation,
4*d2d4b659SJohn Marino Inc.
54b6a78b7SSimon Schubert 
64b6a78b7SSimon Schubert This file is part of the GNU MP Library.
74b6a78b7SSimon Schubert 
84b6a78b7SSimon Schubert The GNU MP Library is free software; you can redistribute it and/or modify
94b6a78b7SSimon Schubert it under the terms of the GNU Lesser General Public License as published by
104b6a78b7SSimon Schubert the Free Software Foundation; either version 3 of the License, or (at your
114b6a78b7SSimon Schubert option) any later version.
124b6a78b7SSimon Schubert 
134b6a78b7SSimon Schubert The GNU MP Library is distributed in the hope that it will be useful, but
144b6a78b7SSimon Schubert WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
154b6a78b7SSimon Schubert or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
164b6a78b7SSimon Schubert License for more details.
174b6a78b7SSimon Schubert 
184b6a78b7SSimon Schubert You should have received a copy of the GNU Lesser General Public License
194b6a78b7SSimon Schubert along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
204b6a78b7SSimon Schubert 
214b6a78b7SSimon Schubert #include "gmp.h"
224b6a78b7SSimon Schubert #include "gmp-impl.h"
234b6a78b7SSimon Schubert 
244b6a78b7SSimon Schubert 
2554028e53SJohn Marino mp_bitcnt_t
mpz_hamdist(mpz_srcptr u,mpz_srcptr v)26*d2d4b659SJohn Marino mpz_hamdist (mpz_srcptr u, mpz_srcptr v) __GMP_NOTHROW
274b6a78b7SSimon Schubert {
284b6a78b7SSimon Schubert   mp_srcptr      up, vp;
294b6a78b7SSimon Schubert   mp_size_t      usize, vsize;
3054028e53SJohn Marino   mp_bitcnt_t    count;
314b6a78b7SSimon Schubert 
324b6a78b7SSimon Schubert   usize = SIZ(u);
334b6a78b7SSimon Schubert   vsize = SIZ(v);
344b6a78b7SSimon Schubert 
354b6a78b7SSimon Schubert   up = PTR(u);
364b6a78b7SSimon Schubert   vp = PTR(v);
374b6a78b7SSimon Schubert 
384b6a78b7SSimon Schubert   if (usize >= 0)
394b6a78b7SSimon Schubert     {
404b6a78b7SSimon Schubert       if (vsize < 0)
4154028e53SJohn Marino 	return ~ (mp_bitcnt_t) 0;
424b6a78b7SSimon Schubert 
434b6a78b7SSimon Schubert       /* positive/positive */
444b6a78b7SSimon Schubert 
454b6a78b7SSimon Schubert       if (usize < vsize)
464b6a78b7SSimon Schubert 	MPN_SRCPTR_SWAP (up,usize, vp,vsize);
474b6a78b7SSimon Schubert 
484b6a78b7SSimon Schubert       count = 0;
494b6a78b7SSimon Schubert       if (vsize != 0)
504b6a78b7SSimon Schubert 	count = mpn_hamdist (up, vp, vsize);
514b6a78b7SSimon Schubert 
524b6a78b7SSimon Schubert       usize -= vsize;
534b6a78b7SSimon Schubert       if (usize != 0)
544b6a78b7SSimon Schubert 	count += mpn_popcount (up + vsize, usize);
554b6a78b7SSimon Schubert 
564b6a78b7SSimon Schubert       return count;
574b6a78b7SSimon Schubert     }
584b6a78b7SSimon Schubert   else
594b6a78b7SSimon Schubert     {
604b6a78b7SSimon Schubert       mp_limb_t  ulimb, vlimb;
614b6a78b7SSimon Schubert       mp_size_t  old_vsize, step;
624b6a78b7SSimon Schubert 
634b6a78b7SSimon Schubert       if (vsize >= 0)
64*d2d4b659SJohn Marino 	return ~ (mp_bitcnt_t) 0;
654b6a78b7SSimon Schubert 
664b6a78b7SSimon Schubert       /* negative/negative */
674b6a78b7SSimon Schubert 
684b6a78b7SSimon Schubert       usize = -usize;
694b6a78b7SSimon Schubert       vsize = -vsize;
704b6a78b7SSimon Schubert 
714b6a78b7SSimon Schubert       /* skip common low zeros */
724b6a78b7SSimon Schubert       for (;;)
734b6a78b7SSimon Schubert 	{
744b6a78b7SSimon Schubert 	  ASSERT (usize > 0);
754b6a78b7SSimon Schubert 	  ASSERT (vsize > 0);
764b6a78b7SSimon Schubert 
774b6a78b7SSimon Schubert 	  usize--;
784b6a78b7SSimon Schubert 	  vsize--;
794b6a78b7SSimon Schubert 
804b6a78b7SSimon Schubert 	  ulimb = *up++;
814b6a78b7SSimon Schubert 	  vlimb = *vp++;
824b6a78b7SSimon Schubert 
834b6a78b7SSimon Schubert 	  if (ulimb != 0)
844b6a78b7SSimon Schubert 	    break;
854b6a78b7SSimon Schubert 
864b6a78b7SSimon Schubert 	  if (vlimb != 0)
874b6a78b7SSimon Schubert 	    {
884b6a78b7SSimon Schubert 	      MPN_SRCPTR_SWAP (up,usize, vp,vsize);
894b6a78b7SSimon Schubert 	      ulimb = vlimb;
904b6a78b7SSimon Schubert 	      vlimb = 0;
914b6a78b7SSimon Schubert 	      break;
924b6a78b7SSimon Schubert 	    }
934b6a78b7SSimon Schubert 	}
944b6a78b7SSimon Schubert 
954b6a78b7SSimon Schubert       /* twos complement first non-zero limbs (ulimb is non-zero, but vlimb
964b6a78b7SSimon Schubert 	 might be zero) */
974b6a78b7SSimon Schubert       ulimb = -ulimb;
984b6a78b7SSimon Schubert       vlimb = -vlimb;
994b6a78b7SSimon Schubert       popc_limb (count, (ulimb ^ vlimb) & GMP_NUMB_MASK);
1004b6a78b7SSimon Schubert 
1014b6a78b7SSimon Schubert       if (vlimb == 0)
1024b6a78b7SSimon Schubert 	{
10354028e53SJohn Marino 	  mp_bitcnt_t  twoscount;
1044b6a78b7SSimon Schubert 
1054b6a78b7SSimon Schubert 	  /* first non-zero of v */
1064b6a78b7SSimon Schubert 	  old_vsize = vsize;
1074b6a78b7SSimon Schubert 	  do
1084b6a78b7SSimon Schubert 	    {
1094b6a78b7SSimon Schubert 	      ASSERT (vsize > 0);
1104b6a78b7SSimon Schubert 	      vsize--;
1114b6a78b7SSimon Schubert 	      vlimb = *vp++;
1124b6a78b7SSimon Schubert 	    }
1134b6a78b7SSimon Schubert 	  while (vlimb == 0);
1144b6a78b7SSimon Schubert 
1154b6a78b7SSimon Schubert 	  /* part of u corresponding to skipped v zeros */
1164b6a78b7SSimon Schubert 	  step = old_vsize - vsize - 1;
1174b6a78b7SSimon Schubert 	  count += step * GMP_NUMB_BITS;
1184b6a78b7SSimon Schubert 	  step = MIN (step, usize);
1194b6a78b7SSimon Schubert 	  if (step != 0)
1204b6a78b7SSimon Schubert 	    {
1214b6a78b7SSimon Schubert 	      count -= mpn_popcount (up, step);
1224b6a78b7SSimon Schubert 	      usize -= step;
1234b6a78b7SSimon Schubert 	      up += step;
1244b6a78b7SSimon Schubert 	    }
1254b6a78b7SSimon Schubert 
1264b6a78b7SSimon Schubert 	  /* First non-zero vlimb as twos complement, xor with ones
1274b6a78b7SSimon Schubert 	     complement ulimb.  Note -v^(~0^u) == (v-1)^u. */
1284b6a78b7SSimon Schubert 	  vlimb--;
1294b6a78b7SSimon Schubert 	  if (usize != 0)
1304b6a78b7SSimon Schubert 	    {
1314b6a78b7SSimon Schubert 	      usize--;
1324b6a78b7SSimon Schubert 	      vlimb ^= *up++;
1334b6a78b7SSimon Schubert 	    }
1344b6a78b7SSimon Schubert 	  popc_limb (twoscount, vlimb);
1354b6a78b7SSimon Schubert 	  count += twoscount;
1364b6a78b7SSimon Schubert 	}
1374b6a78b7SSimon Schubert 
1384b6a78b7SSimon Schubert       /* Overlapping part of u and v, if any.  Ones complement both, so just
1394b6a78b7SSimon Schubert 	 plain hamdist. */
1404b6a78b7SSimon Schubert       step = MIN (usize, vsize);
1414b6a78b7SSimon Schubert       if (step != 0)
1424b6a78b7SSimon Schubert 	{
1434b6a78b7SSimon Schubert 	  count += mpn_hamdist (up, vp, step);
1444b6a78b7SSimon Schubert 	  usize -= step;
1454b6a78b7SSimon Schubert 	  vsize -= step;
1464b6a78b7SSimon Schubert 	  up += step;
1474b6a78b7SSimon Schubert 	  vp += step;
1484b6a78b7SSimon Schubert 	}
1494b6a78b7SSimon Schubert 
1504b6a78b7SSimon Schubert       /* Remaining high part of u or v, if any, ones complement but xor
1514b6a78b7SSimon Schubert 	 against all ones in the other, so plain popcount. */
1524b6a78b7SSimon Schubert       if (usize != 0)
1534b6a78b7SSimon Schubert 	{
1544b6a78b7SSimon Schubert 	remaining:
1554b6a78b7SSimon Schubert 	  count += mpn_popcount (up, usize);
1564b6a78b7SSimon Schubert 	}
1574b6a78b7SSimon Schubert       else if (vsize != 0)
1584b6a78b7SSimon Schubert 	{
1594b6a78b7SSimon Schubert 	  up = vp;
1604b6a78b7SSimon Schubert 	  usize = vsize;
1614b6a78b7SSimon Schubert 	  goto remaining;
1624b6a78b7SSimon Schubert 	}
1634b6a78b7SSimon Schubert       return count;
1644b6a78b7SSimon Schubert     }
1654b6a78b7SSimon Schubert }
166