Annotation of OpenXM_contrib/gmp/mpz/aorsmul_i.c, Revision 1.1.1.1
1.1 ohara 1: /* mpz_addmul_ui, mpz_submul_ui - add or subtract small multiple.
2:
3: THE mpz_aorsmul_1 FUNCTION IN THIS FILE IS FOR INTERNAL USE ONLY AND IS
4: ALMOST CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR
5: COMPLETELY IN 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:
29:
30: #if HAVE_NATIVE_mpn_mul_1c
31: #define MPN_MUL_1C(cout, dst, src, size, n, cin) \
32: do { \
33: (cout) = mpn_mul_1c (dst, src, size, n, cin); \
34: } while (0)
35: #else
36: #define MPN_MUL_1C(cout, dst, src, size, n, cin) \
37: do { \
38: mp_limb_t __cy; \
39: __cy = mpn_mul_1 (dst, src, size, n); \
40: (cout) = __cy + mpn_add_1 (dst, dst, size, cin); \
41: } while (0)
42: #endif
43:
44:
45: /* sub>=0 means an addmul w += x*y, sub<0 means a submul w -= x*y.
46:
47: All that's needed to account for negative w or x is to flip "sub".
48:
49: The final w will retain its sign, unless an underflow occurs in a submul
50: of absolute values, in which case it's flipped.
51:
52: If x has more limbs than w, then mpn_submul_1 followed by mpn_com_n is
53: used. The alternative would be mpn_mul_1 into temporary space followed
54: by mpn_sub_n. Avoiding temporary space seem good, and submul+com stands
55: a chance of being faster since it involves only one set of carry
56: propagations, not two. Note that doing an addmul_1 with a
57: twos-complement negative y doesn't work, because it effectively adds an
58: extra x * 2^BITS_PER_MP_LIMB. */
59:
60: void
61: mpz_aorsmul_1 (mpz_ptr w, mpz_srcptr x, mp_limb_t y, mp_size_t sub)
62: {
63: mp_size_t xsize, wsize, wsize_signed, new_wsize, min_size, dsize;
64: mp_srcptr xp;
65: mp_ptr wp;
66: mp_limb_t cy;
67:
68: /* w unaffected if x==0 or y==0 */
69: xsize = SIZ (x);
70: if (xsize == 0 || y == 0)
71: return;
72:
73: sub ^= xsize;
74: xsize = ABS (xsize);
75:
76: wsize_signed = SIZ (w);
77: if (wsize_signed == 0)
78: {
79: /* nothing to add to, just set x*y, "sub" gives the sign */
80: MPZ_REALLOC (w, xsize+1);
81: wp = PTR (w);
82: cy = mpn_mul_1 (wp, PTR(x), xsize, y);
83: wp[xsize] = cy;
84: xsize += (cy != 0);
85: SIZ (w) = (sub >= 0 ? xsize : -xsize);
86: return;
87: }
88:
89: sub ^= wsize_signed;
90: wsize = ABS (wsize_signed);
91:
92: new_wsize = MAX (wsize, xsize);
93: MPZ_REALLOC (w, new_wsize+1);
94: wp = PTR (w);
95: xp = PTR (x);
96: min_size = MIN (wsize, xsize);
97:
98: if (sub >= 0)
99: {
100: /* addmul of absolute values */
101:
102: cy = mpn_addmul_1 (wp, xp, min_size, y);
103: wp += min_size;
104: xp += min_size;
105:
106: dsize = xsize - wsize;
107: #if HAVE_NATIVE_mpn_mul_1c
108: if (dsize > 0)
109: cy = mpn_mul_1c (wp, xp, dsize, y, cy);
110: else if (dsize < 0)
111: {
112: dsize = -dsize;
113: cy = mpn_add_1 (wp, wp, dsize, cy);
114: }
115: #else
116: if (dsize != 0)
117: {
118: mp_limb_t cy2;
119: if (dsize > 0)
120: cy2 = mpn_mul_1 (wp, xp, dsize, y);
121: else
122: {
123: dsize = -dsize;
124: cy2 = 0;
125: }
126: cy = cy2 + mpn_add_1 (wp, wp, dsize, cy);
127: }
128: #endif
129:
130: wp[dsize] = cy;
131: new_wsize += (cy != 0);
132: }
133: else
134: {
135: /* submul of absolute values */
136:
137: cy = mpn_submul_1 (wp, xp, min_size, y);
138: if (wsize >= xsize)
139: {
140: /* if w bigger than x, then propagate borrow through it */
141: if (wsize != xsize)
142: cy = mpn_sub_1 (wp+xsize, wp+xsize, wsize-xsize, cy);
143:
144: if (cy != 0)
145: {
146: /* Borrow out of w, take twos complement negative to get
147: absolute value, flip sign of w. */
148: wp[new_wsize] = ~-cy; /* extra limb is 0-cy */
149: mpn_com_n (wp, wp, new_wsize);
150: new_wsize++;
151: MPN_INCR_U (wp, new_wsize, CNST_LIMB(1));
152: wsize_signed = -wsize_signed;
153: }
154: }
155: else /* wsize < xsize */
156: {
157: /* x bigger than w, so want x*y-w. Submul has given w-x*y, so
158: take twos complement and use an mpn_mul_1 for the rest. */
159:
160: mp_limb_t cy2;
161:
162: /* -(-cy*b^n + w-x*y) = (cy-1)*b^n + ~(w-x*y) + 1 */
163: mpn_com_n (wp, wp, wsize);
164: cy += mpn_add_1 (wp, wp, wsize, CNST_LIMB(1));
165: cy -= 1;
166:
167: /* If cy-1 == -1 then hold that -1 for latter. mpn_submul_1 never
168: returns cy==MP_LIMB_T_MAX so that value always indicates a -1. */
169: cy2 = (cy == MP_LIMB_T_MAX);
170: cy += cy2;
171: MPN_MUL_1C (cy, wp+wsize, xp+wsize, xsize-wsize, y, cy);
172: wp[new_wsize] = cy;
173: new_wsize += (cy != 0);
174:
175: /* Apply any -1 from above. The value at wp+wsize is non-zero
176: because y!=0 and the high limb of x will be non-zero. */
177: if (cy2)
178: MPN_DECR_U (wp+wsize, new_wsize-wsize, CNST_LIMB(1));
179:
180: wsize_signed = -wsize_signed;
181: }
182:
183: /* submul can produce high zero limbs due to cancellation, both when w
184: has more limbs or x has more */
185: MPN_NORMALIZE (wp, new_wsize);
186: }
187:
188: SIZ (w) = (wsize_signed >= 0 ? new_wsize : -new_wsize);
189:
190: ASSERT (new_wsize == 0 || PTR(w)[new_wsize-1] != 0);
191: }
192:
193:
194: void
195: mpz_addmul_ui (mpz_ptr w, mpz_srcptr x, unsigned long y)
196: {
197: mpz_aorsmul_1 (w, x, (mp_limb_t) y & GMP_NUMB_MASK, (mp_size_t) 0);
198: #if GMP_NAIL_BITS != 0
199: if (y > GMP_NUMB_MAX && SIZ(x) != 0)
200: {
201: mpz_t t;
202: mp_ptr tp;
203: mp_size_t xn;
204: TMP_DECL (mark);
205: TMP_MARK (mark);
206: xn = SIZ (x);
207: MPZ_TMP_INIT (t, ABS (xn) + 1);
208: tp = PTR (t);
209: tp[0] = 0;
210: MPN_COPY (tp + 1, PTR(x), ABS (xn));
211: SIZ(t) = xn >= 0 ? xn + 1 : xn - 1;
212: mpz_aorsmul_1 (w, t, (mp_limb_t) y >> GMP_NUMB_BITS, (mp_size_t) 0);
213: TMP_FREE (mark);
214: }
215: #endif
216: }
217:
218: void
219: mpz_submul_ui (mpz_ptr w, mpz_srcptr x, unsigned long y)
220: {
221: mpz_aorsmul_1 (w, x, (mp_limb_t) y & GMP_NUMB_MASK, (mp_size_t) -1);
222: #if GMP_NAIL_BITS != 0
223: if (y > GMP_NUMB_MAX && SIZ(x) != 0)
224: {
225: mpz_t t;
226: mp_ptr tp;
227: mp_size_t xn;
228: TMP_DECL (mark);
229: TMP_MARK (mark);
230: xn = SIZ (x);
231: MPZ_TMP_INIT (t, ABS (xn) + 1);
232: tp = PTR (t);
233: tp[0] = 0;
234: MPN_COPY (tp + 1, PTR(x), ABS (xn));
235: SIZ(t) = xn >= 0 ? xn + 1 : xn - 1;
236: mpz_aorsmul_1 (w, t, (mp_limb_t) y >> GMP_NUMB_BITS, (mp_size_t) -1);
237: TMP_FREE (mark);
238: }
239: #endif
240: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>