/src/gmp-6.2.1/mpz/aorsmul_i.c
Line | Count | Source (jump to first uncovered line) |
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, 2004, 2005, 2012 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 either: |
13 | | |
14 | | * the GNU Lesser General Public License as published by the Free |
15 | | Software Foundation; either version 3 of the License, or (at your |
16 | | option) any later version. |
17 | | |
18 | | or |
19 | | |
20 | | * the GNU General Public License as published by the Free Software |
21 | | Foundation; either version 2 of the License, or (at your option) any |
22 | | later version. |
23 | | |
24 | | or both in parallel, as here. |
25 | | |
26 | | The GNU MP Library is distributed in the hope that it will be useful, but |
27 | | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
28 | | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
29 | | for more details. |
30 | | |
31 | | You should have received copies of the GNU General Public License and the |
32 | | GNU Lesser General Public License along with the GNU MP Library. If not, |
33 | | see https://www.gnu.org/licenses/. */ |
34 | | |
35 | | #include "gmp-impl.h" |
36 | | |
37 | | |
38 | | #if HAVE_NATIVE_mpn_mul_1c |
39 | | #define MPN_MUL_1C(cout, dst, src, size, n, cin) \ |
40 | 0 | do { \ |
41 | 0 | (cout) = mpn_mul_1c (dst, src, size, n, cin); \ |
42 | 0 | } while (0) |
43 | | #else |
44 | | #define MPN_MUL_1C(cout, dst, src, size, n, cin) \ |
45 | | do { \ |
46 | | mp_limb_t __cy; \ |
47 | | __cy = mpn_mul_1 (dst, src, size, n); \ |
48 | | (cout) = __cy + mpn_add_1 (dst, dst, size, cin); \ |
49 | | } while (0) |
50 | | #endif |
51 | | |
52 | | |
53 | | /* sub>=0 means an addmul w += x*y, sub<0 means a submul w -= x*y. |
54 | | |
55 | | All that's needed to account for negative w or x is to flip "sub". |
56 | | |
57 | | The final w will retain its sign, unless an underflow occurs in a submul |
58 | | of absolute values, in which case it's flipped. |
59 | | |
60 | | If x has more limbs than w, then mpn_submul_1 followed by mpn_com is |
61 | | used. The alternative would be mpn_mul_1 into temporary space followed |
62 | | by mpn_sub_n. Avoiding temporary space seem good, and submul+com stands |
63 | | a chance of being faster since it involves only one set of carry |
64 | | propagations, not two. Note that doing an addmul_1 with a |
65 | | twos-complement negative y doesn't work, because it effectively adds an |
66 | | extra x * 2^GMP_LIMB_BITS. */ |
67 | | |
68 | | REGPARM_ATTR(1) void |
69 | | mpz_aorsmul_1 (mpz_ptr w, mpz_srcptr x, mp_limb_t y, mp_size_t sub) |
70 | 94 | { |
71 | 94 | mp_size_t xsize, wsize, wsize_signed, new_wsize, min_size, dsize; |
72 | 94 | mp_srcptr xp; |
73 | 94 | mp_ptr wp; |
74 | 94 | mp_limb_t cy; |
75 | | |
76 | | /* w unaffected if x==0 or y==0 */ |
77 | 94 | xsize = SIZ (x); |
78 | 94 | if (xsize == 0 || y == 0) |
79 | 0 | return; |
80 | | |
81 | 94 | sub ^= xsize; |
82 | 94 | xsize = ABS (xsize); |
83 | | |
84 | 94 | wsize_signed = SIZ (w); |
85 | 94 | if (wsize_signed == 0) |
86 | 0 | { |
87 | | /* nothing to add to, just set x*y, "sub" gives the sign */ |
88 | 0 | wp = MPZ_REALLOC (w, xsize+1); |
89 | 0 | cy = mpn_mul_1 (wp, PTR(x), xsize, y); |
90 | 0 | wp[xsize] = cy; |
91 | 0 | xsize += (cy != 0); |
92 | 0 | SIZ (w) = (sub >= 0 ? xsize : -xsize); |
93 | 0 | return; |
94 | 0 | } |
95 | | |
96 | 94 | sub ^= wsize_signed; |
97 | 94 | wsize = ABS (wsize_signed); |
98 | | |
99 | 94 | new_wsize = MAX (wsize, xsize); |
100 | 94 | wp = MPZ_REALLOC (w, new_wsize+1); |
101 | 94 | xp = PTR (x); |
102 | 94 | min_size = MIN (wsize, xsize); |
103 | | |
104 | 94 | if (sub >= 0) |
105 | 94 | { |
106 | | /* addmul of absolute values */ |
107 | | |
108 | 94 | cy = mpn_addmul_1 (wp, xp, min_size, y); |
109 | 94 | wp += min_size; |
110 | 94 | xp += min_size; |
111 | | |
112 | 94 | dsize = xsize - wsize; |
113 | 94 | #if HAVE_NATIVE_mpn_mul_1c |
114 | 94 | if (dsize > 0) |
115 | 0 | cy = mpn_mul_1c (wp, xp, dsize, y, cy); |
116 | 94 | else if (dsize < 0) |
117 | 54 | { |
118 | 54 | dsize = -dsize; |
119 | 54 | cy = mpn_add_1 (wp, wp, dsize, cy); |
120 | 54 | } |
121 | | #else |
122 | | if (dsize != 0) |
123 | | { |
124 | | mp_limb_t cy2; |
125 | | if (dsize > 0) |
126 | | cy2 = mpn_mul_1 (wp, xp, dsize, y); |
127 | | else |
128 | | { |
129 | | dsize = -dsize; |
130 | | cy2 = 0; |
131 | | } |
132 | | cy = cy2 + mpn_add_1 (wp, wp, dsize, cy); |
133 | | } |
134 | | #endif |
135 | | |
136 | 94 | wp[dsize] = cy; |
137 | 94 | new_wsize += (cy != 0); |
138 | 94 | } |
139 | 0 | else |
140 | 0 | { |
141 | | /* submul of absolute values */ |
142 | |
|
143 | 0 | cy = mpn_submul_1 (wp, xp, min_size, y); |
144 | 0 | if (wsize >= xsize) |
145 | 0 | { |
146 | | /* if w bigger than x, then propagate borrow through it */ |
147 | 0 | if (wsize != xsize) |
148 | 0 | cy = mpn_sub_1 (wp+xsize, wp+xsize, wsize-xsize, cy); |
149 | |
|
150 | 0 | if (cy != 0) |
151 | 0 | { |
152 | | /* Borrow out of w, take twos complement negative to get |
153 | | absolute value, flip sign of w. */ |
154 | 0 | wp[new_wsize] = ~-cy; /* extra limb is 0-cy */ |
155 | 0 | mpn_com (wp, wp, new_wsize); |
156 | 0 | new_wsize++; |
157 | 0 | MPN_INCR_U (wp, new_wsize, CNST_LIMB(1)); |
158 | 0 | wsize_signed = -wsize_signed; |
159 | 0 | } |
160 | 0 | } |
161 | 0 | else /* wsize < xsize */ |
162 | 0 | { |
163 | | /* x bigger than w, so want x*y-w. Submul has given w-x*y, so |
164 | | take twos complement and use an mpn_mul_1 for the rest. */ |
165 | |
|
166 | 0 | mp_limb_t cy2; |
167 | | |
168 | | /* -(-cy*b^n + w-x*y) = (cy-1)*b^n + ~(w-x*y) + 1 */ |
169 | 0 | mpn_com (wp, wp, wsize); |
170 | 0 | cy += mpn_add_1 (wp, wp, wsize, CNST_LIMB(1)); |
171 | 0 | cy -= 1; |
172 | | |
173 | | /* If cy-1 == -1 then hold that -1 for latter. mpn_submul_1 never |
174 | | returns cy==MP_LIMB_T_MAX so that value always indicates a -1. */ |
175 | 0 | cy2 = (cy == MP_LIMB_T_MAX); |
176 | 0 | cy += cy2; |
177 | 0 | MPN_MUL_1C (cy, wp+wsize, xp+wsize, xsize-wsize, y, cy); |
178 | 0 | wp[new_wsize] = cy; |
179 | 0 | new_wsize += (cy != 0); |
180 | | |
181 | | /* Apply any -1 from above. The value at wp+wsize is non-zero |
182 | | because y!=0 and the high limb of x will be non-zero. */ |
183 | 0 | if (cy2) |
184 | 0 | MPN_DECR_U (wp+wsize, new_wsize-wsize, CNST_LIMB(1)); |
185 | | |
186 | 0 | wsize_signed = -wsize_signed; |
187 | 0 | } |
188 | | |
189 | | /* submul can produce high zero limbs due to cancellation, both when w |
190 | | has more limbs or x has more */ |
191 | 0 | MPN_NORMALIZE (wp, new_wsize); |
192 | 0 | } |
193 | | |
194 | 94 | SIZ (w) = (wsize_signed >= 0 ? new_wsize : -new_wsize); |
195 | | |
196 | 94 | ASSERT (new_wsize == 0 || PTR(w)[new_wsize-1] != 0); |
197 | 94 | } |
198 | | |
199 | | |
200 | | void |
201 | | mpz_addmul_ui (mpz_ptr w, mpz_srcptr x, unsigned long y) |
202 | 94 | { |
203 | | #if BITS_PER_ULONG > GMP_NUMB_BITS |
204 | | if (UNLIKELY (y > GMP_NUMB_MAX)) |
205 | | { |
206 | | mpz_t t; |
207 | | mp_ptr tp; |
208 | | mp_size_t xn; |
209 | | TMP_DECL; |
210 | | TMP_MARK; |
211 | | xn = SIZ (x); |
212 | | if (xn == 0) return; |
213 | | MPZ_TMP_INIT (t, ABS (xn) + 1); |
214 | | tp = PTR (t); |
215 | | tp[0] = 0; |
216 | | MPN_COPY (tp + 1, PTR(x), ABS (xn)); |
217 | | SIZ(t) = xn >= 0 ? xn + 1 : xn - 1; |
218 | | mpz_aorsmul_1 (w, t, (mp_limb_t) y >> GMP_NUMB_BITS, (mp_size_t) 0); |
219 | | PTR(t) = tp + 1; |
220 | | SIZ(t) = xn; |
221 | | mpz_aorsmul_1 (w, t, (mp_limb_t) y & GMP_NUMB_MASK, (mp_size_t) 0); |
222 | | TMP_FREE; |
223 | | return; |
224 | | } |
225 | | #endif |
226 | 94 | mpz_aorsmul_1 (w, x, (mp_limb_t) y, (mp_size_t) 0); |
227 | 94 | } |
228 | | |
229 | | void |
230 | | mpz_submul_ui (mpz_ptr w, mpz_srcptr x, unsigned long y) |
231 | 0 | { |
232 | | #if BITS_PER_ULONG > GMP_NUMB_BITS |
233 | | if (y > GMP_NUMB_MAX) |
234 | | { |
235 | | mpz_t t; |
236 | | mp_ptr tp; |
237 | | mp_size_t xn; |
238 | | TMP_DECL; |
239 | | TMP_MARK; |
240 | | xn = SIZ (x); |
241 | | if (xn == 0) return; |
242 | | MPZ_TMP_INIT (t, ABS (xn) + 1); |
243 | | tp = PTR (t); |
244 | | tp[0] = 0; |
245 | | MPN_COPY (tp + 1, PTR(x), ABS (xn)); |
246 | | SIZ(t) = xn >= 0 ? xn + 1 : xn - 1; |
247 | | mpz_aorsmul_1 (w, t, (mp_limb_t) y >> GMP_NUMB_BITS, (mp_size_t) -1); |
248 | | PTR(t) = tp + 1; |
249 | | SIZ(t) = xn; |
250 | | mpz_aorsmul_1 (w, t, (mp_limb_t) y & GMP_NUMB_MASK, (mp_size_t) -1); |
251 | | TMP_FREE; |
252 | | return; |
253 | | } |
254 | | #endif |
255 | 0 | mpz_aorsmul_1 (w, x, (mp_limb_t) y & GMP_NUMB_MASK, (mp_size_t) -1); |
256 | 0 | } |