mulmid.c revision 1.1.1.1.4.2 1 1.1.1.1.4.2 yamt /* mpn_mulmid -- middle product
2 1.1.1.1.4.2 yamt
3 1.1.1.1.4.2 yamt Contributed by David Harvey.
4 1.1.1.1.4.2 yamt
5 1.1.1.1.4.2 yamt THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE. IT IS ONLY
6 1.1.1.1.4.2 yamt SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES. IN FACT, IT IS ALMOST
7 1.1.1.1.4.2 yamt GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
8 1.1.1.1.4.2 yamt
9 1.1.1.1.4.2 yamt Copyright 2011 Free Software Foundation, Inc.
10 1.1.1.1.4.2 yamt
11 1.1.1.1.4.2 yamt This file is part of the GNU MP Library.
12 1.1.1.1.4.2 yamt
13 1.1.1.1.4.2 yamt The GNU MP Library is free software; you can redistribute it and/or modify
14 1.1.1.1.4.2 yamt it under the terms of the GNU Lesser General Public License as published by
15 1.1.1.1.4.2 yamt the Free Software Foundation; either version 3 of the License, or (at your
16 1.1.1.1.4.2 yamt option) any later version.
17 1.1.1.1.4.2 yamt
18 1.1.1.1.4.2 yamt The GNU MP Library is distributed in the hope that it will be useful, but
19 1.1.1.1.4.2 yamt WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 1.1.1.1.4.2 yamt or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
21 1.1.1.1.4.2 yamt License for more details.
22 1.1.1.1.4.2 yamt
23 1.1.1.1.4.2 yamt You should have received a copy of the GNU Lesser General Public License
24 1.1.1.1.4.2 yamt along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
25 1.1.1.1.4.2 yamt
26 1.1.1.1.4.2 yamt
27 1.1.1.1.4.2 yamt #include "gmp.h"
28 1.1.1.1.4.2 yamt #include "gmp-impl.h"
29 1.1.1.1.4.2 yamt
30 1.1.1.1.4.2 yamt
31 1.1.1.1.4.2 yamt #define CHUNK (200 + MULMID_TOOM42_THRESHOLD)
32 1.1.1.1.4.2 yamt
33 1.1.1.1.4.2 yamt
34 1.1.1.1.4.2 yamt void
35 1.1.1.1.4.2 yamt mpn_mulmid (mp_ptr rp,
36 1.1.1.1.4.2 yamt mp_srcptr ap, mp_size_t an,
37 1.1.1.1.4.2 yamt mp_srcptr bp, mp_size_t bn)
38 1.1.1.1.4.2 yamt {
39 1.1.1.1.4.2 yamt mp_size_t rn, k;
40 1.1.1.1.4.2 yamt mp_ptr scratch, temp;
41 1.1.1.1.4.2 yamt
42 1.1.1.1.4.2 yamt ASSERT (an >= bn);
43 1.1.1.1.4.2 yamt ASSERT (bn >= 1);
44 1.1.1.1.4.2 yamt ASSERT (! MPN_OVERLAP_P (rp, an - bn + 3, ap, an));
45 1.1.1.1.4.2 yamt ASSERT (! MPN_OVERLAP_P (rp, an - bn + 3, bp, bn));
46 1.1.1.1.4.2 yamt
47 1.1.1.1.4.2 yamt if (bn < MULMID_TOOM42_THRESHOLD)
48 1.1.1.1.4.2 yamt {
49 1.1.1.1.4.2 yamt /* region not tall enough to make toom42 worthwhile for any portion */
50 1.1.1.1.4.2 yamt
51 1.1.1.1.4.2 yamt if (an < CHUNK)
52 1.1.1.1.4.2 yamt {
53 1.1.1.1.4.2 yamt /* region not too wide either, just call basecase directly */
54 1.1.1.1.4.2 yamt mpn_mulmid_basecase (rp, ap, an, bp, bn);
55 1.1.1.1.4.2 yamt return;
56 1.1.1.1.4.2 yamt }
57 1.1.1.1.4.2 yamt
58 1.1.1.1.4.2 yamt /* Region quite wide. For better locality, use basecase on chunks:
59 1.1.1.1.4.2 yamt
60 1.1.1.1.4.2 yamt AAABBBCC..
61 1.1.1.1.4.2 yamt .AAABBBCC.
62 1.1.1.1.4.2 yamt ..AAABBBCC
63 1.1.1.1.4.2 yamt */
64 1.1.1.1.4.2 yamt
65 1.1.1.1.4.2 yamt k = CHUNK - bn + 1; /* number of diagonals per chunk */
66 1.1.1.1.4.2 yamt
67 1.1.1.1.4.2 yamt /* first chunk (marked A in the above diagram) */
68 1.1.1.1.4.2 yamt mpn_mulmid_basecase (rp, ap, CHUNK, bp, bn);
69 1.1.1.1.4.2 yamt
70 1.1.1.1.4.2 yamt /* remaining chunks (B, C, etc) */
71 1.1.1.1.4.2 yamt an -= k;
72 1.1.1.1.4.2 yamt
73 1.1.1.1.4.2 yamt while (an >= CHUNK)
74 1.1.1.1.4.2 yamt {
75 1.1.1.1.4.2 yamt mp_limb_t t0, t1, cy;
76 1.1.1.1.4.2 yamt ap += k, rp += k;
77 1.1.1.1.4.2 yamt t0 = rp[0], t1 = rp[1];
78 1.1.1.1.4.2 yamt mpn_mulmid_basecase (rp, ap, CHUNK, bp, bn);
79 1.1.1.1.4.2 yamt ADDC_LIMB (cy, rp[0], rp[0], t0); /* add back saved limbs */
80 1.1.1.1.4.2 yamt MPN_INCR_U (rp + 1, k + 1, t1 + cy);
81 1.1.1.1.4.2 yamt an -= k;
82 1.1.1.1.4.2 yamt }
83 1.1.1.1.4.2 yamt
84 1.1.1.1.4.2 yamt if (an >= bn)
85 1.1.1.1.4.2 yamt {
86 1.1.1.1.4.2 yamt /* last remaining chunk */
87 1.1.1.1.4.2 yamt mp_limb_t t0, t1, cy;
88 1.1.1.1.4.2 yamt ap += k, rp += k;
89 1.1.1.1.4.2 yamt t0 = rp[0], t1 = rp[1];
90 1.1.1.1.4.2 yamt mpn_mulmid_basecase (rp, ap, an, bp, bn);
91 1.1.1.1.4.2 yamt ADDC_LIMB (cy, rp[0], rp[0], t0);
92 1.1.1.1.4.2 yamt MPN_INCR_U (rp + 1, an - bn + 2, t1 + cy);
93 1.1.1.1.4.2 yamt }
94 1.1.1.1.4.2 yamt
95 1.1.1.1.4.2 yamt return;
96 1.1.1.1.4.2 yamt }
97 1.1.1.1.4.2 yamt
98 1.1.1.1.4.2 yamt /* region is tall enough for toom42 */
99 1.1.1.1.4.2 yamt
100 1.1.1.1.4.2 yamt rn = an - bn + 1;
101 1.1.1.1.4.2 yamt
102 1.1.1.1.4.2 yamt if (rn < MULMID_TOOM42_THRESHOLD)
103 1.1.1.1.4.2 yamt {
104 1.1.1.1.4.2 yamt /* region not wide enough to make toom42 worthwhile for any portion */
105 1.1.1.1.4.2 yamt
106 1.1.1.1.4.2 yamt TMP_DECL;
107 1.1.1.1.4.2 yamt
108 1.1.1.1.4.2 yamt if (bn < CHUNK)
109 1.1.1.1.4.2 yamt {
110 1.1.1.1.4.2 yamt /* region not too tall either, just call basecase directly */
111 1.1.1.1.4.2 yamt mpn_mulmid_basecase (rp, ap, an, bp, bn);
112 1.1.1.1.4.2 yamt return;
113 1.1.1.1.4.2 yamt }
114 1.1.1.1.4.2 yamt
115 1.1.1.1.4.2 yamt /* Region quite tall. For better locality, use basecase on chunks:
116 1.1.1.1.4.2 yamt
117 1.1.1.1.4.2 yamt AAAAA....
118 1.1.1.1.4.2 yamt .AAAAA...
119 1.1.1.1.4.2 yamt ..BBBBB..
120 1.1.1.1.4.2 yamt ...BBBBB.
121 1.1.1.1.4.2 yamt ....CCCCC
122 1.1.1.1.4.2 yamt */
123 1.1.1.1.4.2 yamt
124 1.1.1.1.4.2 yamt TMP_MARK;
125 1.1.1.1.4.2 yamt
126 1.1.1.1.4.2 yamt temp = TMP_ALLOC_LIMBS (rn + 2);
127 1.1.1.1.4.2 yamt
128 1.1.1.1.4.2 yamt /* first chunk (marked A in the above diagram) */
129 1.1.1.1.4.2 yamt bp += bn - CHUNK, an -= bn - CHUNK;
130 1.1.1.1.4.2 yamt mpn_mulmid_basecase (rp, ap, an, bp, CHUNK);
131 1.1.1.1.4.2 yamt
132 1.1.1.1.4.2 yamt /* remaining chunks (B, C, etc) */
133 1.1.1.1.4.2 yamt bn -= CHUNK;
134 1.1.1.1.4.2 yamt
135 1.1.1.1.4.2 yamt while (bn >= CHUNK)
136 1.1.1.1.4.2 yamt {
137 1.1.1.1.4.2 yamt ap += CHUNK, bp -= CHUNK;
138 1.1.1.1.4.2 yamt mpn_mulmid_basecase (temp, ap, an, bp, CHUNK);
139 1.1.1.1.4.2 yamt mpn_add_n (rp, rp, temp, rn + 2);
140 1.1.1.1.4.2 yamt bn -= CHUNK;
141 1.1.1.1.4.2 yamt }
142 1.1.1.1.4.2 yamt
143 1.1.1.1.4.2 yamt if (bn)
144 1.1.1.1.4.2 yamt {
145 1.1.1.1.4.2 yamt /* last remaining chunk */
146 1.1.1.1.4.2 yamt ap += CHUNK, bp -= bn;
147 1.1.1.1.4.2 yamt mpn_mulmid_basecase (temp, ap, rn + bn - 1, bp, bn);
148 1.1.1.1.4.2 yamt mpn_add_n (rp, rp, temp, rn + 2);
149 1.1.1.1.4.2 yamt }
150 1.1.1.1.4.2 yamt
151 1.1.1.1.4.2 yamt TMP_FREE;
152 1.1.1.1.4.2 yamt return;
153 1.1.1.1.4.2 yamt }
154 1.1.1.1.4.2 yamt
155 1.1.1.1.4.2 yamt /* we're definitely going to use toom42 somewhere */
156 1.1.1.1.4.2 yamt
157 1.1.1.1.4.2 yamt if (bn > rn)
158 1.1.1.1.4.2 yamt {
159 1.1.1.1.4.2 yamt /* slice region into chunks, use toom42 on all chunks except possibly
160 1.1.1.1.4.2 yamt the last:
161 1.1.1.1.4.2 yamt
162 1.1.1.1.4.2 yamt AA....
163 1.1.1.1.4.2 yamt .AA...
164 1.1.1.1.4.2 yamt ..BB..
165 1.1.1.1.4.2 yamt ...BB.
166 1.1.1.1.4.2 yamt ....CC
167 1.1.1.1.4.2 yamt */
168 1.1.1.1.4.2 yamt
169 1.1.1.1.4.2 yamt TMP_DECL;
170 1.1.1.1.4.2 yamt TMP_MARK;
171 1.1.1.1.4.2 yamt
172 1.1.1.1.4.2 yamt temp = TMP_ALLOC_LIMBS (rn + 2 + mpn_toom42_mulmid_itch (rn));
173 1.1.1.1.4.2 yamt scratch = temp + rn + 2;
174 1.1.1.1.4.2 yamt
175 1.1.1.1.4.2 yamt /* first chunk (marked A in the above diagram) */
176 1.1.1.1.4.2 yamt bp += bn - rn;
177 1.1.1.1.4.2 yamt mpn_toom42_mulmid (rp, ap, bp, rn, scratch);
178 1.1.1.1.4.2 yamt
179 1.1.1.1.4.2 yamt /* remaining chunks (B, C, etc) */
180 1.1.1.1.4.2 yamt bn -= rn;
181 1.1.1.1.4.2 yamt
182 1.1.1.1.4.2 yamt while (bn >= rn)
183 1.1.1.1.4.2 yamt {
184 1.1.1.1.4.2 yamt ap += rn, bp -= rn;
185 1.1.1.1.4.2 yamt mpn_toom42_mulmid (temp, ap, bp, rn, scratch);
186 1.1.1.1.4.2 yamt mpn_add_n (rp, rp, temp, rn + 2);
187 1.1.1.1.4.2 yamt bn -= rn;
188 1.1.1.1.4.2 yamt }
189 1.1.1.1.4.2 yamt
190 1.1.1.1.4.2 yamt if (bn)
191 1.1.1.1.4.2 yamt {
192 1.1.1.1.4.2 yamt /* last remaining chunk */
193 1.1.1.1.4.2 yamt ap += rn, bp -= bn;
194 1.1.1.1.4.2 yamt mpn_mulmid (temp, ap, rn + bn - 1, bp, bn);
195 1.1.1.1.4.2 yamt mpn_add_n (rp, rp, temp, rn + 2);
196 1.1.1.1.4.2 yamt }
197 1.1.1.1.4.2 yamt
198 1.1.1.1.4.2 yamt TMP_FREE;
199 1.1.1.1.4.2 yamt }
200 1.1.1.1.4.2 yamt else
201 1.1.1.1.4.2 yamt {
202 1.1.1.1.4.2 yamt /* slice region into chunks, use toom42 on all chunks except possibly
203 1.1.1.1.4.2 yamt the last:
204 1.1.1.1.4.2 yamt
205 1.1.1.1.4.2 yamt AAABBBCC..
206 1.1.1.1.4.2 yamt .AAABBBCC.
207 1.1.1.1.4.2 yamt ..AAABBBCC
208 1.1.1.1.4.2 yamt */
209 1.1.1.1.4.2 yamt
210 1.1.1.1.4.2 yamt TMP_DECL;
211 1.1.1.1.4.2 yamt TMP_MARK;
212 1.1.1.1.4.2 yamt
213 1.1.1.1.4.2 yamt scratch = TMP_ALLOC_LIMBS (mpn_toom42_mulmid_itch (bn));
214 1.1.1.1.4.2 yamt
215 1.1.1.1.4.2 yamt /* first chunk (marked A in the above diagram) */
216 1.1.1.1.4.2 yamt mpn_toom42_mulmid (rp, ap, bp, bn, scratch);
217 1.1.1.1.4.2 yamt
218 1.1.1.1.4.2 yamt /* remaining chunks (B, C, etc) */
219 1.1.1.1.4.2 yamt rn -= bn;
220 1.1.1.1.4.2 yamt
221 1.1.1.1.4.2 yamt while (rn >= bn)
222 1.1.1.1.4.2 yamt {
223 1.1.1.1.4.2 yamt mp_limb_t t0, t1, cy;
224 1.1.1.1.4.2 yamt ap += bn, rp += bn;
225 1.1.1.1.4.2 yamt t0 = rp[0], t1 = rp[1];
226 1.1.1.1.4.2 yamt mpn_toom42_mulmid (rp, ap, bp, bn, scratch);
227 1.1.1.1.4.2 yamt ADDC_LIMB (cy, rp[0], rp[0], t0); /* add back saved limbs */
228 1.1.1.1.4.2 yamt MPN_INCR_U (rp + 1, bn + 1, t1 + cy);
229 1.1.1.1.4.2 yamt rn -= bn;
230 1.1.1.1.4.2 yamt }
231 1.1.1.1.4.2 yamt
232 1.1.1.1.4.2 yamt TMP_FREE;
233 1.1.1.1.4.2 yamt
234 1.1.1.1.4.2 yamt if (rn)
235 1.1.1.1.4.2 yamt {
236 1.1.1.1.4.2 yamt /* last remaining chunk */
237 1.1.1.1.4.2 yamt mp_limb_t t0, t1, cy;
238 1.1.1.1.4.2 yamt ap += bn, rp += bn;
239 1.1.1.1.4.2 yamt t0 = rp[0], t1 = rp[1];
240 1.1.1.1.4.2 yamt mpn_mulmid (rp, ap, rn + bn - 1, bp, bn);
241 1.1.1.1.4.2 yamt ADDC_LIMB (cy, rp[0], rp[0], t0);
242 1.1.1.1.4.2 yamt MPN_INCR_U (rp + 1, rn + 1, t1 + cy);
243 1.1.1.1.4.2 yamt }
244 1.1.1.1.4.2 yamt }
245 1.1.1.1.4.2 yamt }
246