github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/mpz/hamdist.c (about)

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