iwmfw - Add version 22 firmwares for AC3168 and AC8265 chipsets.
[dragonfly.git] / contrib / gmp / mpz / aorsmul_i.c
blobb3c2efae46dd117c0ce7557be612e30228a58194
1 /* mpz_addmul_ui, mpz_submul_ui - add or subtract small multiple.
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.
7 Copyright 2001, 2002, 2004, 2005 Free Software Foundation, Inc.
9 This file is part of the GNU MP Library.
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 3 of the License, or (at your
14 option) any later version.
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.
21 You should have received a copy of the GNU Lesser General Public License
22 along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
24 #include "gmp.h"
25 #include "gmp-impl.h"
28 #if HAVE_NATIVE_mpn_mul_1c
29 #define MPN_MUL_1C(cout, dst, src, size, n, cin) \
30 do { \
31 (cout) = mpn_mul_1c (dst, src, size, n, cin); \
32 } while (0)
33 #else
34 #define MPN_MUL_1C(cout, dst, src, size, n, cin) \
35 do { \
36 mp_limb_t __cy; \
37 __cy = mpn_mul_1 (dst, src, size, n); \
38 (cout) = __cy + mpn_add_1 (dst, dst, size, cin); \
39 } while (0)
40 #endif
43 /* sub>=0 means an addmul w += x*y, sub<0 means a submul w -= x*y.
45 All that's needed to account for negative w or x is to flip "sub".
47 The final w will retain its sign, unless an underflow occurs in a submul
48 of absolute values, in which case it's flipped.
50 If x has more limbs than w, then mpn_submul_1 followed by mpn_com is
51 used. The alternative would be mpn_mul_1 into temporary space followed
52 by mpn_sub_n. Avoiding temporary space seem good, and submul+com stands
53 a chance of being faster since it involves only one set of carry
54 propagations, not two. Note that doing an addmul_1 with a
55 twos-complement negative y doesn't work, because it effectively adds an
56 extra x * 2^GMP_LIMB_BITS. */
58 REGPARM_ATTR(1) void
59 mpz_aorsmul_1 (mpz_ptr w, mpz_srcptr x, mp_limb_t y, mp_size_t sub)
61 mp_size_t xsize, wsize, wsize_signed, new_wsize, min_size, dsize;
62 mp_srcptr xp;
63 mp_ptr wp;
64 mp_limb_t cy;
66 /* w unaffected if x==0 or y==0 */
67 xsize = SIZ (x);
68 if (xsize == 0 || y == 0)
69 return;
71 sub ^= xsize;
72 xsize = ABS (xsize);
74 wsize_signed = SIZ (w);
75 if (wsize_signed == 0)
77 /* nothing to add to, just set x*y, "sub" gives the sign */
78 MPZ_REALLOC (w, xsize+1);
79 wp = PTR (w);
80 cy = mpn_mul_1 (wp, PTR(x), xsize, y);
81 wp[xsize] = cy;
82 xsize += (cy != 0);
83 SIZ (w) = (sub >= 0 ? xsize : -xsize);
84 return;
87 sub ^= wsize_signed;
88 wsize = ABS (wsize_signed);
90 new_wsize = MAX (wsize, xsize);
91 MPZ_REALLOC (w, new_wsize+1);
92 wp = PTR (w);
93 xp = PTR (x);
94 min_size = MIN (wsize, xsize);
96 if (sub >= 0)
98 /* addmul of absolute values */
100 cy = mpn_addmul_1 (wp, xp, min_size, y);
101 wp += min_size;
102 xp += min_size;
104 dsize = xsize - wsize;
105 #if HAVE_NATIVE_mpn_mul_1c
106 if (dsize > 0)
107 cy = mpn_mul_1c (wp, xp, dsize, y, cy);
108 else if (dsize < 0)
110 dsize = -dsize;
111 cy = mpn_add_1 (wp, wp, dsize, cy);
113 #else
114 if (dsize != 0)
116 mp_limb_t cy2;
117 if (dsize > 0)
118 cy2 = mpn_mul_1 (wp, xp, dsize, y);
119 else
121 dsize = -dsize;
122 cy2 = 0;
124 cy = cy2 + mpn_add_1 (wp, wp, dsize, cy);
126 #endif
128 wp[dsize] = cy;
129 new_wsize += (cy != 0);
131 else
133 /* submul of absolute values */
135 cy = mpn_submul_1 (wp, xp, min_size, y);
136 if (wsize >= xsize)
138 /* if w bigger than x, then propagate borrow through it */
139 if (wsize != xsize)
140 cy = mpn_sub_1 (wp+xsize, wp+xsize, wsize-xsize, cy);
142 if (cy != 0)
144 /* Borrow out of w, take twos complement negative to get
145 absolute value, flip sign of w. */
146 wp[new_wsize] = ~-cy; /* extra limb is 0-cy */
147 mpn_com (wp, wp, new_wsize);
148 new_wsize++;
149 MPN_INCR_U (wp, new_wsize, CNST_LIMB(1));
150 wsize_signed = -wsize_signed;
153 else /* wsize < xsize */
155 /* x bigger than w, so want x*y-w. Submul has given w-x*y, so
156 take twos complement and use an mpn_mul_1 for the rest. */
158 mp_limb_t cy2;
160 /* -(-cy*b^n + w-x*y) = (cy-1)*b^n + ~(w-x*y) + 1 */
161 mpn_com (wp, wp, wsize);
162 cy += mpn_add_1 (wp, wp, wsize, CNST_LIMB(1));
163 cy -= 1;
165 /* If cy-1 == -1 then hold that -1 for latter. mpn_submul_1 never
166 returns cy==MP_LIMB_T_MAX so that value always indicates a -1. */
167 cy2 = (cy == MP_LIMB_T_MAX);
168 cy += cy2;
169 MPN_MUL_1C (cy, wp+wsize, xp+wsize, xsize-wsize, y, cy);
170 wp[new_wsize] = cy;
171 new_wsize += (cy != 0);
173 /* Apply any -1 from above. The value at wp+wsize is non-zero
174 because y!=0 and the high limb of x will be non-zero. */
175 if (cy2)
176 MPN_DECR_U (wp+wsize, new_wsize-wsize, CNST_LIMB(1));
178 wsize_signed = -wsize_signed;
181 /* submul can produce high zero limbs due to cancellation, both when w
182 has more limbs or x has more */
183 MPN_NORMALIZE (wp, new_wsize);
186 SIZ (w) = (wsize_signed >= 0 ? new_wsize : -new_wsize);
188 ASSERT (new_wsize == 0 || PTR(w)[new_wsize-1] != 0);
192 void
193 mpz_addmul_ui (mpz_ptr w, mpz_srcptr x, unsigned long y)
195 #if BITS_PER_ULONG > GMP_NUMB_BITS
196 if (UNLIKELY (y > GMP_NUMB_MAX && SIZ(x) != 0))
198 mpz_t t;
199 mp_ptr tp;
200 mp_size_t xn;
201 TMP_DECL;
202 TMP_MARK;
203 xn = SIZ (x);
204 MPZ_TMP_INIT (t, ABS (xn) + 1);
205 tp = PTR (t);
206 tp[0] = 0;
207 MPN_COPY (tp + 1, PTR(x), ABS (xn));
208 SIZ(t) = xn >= 0 ? xn + 1 : xn - 1;
209 mpz_aorsmul_1 (w, t, (mp_limb_t) y >> GMP_NUMB_BITS, (mp_size_t) 0);
210 PTR(t) = tp + 1;
211 SIZ(t) = xn;
212 mpz_aorsmul_1 (w, t, (mp_limb_t) y & GMP_NUMB_MASK, (mp_size_t) 0);
213 TMP_FREE;
214 return;
216 #endif
217 mpz_aorsmul_1 (w, x, (mp_limb_t) y, (mp_size_t) 0);
220 void
221 mpz_submul_ui (mpz_ptr w, mpz_srcptr x, unsigned long y)
223 #if BITS_PER_ULONG > GMP_NUMB_BITS
224 if (y > GMP_NUMB_MAX && SIZ(x) != 0)
226 mpz_t t;
227 mp_ptr tp;
228 mp_size_t xn;
229 TMP_DECL;
230 TMP_MARK;
231 xn = SIZ (x);
232 MPZ_TMP_INIT (t, ABS (xn) + 1);
233 tp = PTR (t);
234 tp[0] = 0;
235 MPN_COPY (tp + 1, PTR(x), ABS (xn));
236 SIZ(t) = xn >= 0 ? xn + 1 : xn - 1;
237 mpz_aorsmul_1 (w, t, (mp_limb_t) y >> GMP_NUMB_BITS, (mp_size_t) -1);
238 PTR(t) = tp + 1;
239 SIZ(t) = xn;
240 mpz_aorsmul_1 (w, t, (mp_limb_t) y & GMP_NUMB_MASK, (mp_size_t) -1);
241 TMP_FREE;
242 return;
244 #endif
245 mpz_aorsmul_1 (w, x, (mp_limb_t) y & GMP_NUMB_MASK, (mp_size_t) -1);