[BACK]Return to divis.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp / mpn / generic

Annotation of OpenXM_contrib/gmp/mpn/generic/divis.c, Revision 1.1

1.1     ! ohara       1: /* mpn_divisible_p -- mpn by mpn divisibility test
        !             2:
        !             3:    THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
        !             4:    CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
        !             5:    FUTURE GNU MP RELEASES.
        !             6:
        !             7: Copyright 2001, 2002 Free Software Foundation, Inc.
        !             8:
        !             9: This file is part of the GNU MP Library.
        !            10:
        !            11: The GNU MP Library is free software; you can redistribute it and/or modify
        !            12: it under the terms of the GNU Lesser General Public License as published by
        !            13: the Free Software Foundation; either version 2.1 of the License, or (at your
        !            14: option) any later version.
        !            15:
        !            16: The GNU MP Library is distributed in the hope that it will be useful, but
        !            17: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            18: or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
        !            19: License for more details.
        !            20:
        !            21: You should have received a copy of the GNU Lesser General Public License
        !            22: along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
        !            23: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
        !            24: MA 02111-1307, USA. */
        !            25:
        !            26: #include "gmp.h"
        !            27: #include "gmp-impl.h"
        !            28: #include "longlong.h"
        !            29:
        !            30:
        !            31: /* Determine whether {ap,asize} is divisible by {dp,dsize}.  Must have both
        !            32:    operands normalized, meaning high limbs non-zero, except that asize==0 is
        !            33:    allowed.
        !            34:
        !            35:    There usually won't be many low zero bits on d, but the checks for this
        !            36:    are fast and might pick up a few operand combinations, in particular they
        !            37:    might reduce d to fit the single-limb mod_1/modexact_1 code.
        !            38:
        !            39:    Future:
        !            40:
        !            41:    This is currently not much faster than the user doing an mpz_tdiv_r
        !            42:    and testing for a zero remainder, but hopefully it can be improved.
        !            43:
        !            44:    mpn_bdivmod is one possibility, but it only trades udiv_qrnnd's for
        !            45:    multiplies, it won't save crossproducts the way it can in mpz_divexact.
        !            46:    Definitely worthwhile on small operands for most processors, but a
        !            47:    sub-quadratic version will be wanted before it can be used on all sizes.
        !            48:
        !            49:    Getting the remainder limb by limb would make an early exit possible on
        !            50:    finding a non-zero.  This would probably have to be bdivmod style so
        !            51:    there's no addback, but it would need a multi-precision inverse and so
        !            52:    might be slower than the plain method (on small sizes at least).
        !            53:
        !            54:    When d must be normalized (shifted to high bit set), it's possible to
        !            55:    just append a low zero limb to "a" rather than bit-shifting as
        !            56:    mpn_tdiv_qr does internally, so long as it's already been checked that a
        !            57:    has at least as many trailing zeros bits as d.  Or equivalently, pass
        !            58:    qxn==1 to mpn_tdiv_qr, if/when it accepts that.
        !            59:
        !            60:    When called from mpz_congruent_p, {ap,asize} is a temporary which can be
        !            61:    destroyed.  Maybe it'd be possible to get into mpn_tdiv_qr at a lower
        !            62:    level to save copying it, or maybe that function could accept rp==ap.
        !            63:
        !            64:    Could use __attribute__ ((regparm (2))) on i386, so the parameters
        !            65:    wouldn't need extra stack when called from mpz_divisible_p, but a
        !            66:    pre-release gcc 3 didn't generate particularly good register juggling in
        !            67:    that case, so this isn't done for now.  */
        !            68:
        !            69: int
        !            70: mpn_divisible_p (mp_srcptr ap, mp_size_t asize,
        !            71:                 mp_srcptr dp, mp_size_t dsize)
        !            72: {
        !            73:   mp_limb_t  alow, dlow, dmask;
        !            74:   mp_ptr     qp, rp;
        !            75:   mp_size_t  i;
        !            76:   TMP_DECL (marker);
        !            77:
        !            78:   ASSERT (asize >= 0);
        !            79:   ASSERT (asize == 0 || ap[asize-1] != 0);
        !            80:   ASSERT (dsize >= 1);
        !            81:   ASSERT (dp[dsize-1] != 0);
        !            82:   ASSERT_MPN (ap, asize);
        !            83:   ASSERT_MPN (dp, dsize);
        !            84:
        !            85:   /* When a<d only a==0 is divisible.
        !            86:      Notice this test covers all cases of asize==0. */
        !            87:   if (asize < dsize)
        !            88:     return (asize == 0);
        !            89:
        !            90:   /* Strip low zero limbs from d, requiring a==0 on those. */
        !            91:   for (;;)
        !            92:     {
        !            93:       alow = *ap;
        !            94:       dlow = *dp;
        !            95:
        !            96:       if (dlow != 0)
        !            97:        break;
        !            98:
        !            99:       if (alow != 0)
        !           100:        return 0;  /* a has fewer low zero limbs than d, so not divisible */
        !           101:
        !           102:       /* a!=0 and d!=0 so won't get to size==0 */
        !           103:       asize--; ASSERT (asize >= 1);
        !           104:       dsize--; ASSERT (dsize >= 1);
        !           105:       ap++;
        !           106:       dp++;
        !           107:     }
        !           108:
        !           109:   /* a must have at least as many low zero bits as d */
        !           110:   dmask = LOW_ZEROS_MASK (dlow);
        !           111:   if ((alow & dmask) != 0)
        !           112:     return 0;
        !           113:
        !           114:   if (dsize == 1)
        !           115:     {
        !           116:       if (BELOW_THRESHOLD (asize, MODEXACT_1_ODD_THRESHOLD))
        !           117:        return mpn_mod_1 (ap, asize, dlow) == 0;
        !           118:
        !           119:       if ((dlow & 1) == 0)
        !           120:        {
        !           121:          unsigned  twos;
        !           122:          count_trailing_zeros (twos, dlow);
        !           123:          dlow >>= twos;
        !           124:        }
        !           125:       return mpn_modexact_1_odd (ap, asize, dlow) == 0;
        !           126:     }
        !           127:
        !           128:   if (dsize == 2)
        !           129:     {
        !           130:       mp_limb_t  dsecond = dp[1];
        !           131:       if (dsecond <= dmask)
        !           132:        {
        !           133:          unsigned  twos;
        !           134:          count_trailing_zeros (twos, dlow);
        !           135:          dlow = (dlow >> twos) | (dsecond << (GMP_NUMB_BITS-twos));
        !           136:           ASSERT_LIMB (dlow);
        !           137:          return MPN_MOD_OR_MODEXACT_1_ODD (ap, asize, dlow) == 0;
        !           138:        }
        !           139:     }
        !           140:
        !           141:   TMP_MARK (marker);
        !           142:
        !           143:   rp = TMP_ALLOC_LIMBS (asize+1);
        !           144:   qp = rp + dsize;
        !           145:
        !           146:   mpn_tdiv_qr (qp, rp, 0, ap, asize, dp, dsize);
        !           147:
        !           148:   /* test for {rp,dsize} zero or non-zero */
        !           149:   i = 0;
        !           150:   do
        !           151:     {
        !           152:       if (rp[i] != 0)
        !           153:        {
        !           154:          TMP_FREE (marker);
        !           155:          return 0;
        !           156:        }
        !           157:     }
        !           158:   while (++i < dsize);
        !           159:
        !           160:   TMP_FREE (marker);
        !           161:   return 1;
        !           162: }

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