[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

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>