[BACK]Return to and.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp / mpz

Annotation of OpenXM_contrib/gmp/mpz/and.c, Revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>