1 /* balls -- Functions for complex ball arithmetic.
2
3 Copyright (C) 2018, 2020, 2021, 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 the 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 <limits.h> /* for CHAR_BIT */
22 #include <stdio.h> /* for FILE */
23 #include "mpc-impl.h"
24
mpcb_out_str(FILE * f,mpcb_srcptr op)25 void mpcb_out_str (FILE *f, mpcb_srcptr op)
26 {
27 mpc_out_str (f, 10, 0, op->c, MPC_RNDNN);
28 fprintf (f, " ");
29 mpcr_out_str (f, op->r);
30 fprintf (f, "\n");
31 }
32
33 void
mpcb_init(mpcb_ptr rop)34 mpcb_init (mpcb_ptr rop)
35 {
36 mpc_init2 (rop->c, 2);
37 mpcr_set_inf (rop->r);
38 }
39
40
41 void
mpcb_clear(mpcb_ptr rop)42 mpcb_clear (mpcb_ptr rop)
43 {
44 mpc_clear (rop->c);
45 }
46
47
48 mpfr_prec_t
mpcb_get_prec(mpcb_srcptr op)49 mpcb_get_prec (mpcb_srcptr op)
50 {
51 return mpc_get_prec (op->c);
52 }
53
54
55 void
mpcb_set_prec(mpcb_ptr rop,mpfr_prec_t prec)56 mpcb_set_prec (mpcb_ptr rop, mpfr_prec_t prec)
57 {
58 mpc_set_prec (rop->c, prec);
59 mpcr_set_inf (rop->r);
60 }
61
62
63 void
mpcb_set(mpcb_ptr rop,mpcb_srcptr op)64 mpcb_set (mpcb_ptr rop, mpcb_srcptr op)
65 {
66 if (rop != op) {
67 mpc_set_prec (rop->c, mpc_get_prec (op->c));
68 mpc_set (rop->c, op->c, MPC_RNDNN);
69 mpcr_set (rop->r, op->r);
70 }
71 }
72
73
74 void
mpcb_set_inf(mpcb_ptr rop)75 mpcb_set_inf (mpcb_ptr rop)
76 {
77 mpc_set_prec (rop->c, 2);
78 mpc_set_ui_ui (rop->c, 0, 0, MPC_RNDNN);
79 mpcr_set_inf (rop->r);
80 }
81
82
83 void
mpcb_set_c(mpcb_ptr rop,mpc_srcptr op,mpfr_prec_t prec,unsigned long int err_re,unsigned long int err_im)84 mpcb_set_c (mpcb_ptr rop, mpc_srcptr op, mpfr_prec_t prec,
85 unsigned long int err_re, unsigned long int err_im)
86 /* Set the precision of rop to prec and assign a ball with centre op
87 to it. err_re and err_im contain potential errors in the real and
88 imaginary parts of op as multiples of a half ulp. For instance,
89 if the real part of op is exact, err_re should be set to 0;
90 if it is the result of rounding to nearest, it should be set to 1;
91 if it is the result of directed rounding, it should be set to 2.
92 The radius of the ball reflects err_re and err_im and the potential
93 additional rounding error that can occur when the precision of op
94 is higher than prec. If the real part of op is 0, then err_re
95 should be 0, since then ulp notation makes no sense, and similarly
96 for the imaginary part; otherwise the radius is set to infinity.
97 The implementation takes potential different precisions in the real
98 and imaginary parts of op into account. */
99 {
100 int inex;
101 mpcr_t relerr_re, relerr_im;
102
103 mpc_set_prec (rop->c, prec);
104 inex = mpc_set (rop->c, op, MPC_RNDNN);
105
106 if ( (mpfr_zero_p (mpc_realref (op)) && err_re > 0)
107 || (mpfr_zero_p (mpc_imagref (op)) && err_im > 0)
108 || !mpc_fin_p (op))
109 mpcr_set_inf (rop->r);
110 else {
111 mpcr_set_ui64_2si64 (relerr_re, (uint64_t) err_re,
112 (int64_t) (-mpfr_get_prec (mpc_realref (op))));
113 /* prop:relerror of algorithms.tex */
114 if (MPC_INEX_RE (inex))
115 mpcr_add_rounding_error (relerr_re, prec, MPFR_RNDN);
116 mpcr_set_ui64_2si64 (relerr_im, (uint64_t) err_im,
117 (int64_t) (-mpfr_get_prec (mpc_imagref (op))));
118 if (MPC_INEX_IM (inex))
119 mpcr_add_rounding_error (relerr_im, prec, MPFR_RNDN);
120 mpcr_max (rop->r, relerr_re, relerr_im);
121 /* prop:comrelerror in algorithms.tex */
122 }
123 }
124
125
126 void
mpcb_set_ui_ui(mpcb_ptr z,unsigned long int re,unsigned long int im,mpfr_prec_t prec)127 mpcb_set_ui_ui (mpcb_ptr z, unsigned long int re, unsigned long int im,
128 mpfr_prec_t prec)
129 /* Set the precision of z to prec and assign a ball with centre
130 re+I*im to it. If prec is too small to hold the centre coordinates
131 without rounding, use the minimal possible precision instead. */
132 {
133 prec = MPC_MAX (prec,
134 (mpfr_prec_t) (CHAR_BIT * sizeof (unsigned long int)));
135 mpc_set_prec (z->c, prec);
136 mpc_set_ui_ui (z->c, re, im, MPC_RNDNN);
137 mpcr_set_zero (z->r);
138 }
139
140
141 void
mpcb_neg(mpcb_ptr z,mpcb_srcptr z1)142 mpcb_neg (mpcb_ptr z, mpcb_srcptr z1)
143 {
144 mpfr_prec_t p;
145 int overlap = (z == z1);
146
147 if (!overlap) {
148 p = mpcb_get_prec (z1);
149 if (mpcb_get_prec (z) != p)
150 mpcb_set_prec (z, p);
151 }
152
153 mpc_neg (z->c, z1->c, MPC_RNDNN); /* exact */
154 mpcr_set (z->r, z1->r);
155 }
156
157
158 void
mpcb_mul(mpcb_ptr z,mpcb_srcptr z1,mpcb_srcptr z2)159 mpcb_mul (mpcb_ptr z, mpcb_srcptr z1, mpcb_srcptr z2)
160 {
161 mpcr_t r;
162 mpfr_prec_t p = MPC_MIN (mpcb_get_prec (z1), mpcb_get_prec (z2));
163 int overlap = (z == z1 || z == z2);
164 mpc_t zc;
165
166 if (overlap)
167 mpc_init2 (zc, p);
168 else {
169 zc [0] = z->c [0];
170 mpc_set_prec (zc, p);
171 }
172 mpc_mul (zc, z1->c, z2->c, MPC_RNDNN);
173 if (overlap)
174 mpc_clear (z->c);
175 z->c [0] = zc [0];
176
177 /* generic error of multiplication */
178 mpcr_mul (r, z1->r, z2->r);
179 mpcr_add (r, r, z1->r);
180 mpcr_add (r, r, z2->r);
181 /* error of rounding to nearest */
182 mpcr_add_rounding_error (r, p, MPFR_RNDN);
183 mpcr_set (z->r, r);
184 }
185
186
187 void
mpcb_sqr(mpcb_ptr z,mpcb_srcptr z1)188 mpcb_sqr (mpcb_ptr z, mpcb_srcptr z1)
189 {
190 mpcr_t r, r2;
191 mpfr_prec_t p = mpcb_get_prec (z1);
192 int overlap = (z == z1);
193
194 /* Compute the error first in case there is overlap. */
195 mpcr_mul_2ui (r2, z1->r, 1);
196 mpcr_sqr (r, z1->r);
197 mpcr_add (r, r, r2);
198 mpcr_add_rounding_error (r, p, MPFR_RNDN);
199
200 if (!overlap)
201 mpcb_set_prec (z, p);
202 mpc_sqr (z->c, z1->c, MPC_RNDNN);
203 mpcr_set (z->r, r);
204 }
205
206 void
mpcb_pow_ui(mpcb_ptr z,mpcb_srcptr z1,unsigned long int e)207 mpcb_pow_ui (mpcb_ptr z, mpcb_srcptr z1, unsigned long int e)
208 {
209 mpcb_t pow;
210
211 if (e == 0)
212 mpcb_set_ui_ui (z, 1, 0, mpcb_get_prec (z1));
213 else if (e == 1)
214 mpcb_set (z, z1);
215 else {
216 /* Right to left powering is easier to implement, but requires an
217 additional variable even when there is no overlap. */
218 mpcb_init (pow);
219 mpcb_set (pow, z1);
220 /* Avoid setting z to 1 and multiplying by it, instead set it to the
221 smallest 2-power multiple of z1 that is occurring. */
222 while (e % 2 == 0) {
223 mpcb_sqr (pow, pow);
224 e /= 2;
225 }
226 mpcb_set (z, pow);
227 e /= 2;
228 while (e != 0) {
229 mpcb_sqr (pow, pow);
230 if (e % 2 == 1)
231 mpcb_mul (z, z, pow);
232 e /= 2;
233 }
234 mpcb_clear (pow);
235 }
236 }
237
238
239 void
mpcb_add(mpcb_ptr z,mpcb_srcptr z1,mpcb_srcptr z2)240 mpcb_add (mpcb_ptr z, mpcb_srcptr z1, mpcb_srcptr z2)
241 {
242 mpcr_t r, s, denom;
243 mpfr_prec_t p = MPC_MIN (mpcb_get_prec (z1), mpcb_get_prec (z2));
244 int overlap = (z == z1 || z == z2);
245 mpc_t zc;
246
247 if (overlap)
248 mpc_init2 (zc, p);
249 else {
250 zc [0] = z->c [0];
251 mpc_set_prec (zc, p);
252 }
253 mpc_add (zc, z1->c, z2->c, MPC_RNDZZ);
254 /* rounding towards 0 makes the generic error easier to compute,
255 but incurs a tiny penalty for the rounding error */
256
257 /* generic error of addition:
258 r <= (|z1|*r1 + |z2|*r2) / |z1+z2|
259 <= (|z1|*r1 + |z2|*r2) / |z| since we rounded towards 0 */
260 mpcr_c_abs_rnd (denom, zc, MPFR_RNDD);
261 mpcr_c_abs_rnd (r, z1->c, MPFR_RNDU);
262 mpcr_mul (r, r, z1->r);
263 mpcr_c_abs_rnd (s, z2->c, MPFR_RNDU);
264 mpcr_mul (s, s, z2->r);
265 mpcr_add (r, r, s);
266 mpcr_div (r, r, denom);
267 /* error of directed rounding */
268 mpcr_add_rounding_error (r, p, MPFR_RNDZ);
269
270 if (overlap)
271 mpc_clear (z->c);
272 z->c [0] = zc [0];
273 mpcr_set (z->r, r);
274 }
275
276
277 void
mpcb_sqrt(mpcb_ptr z,mpcb_srcptr z1)278 mpcb_sqrt (mpcb_ptr z, mpcb_srcptr z1)
279 /* The function "glides over" the branch cut on the negative real axis:
280 In fact it always returns a ball with centre the square root of the
281 centre of z1, and a reasonable radius even when the input ball has a
282 crosses the negative real axis. This is inconsistent in a sense: The
283 output ball does not contain all the possible outputs of a call to
284 mpc_sqrt on an element of the input ball. On the other hand, it does
285 contain square roots of all elements of the input ball. This comes
286 handy for the alternative implementation of mpc_agm using ball
287 arithmetic, but would also cause a potential implementation of
288 mpcb_agm to ignore the branch cut. */
289 {
290 mpcr_t r;
291 mpfr_prec_t p = mpcb_get_prec (z1);
292 int overlap = (z == z1);
293
294 /* Compute the error first in case there is overlap. */
295 /* generic error of square root for z1->r <= 0.5:
296 0.5*epsilon1 + (sqrt(2)-1) * epsilon1^2
297 <= 0.5 * epsilon1 * (1 + epsilon1),
298 see eq:propsqrt in algorithms.tex, together with a Taylor
299 expansion of 1/sqrt(1-epsilon1) */
300 if (!mpcr_lt_half_p (z1->r))
301 mpcr_set_inf (r);
302 else {
303 mpcr_set_one (r);
304 mpcr_add (r, r, z1->r);
305 mpcr_mul (r, r, z1->r);
306 mpcr_div_2ui (r, r, 1);
307 /* error of rounding to nearest */
308 mpcr_add_rounding_error (r, p, MPFR_RNDN);
309 }
310
311 if (!overlap)
312 mpcb_set_prec (z, p);
313 mpc_sqrt (z->c, z1->c, MPC_RNDNN);
314 mpcr_set (z->r, r);
315 }
316
317
318 void
mpcb_div(mpcb_ptr z,mpcb_srcptr z1,mpcb_srcptr z2)319 mpcb_div (mpcb_ptr z, mpcb_srcptr z1, mpcb_srcptr z2)
320 {
321 mpcr_t r, s;
322 mpfr_prec_t p = MPC_MIN (mpcb_get_prec (z1), mpcb_get_prec (z2));
323 int overlap = (z == z1 || z == z2);
324 mpc_t zc;
325
326 if (overlap)
327 mpc_init2 (zc, p);
328 else {
329 zc [0] = z->c [0];
330 mpc_set_prec (zc, p);
331 }
332 mpc_div (zc, z1->c, z2->c, MPC_RNDNN);
333 if (overlap)
334 mpc_clear (z->c);
335 z->c [0] = zc [0];
336
337 /* generic error of division */
338 mpcr_add (r, z1->r, z2->r);
339 mpcr_set_one (s);
340 mpcr_sub_rnd (s, s, z2->r, MPFR_RNDD);
341 mpcr_div (r, r, s);
342 /* error of rounding to nearest */
343 mpcr_add_rounding_error (r, p, MPFR_RNDN);
344 mpcr_set (z->r, r);
345 }
346
347
348 void
mpcb_div_2ui(mpcb_ptr z,mpcb_srcptr z1,unsigned long int e)349 mpcb_div_2ui (mpcb_ptr z, mpcb_srcptr z1, unsigned long int e)
350 {
351 mpc_div_2ui (z->c, z1->c, e, MPC_RNDNN);
352 mpcr_set (z->r, z1->r);
353 }
354
355
356 int
mpcb_can_round(mpcb_srcptr op,mpfr_prec_t prec_re,mpfr_prec_t prec_im,mpc_rnd_t rnd)357 mpcb_can_round (mpcb_srcptr op, mpfr_prec_t prec_re, mpfr_prec_t prec_im,
358 mpc_rnd_t rnd)
359 /* The function returns true if it can decide that rounding the centre
360 of op to an mpc_t variable of precision prec_re for the real and
361 prec_im for the imaginary part returns a correctly rounded result
362 of the ball in direction rnd for which the rounding direction value
363 can be determined. The second condition implies that if the centre
364 can be represented at the target precisions and the radius is small,
365 but non-zero, the function returns false although correct rounding
366 would be possible, while the rounding direction value could be
367 anything.
368 If the return value is true, then using mpcb_round with the same
369 rounding mode sets a correct result and returns a correct rounding
370 direction value with the usual MPC semantic. */
371 {
372 mpfr_srcptr re, im;
373 mpfr_exp_t exp_re, exp_im, exp_err;
374
375 if (mpcr_inf_p (op->r))
376 return 0;
377 else if (mpcr_zero_p (op->r))
378 return 1;
379
380 re = mpc_realref (op->c);
381 im = mpc_imagref (op->c);
382 /* If the real or the imaginary part of the centre is 0, directed
383 rounding is impossible, and rounding to nearest is only possible
384 if the absolute error is less than the smallest representable
385 number; since rounding only once at precision p introduces an error
386 of about 2^-p, this means that the precision needs to be about as
387 big as the negative of the minimal exponent, which is astronomically
388 large. In any case, even then we could not determine the rounding
389 direction value. */
390 if (mpfr_zero_p (re) || mpfr_zero_p (im))
391 return 0;
392
393 exp_re = mpfr_get_exp (re);
394 exp_im = mpfr_get_exp (im);
395
396 /* Absolute error of the real part, as given in the proof of
397 prop:comrelerror of algorithms.tex:
398 |x-x~| = |x~*theta_R - y~*theta_I|
399 <= (|x~|+|y~|) * epsilon,
400 where epsilon is the complex relative error
401 <= 2 * max (|x~|, |y~|) * epsilon
402 To call mpfr_can_round, we only need the exponent in base 2,
403 which is then bounded above by
404 1 + max (exp_re, exp_im) + exponent (epsilon) */
405 exp_err = 1 + MPC_MAX (exp_re, exp_im) + mpcr_get_exp (op->r);
406
407 /* To check whether the rounding direction value can be determined
408 when rounding to nearest, use the trick described in the
409 documentation of mpfr_can_round to check for directed rounding
410 at precision larger by 1. */
411 return ( mpfr_can_round (re, exp_re - exp_err, MPFR_RNDN,
412 MPFR_RNDZ, prec_re + (MPC_RND_RE (rnd) == MPFR_RNDN))
413 && mpfr_can_round (im, exp_im - exp_err, MPFR_RNDN,
414 MPFR_RNDZ, prec_im + (MPC_RND_IM (rnd) == MPFR_RNDN)));
415 }
416
417
418 int
mpcb_round(mpc_ptr rop,mpcb_srcptr op,mpc_rnd_t rnd)419 mpcb_round (mpc_ptr rop, mpcb_srcptr op, mpc_rnd_t rnd)
420 /* Set rop to the centre of op and return the corresponding rounding
421 direction value. To make sure that this corresponds to the MPC
422 semantics of returning a correctly rounded result and a correct
423 rounding direction value, one needs to call mpcb_can_round first. */
424 {
425 return mpc_set (rop, op->c, rnd);
426 }
427
428