1 /* mpc_mul -- Multiply two complex numbers
2
3 Copyright (C) 2002, 2004, 2005, 2008, 2009, 2010, 2011, 2012, 2016, 2020, 2022 INRIA
4
5 This file is part of GNU MPC.
6
7 GNU MPC is free software; you can redistribute it and/or modify it under
8 he terms of the GNU Lesser General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11
12 GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
15 more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program. If not, see http://www.gnu.org/licenses/ .
19 */
20
21 #include <stdio.h> /* for MPC_ASSERT */
22 #include "mpc-impl.h"
23
24 #define mpz_add_si(z,x,y) do { \
25 if (y >= 0) \
26 mpz_add_ui (z, x, (long int) y); \
27 else \
28 mpz_sub_ui (z, x, (long int) (-y)); \
29 } while (0);
30
31 /* compute z=x*y when x has an infinite part */
32 static int
mul_infinite(mpc_ptr z,mpc_srcptr x,mpc_srcptr y)33 mul_infinite (mpc_ptr z, mpc_srcptr x, mpc_srcptr y)
34 {
35 /* Let x=xr+i*xi and y=yr+i*yi; extract the signs of the operands */
36 int xrs = mpfr_signbit (mpc_realref (x)) ? -1 : 1;
37 int xis = mpfr_signbit (mpc_imagref (x)) ? -1 : 1;
38 int yrs = mpfr_signbit (mpc_realref (y)) ? -1 : 1;
39 int yis = mpfr_signbit (mpc_imagref (y)) ? -1 : 1;
40
41 int u, v;
42
43 /* compute the sign of
44 u = xrs * yrs * xr * yr - xis * yis * xi * yi
45 v = xrs * yis * xr * yi + xis * yrs * xi * yr
46 +1 if positive, -1 if negative, 0 if NaN */
47 if ( mpfr_nan_p (mpc_realref (x)) || mpfr_nan_p (mpc_imagref (x))
48 || mpfr_nan_p (mpc_realref (y)) || mpfr_nan_p (mpc_imagref (y))) {
49 u = 0;
50 v = 0;
51 }
52 else if (mpfr_inf_p (mpc_realref (x))) {
53 /* x = (+/-inf) xr + i*xi */
54 u = ( mpfr_zero_p (mpc_realref (y))
55 || (mpfr_inf_p (mpc_imagref (x)) && mpfr_zero_p (mpc_imagref (y)))
56 || (mpfr_zero_p (mpc_imagref (x)) && mpfr_inf_p (mpc_imagref (y)))
57 || ( (mpfr_inf_p (mpc_imagref (x)) || mpfr_inf_p (mpc_imagref (y)))
58 && xrs*yrs == xis*yis)
59 ? 0 : xrs * yrs);
60 v = ( mpfr_zero_p (mpc_imagref (y))
61 || (mpfr_inf_p (mpc_imagref (x)) && mpfr_zero_p (mpc_realref (y)))
62 || (mpfr_zero_p (mpc_imagref (x)) && mpfr_inf_p (mpc_realref (y)))
63 || ( (mpfr_inf_p (mpc_imagref (x)) || mpfr_inf_p (mpc_imagref (x)))
64 && xrs*yis != xis*yrs)
65 ? 0 : xrs * yis);
66 }
67 else {
68 /* x = xr + i*(+/-inf) with |xr| != inf */
69 u = ( mpfr_zero_p (mpc_imagref (y))
70 || (mpfr_zero_p (mpc_realref (x)) && mpfr_inf_p (mpc_realref (y)))
71 || (mpfr_inf_p (mpc_realref (y)) && xrs*yrs == xis*yis)
72 ? 0 : -xis * yis);
73 v = ( mpfr_zero_p (mpc_realref (y))
74 || (mpfr_zero_p (mpc_realref (x)) && mpfr_inf_p (mpc_imagref (y)))
75 || (mpfr_inf_p (mpc_imagref (y)) && xrs*yis != xis*yrs)
76 ? 0 : xis * yrs);
77 }
78
79 if (u == 0 && v == 0) {
80 /* Naive result is NaN+i*NaN. Obtain an infinity using the algorithm
81 given in Annex G.5.1 of the ISO C99 standard */
82 int xr = (mpfr_zero_p (mpc_realref (x)) || mpfr_nan_p (mpc_realref (x)) ? 0
83 : (mpfr_inf_p (mpc_realref (x)) ? 1 : 0));
84 int xi = (mpfr_zero_p (mpc_imagref (x)) || mpfr_nan_p (mpc_imagref (x)) ? 0
85 : (mpfr_inf_p (mpc_imagref (x)) ? 1 : 0));
86 int yr = (mpfr_zero_p (mpc_realref (y)) || mpfr_nan_p (mpc_realref (y)) ? 0 : 1);
87 int yi = (mpfr_zero_p (mpc_imagref (y)) || mpfr_nan_p (mpc_imagref (y)) ? 0 : 1);
88 if (mpc_inf_p (y)) {
89 yr = mpfr_inf_p (mpc_realref (y)) ? 1 : 0;
90 yi = mpfr_inf_p (mpc_imagref (y)) ? 1 : 0;
91 }
92
93 u = xrs * xr * yrs * yr - xis * xi * yis * yi;
94 v = xrs * xr * yis * yi + xis * xi * yrs * yr;
95 }
96
97 if (u == 0)
98 mpfr_set_nan (mpc_realref (z));
99 else
100 mpfr_set_inf (mpc_realref (z), u);
101
102 if (v == 0)
103 mpfr_set_nan (mpc_imagref (z));
104 else
105 mpfr_set_inf (mpc_imagref (z), v);
106
107 return MPC_INEX (0, 0); /* exact */
108 }
109
110
111 /* compute z = x*y for Im(y) == 0 */
112 static int
mul_real(mpc_ptr z,mpc_srcptr x,mpc_srcptr y,mpc_rnd_t rnd)113 mul_real (mpc_ptr z, mpc_srcptr x, mpc_srcptr y, mpc_rnd_t rnd)
114 {
115 int xrs, xis, yrs, yis;
116 int inex;
117
118 /* save signs of operands */
119 xrs = MPFR_SIGNBIT (mpc_realref (x));
120 xis = MPFR_SIGNBIT (mpc_imagref (x));
121 yrs = MPFR_SIGNBIT (mpc_realref (y));
122 yis = MPFR_SIGNBIT (mpc_imagref (y));
123
124 inex = mpc_mul_fr (z, x, mpc_realref (y), rnd);
125 /* Signs of zeroes may be wrong. Their correction does not change the
126 inexact flag. */
127 if (mpfr_zero_p (mpc_realref (z)))
128 mpfr_setsign (mpc_realref (z), mpc_realref (z), MPC_RND_RE(rnd) == MPFR_RNDD
129 || (xrs != yrs && xis == yis), MPFR_RNDN);
130 if (mpfr_zero_p (mpc_imagref (z)))
131 mpfr_setsign (mpc_imagref (z), mpc_imagref (z), MPC_RND_IM (rnd) == MPFR_RNDD
132 || (xrs != yis && xis != yrs), MPFR_RNDN);
133
134 return inex;
135 }
136
137
138 /* compute z = x*y for Re(y) == 0, and Im(x) != 0 and Im(y) != 0 */
139 static int
mul_imag(mpc_ptr z,mpc_srcptr x,mpc_srcptr y,mpc_rnd_t rnd)140 mul_imag (mpc_ptr z, mpc_srcptr x, mpc_srcptr y, mpc_rnd_t rnd)
141 {
142 int sign;
143 int inex_re, inex_im;
144 int overlap = z == x || z == y;
145 mpc_t rop;
146
147 if (overlap)
148 mpc_init3 (rop, MPC_PREC_RE (z), MPC_PREC_IM (z));
149 else
150 rop [0] = z[0];
151
152 sign = (MPFR_SIGNBIT (mpc_realref (y)) != MPFR_SIGNBIT (mpc_imagref (x)))
153 && (MPFR_SIGNBIT (mpc_imagref (y)) != MPFR_SIGNBIT (mpc_realref (x)));
154
155 inex_re = -mpfr_mul (mpc_realref (rop), mpc_imagref (x), mpc_imagref (y),
156 INV_RND (MPC_RND_RE (rnd)));
157 mpfr_neg (mpc_realref (rop), mpc_realref (rop), MPFR_RNDN); /* exact */
158 inex_im = mpfr_mul (mpc_imagref (rop), mpc_realref (x), mpc_imagref (y),
159 MPC_RND_IM (rnd));
160 mpc_set (z, rop, MPC_RNDNN);
161
162 /* Sign of zeroes may be wrong (note that Re(z) cannot be zero) */
163 if (mpfr_zero_p (mpc_imagref (z)))
164 mpfr_setsign (mpc_imagref (z), mpc_imagref (z), MPC_RND_IM (rnd) == MPFR_RNDD
165 || sign, MPFR_RNDN);
166
167 if (overlap)
168 mpc_clear (rop);
169
170 return MPC_INEX (inex_re, inex_im);
171 }
172
173
174 int
mpc_mul_naive(mpc_ptr z,mpc_srcptr x,mpc_srcptr y,mpc_rnd_t rnd)175 mpc_mul_naive (mpc_ptr z, mpc_srcptr x, mpc_srcptr y, mpc_rnd_t rnd)
176 {
177 /* computes z=x*y by the schoolbook method, where x and y are assumed
178 to be finite and without zero parts */
179 int overlap, inex_re, inex_im;
180 mpc_t rop;
181
182 MPC_ASSERT ( mpfr_regular_p (mpc_realref (x)) && mpfr_regular_p (mpc_imagref (x))
183 && mpfr_regular_p (mpc_realref (y)) && mpfr_regular_p (mpc_imagref (y)));
184 overlap = (z == x) || (z == y);
185 if (overlap)
186 mpc_init3 (rop, MPC_PREC_RE (z), MPC_PREC_IM (z));
187 else
188 rop [0] = z [0];
189
190 inex_re = mpfr_fmms (mpc_realref (rop), mpc_realref (x), mpc_realref (y),
191 mpc_imagref (x), mpc_imagref (y), MPC_RND_RE (rnd));
192 inex_im = mpfr_fmma (mpc_imagref (rop), mpc_realref (x), mpc_imagref (y),
193 mpc_imagref (x), mpc_realref (y), MPC_RND_IM (rnd));
194
195 mpc_set (z, rop, MPC_RNDNN);
196 if (overlap)
197 mpc_clear (rop);
198
199 return MPC_INEX (inex_re, inex_im);
200 }
201
202
203 int
mpc_mul_karatsuba(mpc_ptr rop,mpc_srcptr op1,mpc_srcptr op2,mpc_rnd_t rnd)204 mpc_mul_karatsuba (mpc_ptr rop, mpc_srcptr op1, mpc_srcptr op2, mpc_rnd_t rnd)
205 {
206 /* computes rop=op1*op2 by a Karatsuba algorithm, where op1 and op2
207 are assumed to be finite and without zero parts */
208 mpfr_srcptr a, b, c, d;
209 int mul_i, ok, inexact, mul_a, mul_c, inex_re = 0, inex_im = 0, sign_x, sign_u;
210 mpfr_t u, v, w, x;
211 mpfr_prec_t prec, prec_re, prec_u, prec_v, prec_w;
212 mpfr_rnd_t rnd_re, rnd_u;
213 int overlap;
214 /* true if rop == op1 or rop == op2 */
215 mpc_t result;
216 /* overlap is quite difficult to handle, because we have to tentatively
217 round the variable u in the end to either the real or the imaginary
218 part of rop (it is not possible to tell now whether the real or
219 imaginary part is used). If this fails, we have to start again and
220 need the correct values of op1 and op2.
221 So we just create a new variable for the result in this case. */
222 mpfr_ptr ref;
223 int loop;
224 const int MAX_MUL_LOOP = 1;
225
226 overlap = (rop == op1) || (rop == op2);
227 if (overlap)
228 mpc_init3 (result, MPC_PREC_RE (rop), MPC_PREC_IM (rop));
229 else
230 result [0] = rop [0];
231
232 a = mpc_realref(op1);
233 b = mpc_imagref(op1);
234 c = mpc_realref(op2);
235 d = mpc_imagref(op2);
236
237 /* (a + i*b) * (c + i*d) = [ac - bd] + i*[ad + bc] */
238
239 mul_i = 0; /* number of multiplications by i */
240 mul_a = 1; /* implicit factor for a */
241 mul_c = 1; /* implicit factor for c */
242
243 if (mpfr_cmp_abs (a, b) < 0)
244 {
245 MPFR_SWAP (a, b);
246 mul_i ++;
247 mul_a = -1; /* consider i * (a+i*b) = -b + i*a */
248 }
249
250 if (mpfr_cmp_abs (c, d) < 0)
251 {
252 MPFR_SWAP (c, d);
253 mul_i ++;
254 mul_c = -1; /* consider -d + i*c instead of c + i*d */
255 }
256
257 /* find the precision and rounding mode for the new real part */
258 if (mul_i % 2)
259 {
260 prec_re = MPC_PREC_IM(rop);
261 rnd_re = MPC_RND_IM(rnd);
262 }
263 else /* mul_i = 0 or 2 */
264 {
265 prec_re = MPC_PREC_RE(rop);
266 rnd_re = MPC_RND_RE(rnd);
267 }
268
269 if (mul_i)
270 rnd_re = INV_RND(rnd_re);
271
272 /* now |a| >= |b| and |c| >= |d| */
273 prec = MPC_MAX_PREC(rop);
274
275 mpfr_init2 (v, prec_v = mpfr_get_prec (a) + mpfr_get_prec (d));
276 mpfr_init2 (w, prec_w = mpfr_get_prec (b) + mpfr_get_prec (c));
277 mpfr_init2 (u, 2);
278 mpfr_init2 (x, 2);
279
280 inexact = mpfr_mul (v, a, d, MPFR_RNDN);
281 if (inexact) {
282 /* over- or underflow */
283 ok = 0;
284 goto clear;
285 }
286 if (mul_a == -1)
287 mpfr_neg (v, v, MPFR_RNDN);
288
289 inexact = mpfr_mul (w, b, c, MPFR_RNDN);
290 if (inexact) {
291 /* over- or underflow */
292 ok = 0;
293 goto clear;
294 }
295 if (mul_c == -1)
296 mpfr_neg (w, w, MPFR_RNDN);
297
298 /* compute sign(v-w) */
299 sign_x = mpfr_cmp_abs (v, w);
300 if (sign_x > 0)
301 sign_x = 2 * mpfr_sgn (v) - mpfr_sgn (w);
302 else if (sign_x == 0)
303 sign_x = mpfr_sgn (v) - mpfr_sgn (w);
304 else
305 sign_x = mpfr_sgn (v) - 2 * mpfr_sgn (w);
306
307 sign_u = mul_a * mpfr_sgn (a) * mul_c * mpfr_sgn (c);
308
309 if (sign_x * sign_u < 0)
310 { /* swap inputs */
311 MPFR_SWAP (a, c);
312 MPFR_SWAP (b, d);
313 mpfr_swap (v, w);
314 { int tmp; tmp = mul_a; mul_a = mul_c; mul_c = tmp; }
315 sign_x = - sign_x;
316 }
317
318 /* now sign_x * sign_u >= 0 */
319 loop = 0;
320 do
321 {
322 loop++;
323 /* the following should give failures with prob. <= 1/prec */
324 prec += mpc_ceil_log2 (prec) + 3;
325
326 mpfr_set_prec (u, prec_u = prec);
327 mpfr_set_prec (x, prec);
328
329 /* first compute away(b +/- a) and store it in u */
330 inexact = (mul_a == -1 ?
331 mpfr_sub (u, b, a, MPFR_RNDA) :
332 mpfr_add (u, b, a, MPFR_RNDA));
333
334 /* then compute away(+/-c - d) and store it in x */
335 inexact |= (mul_c == -1 ?
336 mpfr_add (x, c, d, MPFR_RNDA) :
337 mpfr_sub (x, c, d, MPFR_RNDA));
338 if (mul_c == -1)
339 mpfr_neg (x, x, MPFR_RNDN);
340
341 if (inexact == 0)
342 mpfr_prec_round (u, prec_u = 2 * prec, MPFR_RNDN);
343
344 /* compute away(u*x) and store it in u */
345 inexact |= mpfr_mul (u, u, x, MPFR_RNDA);
346 /* (a+b)*(c-d) */
347
348 /* if all computations are exact up to here, it may be that
349 the real part is exact, thus we need if possible to
350 compute v - w exactly */
351 if (inexact == 0)
352 {
353 mpfr_prec_t prec_x;
354 /* v and w are different from 0, so mpfr_get_exp is safe to use */
355 prec_x = SAFE_ABS (mpfr_exp_t, mpfr_get_exp (v) - mpfr_get_exp (w))
356 + MPC_MAX (prec_v, prec_w) + 1;
357 /* +1 is necessary for a potential carry */
358 /* ensure we do not use a too large precision */
359 if (prec_x > prec_u)
360 prec_x = prec_u;
361 if (prec_x > prec)
362 mpfr_prec_round (x, prec_x, MPFR_RNDN);
363 }
364
365 rnd_u = (sign_u > 0) ? MPFR_RNDU : MPFR_RNDD;
366 inexact |= mpfr_sub (x, v, w, rnd_u); /* ad - bc */
367
368 /* in case u=0, ensure that rnd_u rounds x away from zero */
369 if (mpfr_sgn (u) == 0)
370 rnd_u = (mpfr_sgn (x) > 0) ? MPFR_RNDU : MPFR_RNDD;
371 inexact |= mpfr_add (u, u, x, rnd_u); /* ac - bd */
372
373 ok = inexact == 0 ||
374 mpfr_can_round (u, prec_u - 3, rnd_u, MPFR_RNDZ,
375 prec_re + (rnd_re == MPFR_RNDN));
376 /* this ensures both we can round correctly and determine the correct
377 inexact flag (for rounding to nearest) */
378 }
379 while (!ok && loop <= MAX_MUL_LOOP);
380 /* after MAX_MUL_LOOP rounds, use mpc_naive instead */
381
382 if (ok) {
383 /* if inexact is zero, then u is exactly ac-bd, otherwise fix the sign
384 of the inexact flag for u, which was rounded away from ac-bd */
385 if (inexact != 0)
386 inexact = mpfr_sgn (u);
387
388 if (mul_i == 0)
389 {
390 inex_re = mpfr_set (mpc_realref(result), u, MPC_RND_RE(rnd));
391 if (inex_re == 0)
392 {
393 inex_re = inexact; /* u is rounded away from 0 */
394 inex_im = mpfr_add (mpc_imagref(result), v, w, MPC_RND_IM(rnd));
395 }
396 else
397 inex_im = mpfr_add (mpc_imagref(result), v, w, MPC_RND_IM(rnd));
398 }
399 else if (mul_i == 1) /* (x+i*y)/i = y - i*x */
400 {
401 inex_im = mpfr_neg (mpc_imagref(result), u, MPC_RND_IM(rnd));
402 if (inex_im == 0)
403 {
404 inex_im = -inexact; /* u is rounded away from 0 */
405 inex_re = mpfr_add (mpc_realref(result), v, w, MPC_RND_RE(rnd));
406 }
407 else
408 inex_re = mpfr_add (mpc_realref(result), v, w, MPC_RND_RE(rnd));
409 }
410 else /* mul_i = 2, z/i^2 = -z */
411 {
412 inex_re = mpfr_neg (mpc_realref(result), u, MPC_RND_RE(rnd));
413 if (inex_re == 0)
414 {
415 inex_re = -inexact; /* u is rounded away from 0 */
416 inex_im = -mpfr_add (mpc_imagref(result), v, w,
417 INV_RND(MPC_RND_IM(rnd)));
418 mpfr_neg (mpc_imagref(result), mpc_imagref(result), MPC_RND_IM(rnd));
419 }
420 else
421 {
422 inex_im = -mpfr_add (mpc_imagref(result), v, w,
423 INV_RND(MPC_RND_IM(rnd)));
424 mpfr_neg (mpc_imagref(result), mpc_imagref(result), MPC_RND_IM(rnd));
425 }
426 }
427
428 /* Clear potential signs of 0. */
429 if (!inex_re) {
430 ref = mpc_realref (result);
431 if (mpfr_zero_p (ref) && mpfr_signbit (ref))
432 MPFR_CHANGE_SIGN (ref);
433 }
434 if (!inex_im) {
435 ref = mpc_imagref (result);
436 if (mpfr_zero_p (ref) && mpfr_signbit (ref))
437 MPFR_CHANGE_SIGN (ref);
438 }
439
440 mpc_set (rop, result, MPC_RNDNN);
441 }
442
443 clear:
444 mpfr_clear (u);
445 mpfr_clear (v);
446 mpfr_clear (w);
447 mpfr_clear (x);
448 if (overlap)
449 mpc_clear (result);
450
451 if (ok)
452 return MPC_INEX(inex_re, inex_im);
453 else
454 return mpc_mul_naive (rop, op1, op2, rnd);
455 }
456
457
458 int
mpc_mul(mpc_ptr a,mpc_srcptr b,mpc_srcptr c,mpc_rnd_t rnd)459 mpc_mul (mpc_ptr a, mpc_srcptr b, mpc_srcptr c, mpc_rnd_t rnd)
460 {
461 /* Conforming to ISO C99 standard (G.5.1 multiplicative operators),
462 infinities are treated specially if both parts are NaN when computed
463 naively. */
464 if (mpc_inf_p (b))
465 return mul_infinite (a, b, c);
466 if (mpc_inf_p (c))
467 return mul_infinite (a, c, b);
468
469 /* NaN contamination of both parts in result */
470 if (mpfr_nan_p (mpc_realref (b)) || mpfr_nan_p (mpc_imagref (b))
471 || mpfr_nan_p (mpc_realref (c)) || mpfr_nan_p (mpc_imagref (c))) {
472 mpfr_set_nan (mpc_realref (a));
473 mpfr_set_nan (mpc_imagref (a));
474 return MPC_INEX (0, 0);
475 }
476
477 /* check for real multiplication */
478 if (mpfr_zero_p (mpc_imagref (b)))
479 return mul_real (a, c, b, rnd);
480 if (mpfr_zero_p (mpc_imagref (c)))
481 return mul_real (a, b, c, rnd);
482
483 /* check for purely imaginary multiplication */
484 if (mpfr_zero_p (mpc_realref (b)))
485 return mul_imag (a, c, b, rnd);
486 if (mpfr_zero_p (mpc_realref (c)))
487 return mul_imag (a, b, c, rnd);
488
489 /* If the real and imaginary part of one argument have a very different */
490 /* exponent, it is not reasonable to use Karatsuba multiplication. */
491 if ( SAFE_ABS (mpfr_exp_t,
492 mpfr_get_exp (mpc_realref (b)) - mpfr_get_exp (mpc_imagref (b)))
493 > (mpfr_exp_t) MPC_MAX_PREC (b) / 2
494 || SAFE_ABS (mpfr_exp_t,
495 mpfr_get_exp (mpc_realref (c)) - mpfr_get_exp (mpc_imagref (c)))
496 > (mpfr_exp_t) MPC_MAX_PREC (c) / 2)
497 return mpc_mul_naive (a, b, c, rnd);
498 else
499 return ((MPC_MAX_PREC(a)
500 <= (mpfr_prec_t) MUL_KARATSUBA_THRESHOLD * BITS_PER_MP_LIMB)
501 ? mpc_mul_naive : mpc_mul_karatsuba) (a, b, c, rnd);
502 }
503