(root)/
gmp-6.3.0/
mpz/
and.c
       1  /* mpz_and -- Logical and.
       2  
       3  Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2003, 2005, 2012,
       4  2015-2018 Free 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-impl.h"
      33  
      34  void
      35  mpz_and (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
      36  {
      37    mp_srcptr op1_ptr, op2_ptr;
      38    mp_size_t op1_size, op2_size;
      39    mp_ptr res_ptr;
      40    mp_size_t res_size;
      41    mp_size_t i;
      42  
      43    op1_size = SIZ(op1);
      44    op2_size = SIZ(op2);
      45  
      46    if (op1_size < op2_size)
      47      {
      48        MPZ_SRCPTR_SWAP (op1, op2);
      49        MP_SIZE_T_SWAP (op1_size, op2_size);
      50      }
      51  
      52    op1_ptr = PTR(op1);
      53    op2_ptr = PTR(op2);
      54  
      55    if (op2_size >= 0)
      56      {
      57        /* First loop finds the size of the result.  */
      58        for (i = op2_size; --i >= 0;)
      59  	if ((op1_ptr[i] & op2_ptr[i]) != 0)
      60  	  {
      61  	    res_size = i + 1;
      62  	    /* Handle allocation, now then we know exactly how much space is
      63  	       needed for the result.  */
      64  	    /* Don't re-read op1_ptr and op2_ptr.  Since res_size <=
      65  	       MIN(op1_size, op2_size), res is not changed when op1
      66  	       is identical to res or op2 is identical to res.  */
      67  	    SIZ (res) = res_size;
      68  	    mpn_and_n (MPZ_NEWALLOC (res, res_size), op1_ptr, op2_ptr, res_size);
      69  	    return;
      70  	  }
      71  
      72        SIZ (res) = 0;
      73      }
      74    else
      75      {
      76        TMP_DECL;
      77  
      78        op2_size = -op2_size;
      79        TMP_MARK;
      80        if (op1_size < 0)
      81  	{
      82  	  mp_ptr opx, opy;
      83  
      84  	  /* Both operands are negative, so will be the result.
      85  	     -((-OP1) & (-OP2)) = -(~(OP1 - 1) & ~(OP2 - 1)) =
      86  	     = ~(~(OP1 - 1) & ~(OP2 - 1)) + 1 =
      87  	     = ((OP1 - 1) | (OP2 - 1)) + 1      */
      88  
      89  	  /* It might seem as we could end up with an (invalid) result with
      90  	     a leading zero-limb here when one of the operands is of the
      91  	     type 1,,0,,..,,.0.  But some analysis shows that we surely
      92  	     would get carry into the zero-limb in this situation...  */
      93  
      94  	  op1_size = -op1_size;
      95  
      96  	  TMP_ALLOC_LIMBS_2 (opx, op1_size, opy, op2_size);
      97  	  mpn_sub_1 (opx, op1_ptr, op1_size, (mp_limb_t) 1);
      98  	  op1_ptr = opx;
      99  
     100  	  mpn_sub_1 (opy, op2_ptr, op2_size, (mp_limb_t) 1);
     101  	  op2_ptr = opy;
     102  
     103  	  res_ptr = MPZ_NEWALLOC (res, 1 + op2_size);
     104  	  /* Don't re-read OP1_PTR and OP2_PTR.  They point to temporary
     105  	     space--never to the space PTR(res) used to point to before
     106  	     reallocation.  */
     107  
     108  	  MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
     109  		    op2_size - op1_size);
     110  	  mpn_ior_n (res_ptr, op1_ptr, op2_ptr, op1_size);
     111  	  TMP_FREE;
     112  	  res_size = op2_size;
     113  
     114  	  res_ptr[res_size] = 0;
     115  	  MPN_INCR_U (res_ptr, res_size + 1, (mp_limb_t) 1);
     116  	  res_size += res_ptr[res_size];
     117  
     118  	  SIZ(res) = -res_size;
     119  	}
     120        else
     121  	{
     122  #if ANDNEW
     123  	  mp_size_t op2_lim;
     124  	  mp_size_t count;
     125  
     126  	  /* OP2 must be negated as with infinite precision.
     127  
     128  	     Scan from the low end for a non-zero limb.  The first non-zero
     129  	     limb is simply negated (two's complement).  Any subsequent
     130  	     limbs are one's complemented.  Of course, we don't need to
     131  	     handle more limbs than there are limbs in the other, positive
     132  	     operand as the result for those limbs is going to become zero
     133  	     anyway.  */
     134  
     135  	  /* Scan for the least significant non-zero OP2 limb, and zero the
     136  	     result meanwhile for those limb positions.  (We will surely
     137  	     find a non-zero limb, so we can write the loop with one
     138  	     termination condition only.)  */
     139  	  for (i = 0; op2_ptr[i] == 0; i++)
     140  	    res_ptr[i] = 0;
     141  	  op2_lim = i;
     142  
     143  	  if (op1_size <= op2_size)
     144  	    {
     145  	      /* The ones-extended OP2 is >= than the zero-extended OP1.
     146  		 RES_SIZE <= OP1_SIZE.  Find the exact size.  */
     147  	      for (i = op1_size - 1; i > op2_lim; i--)
     148  		if ((op1_ptr[i] & ~op2_ptr[i]) != 0)
     149  		  break;
     150  	      res_size = i + 1;
     151  	      for (i = res_size - 1; i > op2_lim; i--)
     152  		res_ptr[i] = op1_ptr[i] & ~op2_ptr[i];
     153  	      res_ptr[op2_lim] = op1_ptr[op2_lim] & -op2_ptr[op2_lim];
     154  	      /* Yes, this *can* happen!  */
     155  	      MPN_NORMALIZE (res_ptr, res_size);
     156  	    }
     157  	  else
     158  	    {
     159  	      /* The ones-extended OP2 is < than the zero-extended OP1.
     160  		 RES_SIZE == OP1_SIZE, since OP1 is normalized.  */
     161  	      res_size = op1_size;
     162  	      MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, op1_size - op2_size);
     163  	      for (i = op2_size - 1; i > op2_lim; i--)
     164  		res_ptr[i] = op1_ptr[i] & ~op2_ptr[i];
     165  	      res_ptr[op2_lim] = op1_ptr[op2_lim] & -op2_ptr[op2_lim];
     166  	    }
     167  #else
     168  
     169  	  /* OP1 is positive and zero-extended,
     170  	     OP2 is negative and ones-extended.
     171  	     The result will be positive.
     172  	     OP1 & -OP2 = OP1 & ~(OP2 - 1).  */
     173  
     174  	  mp_ptr opx;
     175  
     176  	  opx = TMP_ALLOC_LIMBS (op2_size);
     177  	  mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1);
     178  	  op2_ptr = opx;
     179  
     180  	  if (op1_size > op2_size)
     181  	    {
     182  	      /* The result has the same size as OP1, since OP1 is normalized
     183  		 and longer than the ones-extended OP2.  */
     184  	      res_size = op1_size;
     185  
     186  	      /* Handle allocation, now then we know exactly how much space is
     187  		 needed for the result.  */
     188  	      res_ptr = MPZ_NEWALLOC (res, res_size);
     189  	      /* Don't re-read OP1_PTR or OP2_PTR.  Since res_size = op1_size,
     190  		 op1 is not changed if it is identical to res.
     191  		 OP2_PTR points to temporary space.  */
     192  
     193  	      mpn_andn_n (res_ptr, op1_ptr, op2_ptr, op2_size);
     194  	      MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, res_size - op2_size);
     195  	    }
     196  	  else
     197  	    {
     198  	      /* Find out the exact result size.  Ignore the high limbs of OP2,
     199  		 OP1 is zero-extended and would make the result zero.  */
     200  	      res_size = 0;
     201  	      for (i = op1_size; --i >= 0;)
     202  		if ((op1_ptr[i] & ~op2_ptr[i]) != 0)
     203  		  {
     204  		    res_size = i + 1;
     205  		    /* Handle allocation, now then we know exactly how much
     206  		       space is needed for the result.  */
     207  		    /* Don't re-read OP1_PTR.  Since res_size <= op1_size,
     208  		       op1 is not changed if it is identical to res.  Don't
     209  		       re-read OP2_PTR.  It points to temporary space--never
     210  		       to the space PTR(res) used to point to before
     211  		       reallocation.  */
     212  		    mpn_andn_n (MPZ_NEWALLOC (res, res_size), op1_ptr, op2_ptr, res_size);
     213  
     214  		    break;
     215  		  }
     216  	    }
     217  #endif
     218  	  SIZ(res) = res_size;
     219  	  TMP_FREE;
     220  	}
     221      }
     222  }