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>