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

     1  /* mpz_and -- Logical and.
     2  
     3  Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2003, 2005, 2012 Free
     4  Software Foundation, Inc.
     5  
     6  This file is part of the GNU MP Library.
     7  
     8  The GNU MP Library is free software; you can redistribute it and/or modify
     9  it under the terms of either:
    10  
    11    * the GNU Lesser General Public License as published by the Free
    12      Software Foundation; either version 3 of the License, or (at your
    13      option) any later version.
    14  
    15  or
    16  
    17    * the GNU General Public License as published by the Free Software
    18      Foundation; either version 2 of the License, or (at your option) any
    19      later version.
    20  
    21  or both in parallel, as here.
    22  
    23  The GNU MP Library is distributed in the hope that it will be useful, but
    24  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    25  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    26  for more details.
    27  
    28  You should have received copies of the GNU General Public License and the
    29  GNU Lesser General Public License along with the GNU MP Library.  If not,
    30  see https://www.gnu.org/licenses/.  */
    31  
    32  #include "gmp.h"
    33  #include "gmp-impl.h"
    34  
    35  void
    36  mpz_and (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
    37  {
    38    mp_srcptr op1_ptr, op2_ptr;
    39    mp_size_t op1_size, op2_size;
    40    mp_ptr res_ptr;
    41    mp_size_t res_size;
    42    mp_size_t i;
    43    TMP_DECL;
    44  
    45    TMP_MARK;
    46    op1_size = SIZ(op1);
    47    op2_size = SIZ(op2);
    48  
    49    op1_ptr = PTR(op1);
    50    op2_ptr = PTR(op2);
    51  
    52    if (op1_size >= 0)
    53      {
    54        if (op2_size >= 0)
    55  	{
    56  	  res_size = MIN (op1_size, op2_size);
    57  	  /* First loop finds the size of the result.  */
    58  	  for (i = res_size - 1; i >= 0; i--)
    59  	    if ((op1_ptr[i] & op2_ptr[i]) != 0)
    60  	      break;
    61  	  res_size = i + 1;
    62  
    63  	  /* Handle allocation, now then we know exactly how much space is
    64  	     needed for the result.  */
    65  	  res_ptr = MPZ_REALLOC (res, res_size);
    66  	  /* Don't re-read op1_ptr and op2_ptr.  Since res_size <=
    67  	     MIN(op1_size, op2_size), res is not changed when op1
    68  	     is identical to res or op2 is identical to res.  */
    69  
    70  	  SIZ(res) = res_size;
    71  	  if (LIKELY (res_size != 0))
    72  	    mpn_and_n (res_ptr, op1_ptr, op2_ptr, res_size);
    73  	  return;
    74  	}
    75        else /* op2_size < 0 */
    76  	{
    77  	  /* Fall through to the code at the end of the function.  */
    78  	}
    79      }
    80    else
    81      {
    82        if (op2_size < 0)
    83  	{
    84  	  mp_ptr opx, opy;
    85  	  mp_limb_t cy;
    86  
    87  	  /* Both operands are negative, so will be the result.
    88  	     -((-OP1) & (-OP2)) = -(~(OP1 - 1) & ~(OP2 - 1)) =
    89  	     = ~(~(OP1 - 1) & ~(OP2 - 1)) + 1 =
    90  	     = ((OP1 - 1) | (OP2 - 1)) + 1      */
    91  
    92  	  /* It might seem as we could end up with an (invalid) result with
    93  	     a leading zero-limb here when one of the operands is of the
    94  	     type 1,,0,,..,,.0.  But some analysis shows that we surely
    95  	     would get carry into the zero-limb in this situation...  */
    96  
    97  	  op1_size = -op1_size;
    98  	  op2_size = -op2_size;
    99  
   100  	  if (op1_size > op2_size)
   101  	    MPN_SRCPTR_SWAP (op1_ptr, op1_size, op2_ptr, op2_size);
   102  
   103  	  TMP_ALLOC_LIMBS_2 (opx, op1_size, opy, op2_size);
   104  	  mpn_sub_1 (opx, op1_ptr, op1_size, (mp_limb_t) 1);
   105  	  op1_ptr = opx;
   106  
   107  	  mpn_sub_1 (opy, op2_ptr, op2_size, (mp_limb_t) 1);
   108  	  op2_ptr = opy;
   109  
   110  	  res_ptr = MPZ_REALLOC (res, 1 + op2_size);
   111  	  /* Don't re-read OP1_PTR and OP2_PTR.  They point to temporary
   112  	     space--never to the space PTR(res) used to point to before
   113  	     reallocation.  */
   114  
   115  	  MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
   116  		    op2_size - op1_size);
   117  	  mpn_ior_n (res_ptr, op1_ptr, op2_ptr, op1_size);
   118  	  res_size = op2_size;
   119  
   120  	  cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1);
   121  	  res_ptr[res_size] = cy;
   122  	  res_size += (cy != 0);
   123  
   124  	  SIZ(res) = -res_size;
   125  	  TMP_FREE;
   126  	  return;
   127  	}
   128        else
   129  	{
   130  	  /* We should compute -OP1 & OP2.  Swap OP1 and OP2 and fall
   131  	     through to the code that handles OP1 & -OP2.  */
   132  	  MPN_SRCPTR_SWAP (op1_ptr, op1_size, op2_ptr, op2_size);
   133  	}
   134  
   135      }
   136  
   137    {
   138  #if ANDNEW
   139      mp_size_t op2_lim;
   140      mp_size_t count;
   141  
   142      /* OP2 must be negated as with infinite precision.
   143  
   144         Scan from the low end for a non-zero limb.  The first non-zero
   145         limb is simply negated (two's complement).  Any subsequent
   146         limbs are one's complemented.  Of course, we don't need to
   147         handle more limbs than there are limbs in the other, positive
   148         operand as the result for those limbs is going to become zero
   149         anyway.  */
   150  
   151      /* Scan for the least significant non-zero OP2 limb, and zero the
   152         result meanwhile for those limb positions.  (We will surely
   153         find a non-zero limb, so we can write the loop with one
   154         termination condition only.)  */
   155      for (i = 0; op2_ptr[i] == 0; i++)
   156        res_ptr[i] = 0;
   157      op2_lim = i;
   158  
   159      op2_size = -op2_size;
   160  
   161      if (op1_size <= op2_size)
   162        {
   163  	/* The ones-extended OP2 is >= than the zero-extended OP1.
   164  	   RES_SIZE <= OP1_SIZE.  Find the exact size.  */
   165  	for (i = op1_size - 1; i > op2_lim; i--)
   166  	  if ((op1_ptr[i] & ~op2_ptr[i]) != 0)
   167  	    break;
   168  	res_size = i + 1;
   169  	for (i = res_size - 1; i > op2_lim; i--)
   170  	  res_ptr[i] = op1_ptr[i] & ~op2_ptr[i];
   171  	res_ptr[op2_lim] = op1_ptr[op2_lim] & -op2_ptr[op2_lim];
   172  	/* Yes, this *can* happen!  */
   173  	MPN_NORMALIZE (res_ptr, res_size);
   174        }
   175      else
   176        {
   177  	/* The ones-extended OP2 is < than the zero-extended OP1.
   178  	   RES_SIZE == OP1_SIZE, since OP1 is normalized.  */
   179  	res_size = op1_size;
   180  	MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, op1_size - op2_size);
   181  	for (i = op2_size - 1; i > op2_lim; i--)
   182  	  res_ptr[i] = op1_ptr[i] & ~op2_ptr[i];
   183  	res_ptr[op2_lim] = op1_ptr[op2_lim] & -op2_ptr[op2_lim];
   184        }
   185  
   186      SIZ(res) = res_size;
   187  #else
   188  
   189      /* OP1 is positive and zero-extended,
   190         OP2 is negative and ones-extended.
   191         The result will be positive.
   192         OP1 & -OP2 = OP1 & ~(OP2 - 1).  */
   193  
   194      mp_ptr opx;
   195  
   196      op2_size = -op2_size;
   197      opx = TMP_ALLOC_LIMBS (op2_size);
   198      mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1);
   199      op2_ptr = opx;
   200  
   201      if (op1_size > op2_size)
   202        {
   203  	/* The result has the same size as OP1, since OP1 is normalized
   204  	   and longer than the ones-extended OP2.  */
   205  	res_size = op1_size;
   206  
   207  	/* Handle allocation, now then we know exactly how much space is
   208  	   needed for the result.  */
   209  	res_ptr = MPZ_REALLOC (res, res_size);
   210  	/* Don't re-read OP1_PTR or OP2_PTR.  Since res_size = op1_size,
   211  	   op1 is not changed if it is identical to res.
   212  	   OP2_PTR points to temporary space.  */
   213  
   214  	MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, res_size - op2_size);
   215  	mpn_andn_n (res_ptr, op1_ptr, op2_ptr, op2_size);
   216  
   217  	SIZ(res) = res_size;
   218        }
   219      else
   220        {
   221  	/* Find out the exact result size.  Ignore the high limbs of OP2,
   222  	   OP1 is zero-extended and would make the result zero.  */
   223  	for (i = op1_size - 1; i >= 0; i--)
   224  	  if ((op1_ptr[i] & ~op2_ptr[i]) != 0)
   225  	    break;
   226  	res_size = i + 1;
   227  
   228  	/* Handle allocation, now then we know exactly how much space is
   229  	   needed for the result.  */
   230  	res_ptr = MPZ_REALLOC (res, res_size);
   231  	/* Don't re-read OP1_PTR.  Since res_size <= op1_size,
   232  	   op1 is not changed if it is identical to res.
   233  	   Don't re-read OP2_PTR.  It points to temporary space--never
   234  	   to the space PTR(res) used to point to before reallocation.  */
   235  
   236  	if (LIKELY (res_size != 0))
   237  	  mpn_andn_n (res_ptr, op1_ptr, op2_ptr, res_size);
   238  
   239  	SIZ(res) = res_size;
   240        }
   241  #endif
   242    }
   243    TMP_FREE;
   244  }