1 /*
2 Copyright © 2014, 2017, 2018, 2019 Andreas Enge <andreas.enge@inria.fr>
3 Copyright © 2017 Fredrik Johansson <fredrik.johansson@gmail.com>
4
5 This file is part of paritwine.
6
7 Paritwine is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or (at
10 your option) any later version.
11
12 Paritwine is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Paritwine. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "paritwine.h"
22
23
24 /****************************************************************************/
25 /* */
26 /* Functions converting between pari and mpz */
27 /* */
28 /****************************************************************************/
29
mpz_set_GEN(mpz_ptr z,GEN x)30 void mpz_set_GEN (mpz_ptr z, GEN x)
31 /* Sets z to x, which needs to be of type t_INT. */
32
33 {
34 const long lx = lgefint (x) - 2;
35 const long sign = signe (x);
36 int i;
37
38 assert (sizeof (long) == sizeof (mp_limb_t));
39
40 if (typ (x) != t_INT)
41 pari_err_TYPE ("mpz_set_GEN", x);
42
43 if (sign == 0)
44 mpz_set_ui (z, 0);
45 else {
46 mpz_realloc2 (z, lx * BITS_IN_LONG);
47 z->_mp_size = sign * lx;
48 for (i = 0; i < lx; i++)
49 (z->_mp_d) [i] = *int_W (x, i);
50 }
51 }
52
53 /****************************************************************************/
54
mpz_get_GEN(mpz_srcptr z)55 GEN mpz_get_GEN (mpz_srcptr z)
56 /* Returns the GEN of type t_INT corresponding to z. */
57
58 {
59 const long lz = z->_mp_size;
60 const long lx = labs (lz);
61 const long lx2 = lx + 2;
62 int i;
63 GEN x = cgeti (lx2);
64
65 assert (sizeof (long) == sizeof (mp_limb_t));
66
67 x [1] = evalsigne ((lz > 0 ? 1 : (lz < 0 ? -1 : 0))) | evallgefint (lx2);
68 for (i = 0; i < lx; i++)
69 *int_W (x, i) = (z->_mp_d) [i];
70
71 return x;
72 }
73
74
75 /****************************************************************************/
76 /* */
77 /* Functions converting between pari and mpq */
78 /* */
79 /****************************************************************************/
80
mpq_set_GEN(mpq_ptr q,GEN x)81 void mpq_set_GEN (mpq_ptr q, GEN x)
82 /* Sets q to x, which needs to be of type t_FRAC or t_INT. */
83
84 {
85 if (typ (x) == t_FRAC) {
86 mpz_set_GEN (&(q->_mp_num), gel (x, 1));
87 mpz_set_GEN (&(q->_mp_den), gel (x, 2));
88 }
89 else if (typ (x) == t_INT) {
90 mpz_set_GEN (&(q->_mp_num), x);
91 mpz_set_GEN (&(q->_mp_den), gen_1);
92 }
93 else
94 pari_err_TYPE ("mpq_set_GEN", x);
95 }
96
97 /****************************************************************************/
98
mpq_get_GEN(mpq_srcptr q)99 GEN mpq_get_GEN (mpq_srcptr q)
100 /* Returns the GEN of type t_FRAC corresponding to q. */
101
102 {
103 GEN x = cgetg (3, t_FRAC);
104
105 gel (x, 1) = mpz_get_GEN (mpq_numref (q));
106 gel (x, 2) = mpz_get_GEN (mpq_denref (q));
107
108 return x;
109 }
110
111
112 /****************************************************************************/
113 /* */
114 /* Functions converting between pari and mpfr */
115 /* */
116 /****************************************************************************/
117
118 #ifdef HAVE_LIBMPFR
xmpn_mirrorcopy(mp_limb_t * z,mp_limb_t * x,long n)119 static void xmpn_mirrorcopy (mp_limb_t *z, mp_limb_t *x, long n)
120 /* Copied from kernel/gmp/mp.c; used to revert the mantissa between
121 mpfr and pari representations. */
122 {
123 long i;
124 for (i = 0; i < n; i++)
125 z [i]= x [n-1-i];
126 }
127
128 /****************************************************************************/
129
pari_mpfr_init2(mpfr_ptr f,mpfr_prec_t prec)130 void pari_mpfr_init2 (mpfr_ptr f, mpfr_prec_t prec)
131 /* Works in the same way as mpfr_init2, except that the space for the
132 mantissa is allocated on the pari stack. */
133 {
134 long l;
135 mp_limb_t * mant;
136
137 assert (sizeof (long) == sizeof (mp_limb_t));
138
139 l = nbits2nlong (mpfr_custom_get_size (prec) * 8);
140 mant = new_chunk (l);
141 mpfr_custom_init_set (f, MPFR_NAN_KIND, 0, prec, mant);
142 }
143
144 /****************************************************************************/
145
pari_mpfr_init_set_REAL(mpfr_ptr f,GEN x)146 static void pari_mpfr_init_set_REAL (mpfr_ptr f, GEN x)
147 /* Creates space for f on the pari stack and sets it to x, which is
148 assumed to be a t_REAL.
149 Unlike with the mpfr_init_set functions, the used precision is not the
150 mpfr default precision, but that of x (also if x is 0). */
151 {
152 assert (sizeof (long) == sizeof (mp_limb_t));
153
154 if (signe (x) == 0) {
155 long e = expo (x);
156 mp_prec_t prec = (e > -2 ? 2 : -e);
157 pari_mpfr_init2 (f, prec);
158 mpfr_set_zero (f, 1);
159 }
160 else {
161 long l = realprec (x) - 2;
162 mp_limb_t * rc = new_chunk (l);
163
164 xmpn_mirrorcopy (rc, x+2, l);
165 mpfr_custom_init_set (f, signe (x) * MPFR_REGULAR_KIND,
166 expo (x) + 1, bit_prec (x), rc);
167 }
168 }
169
170 /****************************************************************************/
171
mpfr_set_REAL(mpfr_ptr f,GEN x,mpfr_rnd_t rnd)172 static int mpfr_set_REAL (mpfr_ptr f, GEN x, mpfr_rnd_t rnd)
173 /* Sets f to x, which is assumed to be of type t_REAL. */
174
175 {
176 pari_sp av = avma;
177 int inex;
178 mpfr_t tmp;
179
180 /* Copy x without loss. TODO: Share mantissa of x once it need not
181 be reverted any more. */
182 pari_mpfr_init_set_REAL (tmp, x);
183 inex = mpfr_set (f, tmp, rnd);
184
185 avma = av;
186
187 return (inex);
188 }
189
190 /****************************************************************************/
191
mpfr_set_INT(mpfr_ptr f,GEN x,mpfr_rnd_t rnd)192 static int mpfr_set_INT (mpfr_ptr f, GEN x, mpfr_rnd_t rnd)
193 /* Sets f to x, which is assumed to be of type t_INT. */
194
195 {
196 int inex;
197 mpz_t tmp;
198
199 mpz_init (tmp);
200 mpz_set_GEN (tmp, x);
201 inex = mpfr_set_z (f, tmp, rnd);
202 mpz_clear (tmp);
203
204 return (inex);
205 }
206
207 /****************************************************************************/
208
pari_mpfr_init_set_INT(mpfr_ptr f,GEN x,mpfr_prec_t prec)209 static void pari_mpfr_init_set_INT (mpfr_ptr f, GEN x, mpfr_prec_t prec)
210 /* Creates space for f of mpfr precision prec on the pari stack and sets
211 it to x, which is assumed to be a t_INT. */
212 {
213 pari_mpfr_init2 (f, prec);
214 mpfr_set_INT (f, x, MPFR_RNDN);
215 }
216
217 /****************************************************************************/
218
mpfr_set_FRAC(mpfr_ptr f,GEN x,mpfr_rnd_t rnd)219 static int mpfr_set_FRAC (mpfr_ptr f, GEN x, mpfr_rnd_t rnd)
220 /* Sets f to x, which is assumed to be of type t_FRAC. */
221
222 {
223 int inex;
224 mpq_t tmp;
225
226 mpq_init (tmp);
227 mpq_set_GEN (tmp, x);
228 inex = mpfr_set_q (f, tmp, rnd);
229 mpq_clear (tmp);
230
231 return (inex);
232 }
233
234 /****************************************************************************/
235
pari_mpfr_init_set_FRAC(mpfr_ptr f,GEN x,mpfr_prec_t prec)236 static void pari_mpfr_init_set_FRAC (mpfr_ptr f, GEN x, mpfr_prec_t prec)
237 /* Creates space for f of mpfr precision prec on the pari stack and sets
238 it to x, which is assumed to be a t_FRAC. */
239 {
240 pari_mpfr_init2 (f, prec);
241 mpfr_set_FRAC (f, x, MPFR_RNDN);
242 }
243
244 /****************************************************************************/
245
mpfr_set_GEN(mpfr_ptr f,GEN x,mpfr_rnd_t rnd)246 int mpfr_set_GEN (mpfr_ptr f, GEN x, mpfr_rnd_t rnd)
247 /* Sets f to x. */
248
249 {
250 switch (typ (x)) {
251 case t_REAL:
252 return mpfr_set_REAL (f, x, rnd);
253 case t_INT:
254 return mpfr_set_INT (f, x, rnd);
255 case t_FRAC:
256 return mpfr_set_FRAC (f, x, rnd);
257 default:
258 pari_err_TYPE ("mpfr_set_GEN", x);
259 }
260 }
261
262 /****************************************************************************/
263
pari_mpfr_init_set_GEN(mpfr_ptr f,GEN x,mpfr_prec_t default_prec)264 void pari_mpfr_init_set_GEN (mpfr_ptr f, GEN x, mpfr_prec_t default_prec)
265 /* Creates space for f on the pari stack and sets it to x.
266 If x is of type t_REAL, its own precision is used, otherwise,
267 default_prec is used for f. */
268
269 {
270 switch (typ (x)) {
271 case t_REAL:
272 pari_mpfr_init_set_REAL (f, x);
273 return;
274 case t_INT:
275 pari_mpfr_init_set_INT (f, x, default_prec);
276 return;
277 case t_FRAC:
278 pari_mpfr_init_set_FRAC (f, x, default_prec);
279 return;
280 default:
281 pari_err_TYPE ("pari_mpfr_init_set_GEN", x);
282 }
283 }
284
285 /****************************************************************************/
286
mpfr_get_GEN(mpfr_srcptr f)287 GEN mpfr_get_GEN (mpfr_srcptr f)
288 /* returns f as a t_REAL with the minimal precision required to represent
289 it */
290 {
291 if (!mpfr_number_p (f))
292 pari_err_OVERFLOW ("mpfr_get_GEN");
293 else if (mpfr_zero_p (f))
294 return real_0_bit (-mpfr_get_prec (f));
295 else {
296 long l = nbits2nlong (mpfr_get_prec (f));
297 GEN r = cgetr (l + 2);
298 xmpn_mirrorcopy (r+2, mpfr_custom_get_significand (f), l);
299 setsigne (r, (mpfr_signbit (f) ? -1 : 1));
300 setexpo (r, mpfr_get_exp (f) - 1);
301 return r;
302 }
303 }
304 #endif
305
306
307 /****************************************************************************/
308 /* */
309 /* Functions converting between pari and mpc */
310 /* */
311 /****************************************************************************/
312
313 #ifdef HAVE_LIBMPC
pari_mpc_init2(mpc_ptr c,mpfr_prec_t prec)314 void pari_mpc_init2 (mpc_ptr c, mpfr_prec_t prec)
315 /* Works in the same way as mpc_init2, except that the space for the
316 mantissae is allocated on the pari stack. */
317 {
318 pari_mpfr_init2 (mpc_realref (c), prec);
319 pari_mpfr_init2 (mpc_imagref (c), prec);
320 }
321
322 /****************************************************************************/
323
pari_mpc_init3(mpc_ptr c,mpfr_prec_t prec_re,mpfr_prec_t prec_im)324 void pari_mpc_init3 (mpc_ptr c, mpfr_prec_t prec_re, mpfr_prec_t prec_im)
325 /* Works in the same way as mpc_init3, except that the space for the
326 mantissae is allocated on the pari stack. */
327 {
328 pari_mpfr_init2 (mpc_realref (c), prec_re);
329 pari_mpfr_init2 (mpc_imagref (c), prec_im);
330 }
331
332 /****************************************************************************/
333
mpc_set_GEN(mpc_ptr c,GEN x,mpc_rnd_t rnd)334 int mpc_set_GEN (mpc_ptr c, GEN x, mpc_rnd_t rnd)
335 /* Sets c to x. */
336
337 {
338 int inex_re, inex_im;
339
340 switch (typ (x)) {
341 case t_COMPLEX:
342 inex_re = mpfr_set_GEN (mpc_realref (c), greal (x),
343 MPC_RND_RE (rnd));
344 inex_im = mpfr_set_GEN (mpc_imagref (c), gimag (x),
345 MPC_RND_IM (rnd));
346 break;
347 case t_REAL:
348 case t_INT:
349 case t_FRAC:
350 inex_re = mpfr_set_GEN (mpc_realref (c), x, MPC_RND_RE (rnd));
351 inex_im = mpfr_set_GEN (mpc_imagref (c), gen_0, MPC_RND_IM (rnd));
352 break;
353 default:
354 pari_err_TYPE ("mpc_set_GEN", x);
355 }
356
357 return MPC_INEX (inex_re, inex_im);
358 }
359
360 /****************************************************************************/
361
pari_mpc_init_set_GEN(mpc_ptr c,GEN x,mpfr_prec_t default_prec)362 void pari_mpc_init_set_GEN (mpc_ptr c, GEN x, mpfr_prec_t default_prec)
363 /* Creates space for c on the pari stack and sets it to x.
364 Components of type t_REAL get their own precision, while others
365 are created with default_prec. */
366
367 {
368 switch (typ (x)) {
369 case t_COMPLEX:
370 pari_mpfr_init_set_GEN (mpc_realref (c), greal (x), default_prec);
371 pari_mpfr_init_set_GEN (mpc_imagref (c), gimag (x), default_prec);
372 return;
373 case t_REAL:
374 case t_INT:
375 case t_FRAC:
376 pari_mpfr_init_set_GEN (mpc_realref (c), greal (x), default_prec);
377 pari_mpfr_init_set_GEN (mpc_imagref (c), gen_0, default_prec);
378 return;
379 default:
380 pari_err_TYPE ("mpc_init_set_GEN", x);
381 }
382 }
383
384 /****************************************************************************/
385
mpc_get_GEN(mpc_srcptr c)386 GEN mpc_get_GEN (mpc_srcptr c)
387 /* returns c as a t_COMPLEX with the minimal precision required to
388 represent it */
389 {
390 GEN x = cgetg (3, t_COMPLEX);
391
392 gel (x, 1) = mpfr_get_GEN (mpc_realref (c));
393 gel (x, 2) = mpfr_get_GEN (mpc_imagref (c));
394
395 return x;
396 }
397 #endif
398
399
400 /****************************************************************************/
401 /* */
402 /* Functions converting between pari and flint */
403 /* */
404 /****************************************************************************/
405
406 #ifdef HAVE_LIBFLINT
407 GEN
fmpz_get_GEN(const fmpz_t x)408 fmpz_get_GEN(const fmpz_t x)
409 {
410 if (!COEFF_IS_MPZ(*x))
411 {
412 return stoi(*x);
413 }
414 else
415 {
416 GEN y;
417 slong ssize, size;
418 __mpz_struct * z;
419
420 z = COEFF_TO_PTR(*x);
421 ssize = z->_mp_size;
422 size = FLINT_ABS(ssize);
423
424 y = cgeti(size + 2);
425 y[1] = evalsigne(ssize < 0 ? -1 : 1) + evallgefint(size + 2);
426 flint_mpn_copyi(&y[2], z->_mp_d, size);
427
428 return y;
429 }
430 }
431
432 void
fmpz_set_GEN(fmpz_t y,const GEN x)433 fmpz_set_GEN(fmpz_t y, const GEN x)
434 {
435 if (typ(x) == t_INT)
436 {
437 slong size;
438
439 size = lgefint(x) - 2;
440
441 if (size == 0)
442 {
443 fmpz_zero(y);
444 }
445 else if (size == 1)
446 {
447 if (signe(x) < 0)
448 fmpz_neg_ui(y, x[2]);
449 else
450 fmpz_set_ui(y, x[2]);
451 }
452 else
453 {
454 __mpz_struct * z = _fmpz_promote(y);
455
456 if (z->_mp_alloc < size)
457 mpz_realloc2(z, size * FLINT_BITS);
458
459 flint_mpn_copyi(z->_mp_d, &x[2], size);
460 z->_mp_size = (signe(x) < 0) ? -size : size;
461 }
462 }
463 else
464 {
465 pari_err_TYPE ("fmpz_set_GEN", x);
466 }
467 }
468
469 GEN
fmpq_get_GEN(const fmpq_t x)470 fmpq_get_GEN(const fmpq_t x)
471 {
472 if (fmpz_is_one(fmpq_denref(x)))
473 {
474 return fmpz_get_GEN(fmpq_numref(x));
475 }
476 else
477 {
478 GEN y = cgetg(3, t_FRAC);
479
480 gel(y, 1) = fmpz_get_GEN(fmpq_numref(x));
481 gel(y, 2) = fmpz_get_GEN(fmpq_denref(x));
482 return y;
483 }
484 }
485
486 void
fmpq_set_GEN(fmpq_t y,const GEN x)487 fmpq_set_GEN(fmpq_t y, const GEN x)
488 {
489 if (typ(x) == t_INT)
490 {
491 fmpz_set_GEN(fmpq_numref(y), x);
492 fmpz_one(fmpq_denref(y));
493 }
494 else if (typ(x) == t_FRAC)
495 {
496 fmpz_set_GEN(fmpq_numref(y), gel(x, 1));
497 fmpz_set_GEN(fmpq_denref(y), gel(x, 2));
498 }
499 else
500 {
501 pari_err_TYPE ("fmpq_set_GEN", x);
502 }
503 }
504 #endif
505
506
507 /****************************************************************************/
508 /* */
509 /* Functions converting between pari and arb */
510 /* */
511 /****************************************************************************/
512
513 #ifdef HAVE_LIBARB
514 GEN
arf_get_GEN(const arf_t x,slong prec)515 arf_get_GEN(const arf_t x, slong prec)
516 {
517 if (!arf_is_finite(x))
518 {
519 pari_err_TYPE ("arf_get_GEN", gen_0); /* todo: throw the right error */
520 return gen_0;
521 /*
522 if (arf_is_pos_inf(x))
523 return mkoo();
524 else if (arf_is_neg_inf(x))
525 return mkmoo();
526 else
527 ...
528 */
529 }
530 else if (arf_is_zero(x))
531 {
532 return gen_0;
533 }
534 else
535 {
536 GEN y;
537 slong i;
538 mp_srcptr xp;
539 mp_size_t xn, yn;
540
541 ARF_GET_MPN_READONLY(xp, xn, x);
542
543 yn = (prec + FLINT_BITS - 1) / FLINT_BITS;
544
545 y = cgetr(yn + 2);
546 y[1] = evalsigne(ARF_SGNBIT(x) ? -1 : 1) | evalexpo(ARF_EXP(x) - 1);
547 for (i = 0; i < FLINT_MIN(xn, yn); i++)
548 y[2 + i] = xp[xn - 1 - i];
549 for (i = xn; i < yn; i++)
550 y[2 + i] = 0;
551
552 return y;
553 }
554 }
555
556 void
arf_set_GEN(arf_t y,const GEN x)557 arf_set_GEN(arf_t y, const GEN x)
558 {
559 if (typ(x) == t_INT)
560 {
561 slong size = lgefint(x) - 2;
562
563 if (size == 0)
564 arf_zero(y);
565 else
566 arf_set_mpn(y, x + 2, size, signe(x) < 0);
567 }
568 else if (typ(x) == t_REAL)
569 {
570 slong expo, sgn, xn, i;
571 mp_ptr yp;
572
573 xn = lg(x) - 2;
574 sgn = signe(x);
575 expo = expo(x);
576
577 while (xn > 0 && x[2 + xn - 1] == 0)
578 xn--;
579
580 if (xn == 0)
581 {
582 arf_zero(y);
583 }
584 else
585 {
586 ARF_GET_MPN_WRITE(yp, xn, y);
587
588 for (i = 0; i < xn; i++)
589 yp[xn - 1 - i] = x[2 + i];
590
591 if (sgn < 0)
592 ARF_NEG(y);
593
594 fmpz_set_si(ARF_EXPREF(y), expo + 1);
595 }
596 }
597 else
598 {
599 pari_err_TYPE ("arf_set_GEN", x);
600 }
601 }
602
603 GEN
mag_get_GEN(const mag_t x)604 mag_get_GEN(const mag_t x)
605 {
606 if (mag_is_zero(x))
607 {
608 return gen_0;
609 }
610 else if (mag_is_inf(x))
611 {
612 pari_err_TYPE ("mag_get_GEN", gen_0); /* todo: throw the right error */
613 return gen_0;
614 }
615 else
616 {
617 GEN y;
618 y = cgetr(3);
619 y[1] = evalsigne(1) | evalexpo(MAG_EXP(x) - 1);
620 y[2] = MAG_MAN(x) << (FLINT_BITS - MAG_BITS);
621 return y;
622 }
623 }
624
mag_set_GEN(mag_t y,const GEN x)625 void mag_set_GEN(mag_t y, const GEN x)
626 {
627 arf_t t;
628 arf_init(t);
629 arf_set_GEN(t, x);
630 arf_get_mag(y, t);
631 arf_clear(t);
632 }
633
634 void
arb_set_GEN(arb_t y,const GEN x,slong prec)635 arb_set_GEN(arb_t y, const GEN x, slong prec)
636 {
637 if (typ(x) == t_FRAC)
638 {
639 fmpq_t t;
640 fmpq_init(t);
641 fmpq_set_GEN(t, x);
642 arb_set_fmpq(y, t, prec);
643 fmpq_clear(t);
644 }
645 else if (typ(x) == t_VEC)
646 {
647 if (lg(x) != 3)
648 {
649 pari_err_TYPE ("arb_set_GEN", gen_0); /* todo: throw the right error */
650 }
651 else
652 {
653 arf_set_GEN(arb_midref(y), gel(x, 1));
654 mag_set_GEN(arb_radref(y), gel(x, 2));
655 }
656 }
657 else
658 {
659 arf_set_GEN(arb_midref(y), x);
660 mag_zero(arb_radref(y));
661 arb_set_round(y, y, prec);
662 }
663 }
664
665 GEN
arb_get_GEN(const arb_t x,slong prec)666 arb_get_GEN(const arb_t x, slong prec)
667 {
668 GEN y = cgetg(3, t_VEC);
669 gel(y, 1) = arf_get_GEN(arb_midref(x), prec);
670 gel(y, 2) = mag_get_GEN(arb_radref(x));
671 return y;
672 }
673
674 void
acb_set_GEN(acb_t y,const GEN x,slong prec)675 acb_set_GEN(acb_t y, const GEN x, slong prec)
676 {
677 if (typ(x) == t_COMPLEX)
678 {
679 arb_set_GEN(acb_realref(y), gel(x, 1), prec);
680 arb_set_GEN(acb_imagref(y), gel(x, 2), prec);
681 }
682 else if (typ(x) == t_VEC)
683 {
684 if (lg(x) != 3)
685 {
686 pari_err_TYPE ("acb_set_GEN", gen_0); /* todo: throw the right error */
687 }
688 else
689 {
690 /* Create two variables of type t_VEC for the real and imaginary
691 parts of x, and call arb_set_GEN on them. */
692 pari_sp av = avma;
693 GEN re, im;
694 re = cgetg (3, t_VEC);
695 gel (re, 1) = greal (gel (x, 1));
696 gel (re, 2) = greal (gel (x, 2));
697 im = cgetg (3, t_VEC);
698 gel (im, 1) = gimag (gel (x, 1));
699 gel (im, 2) = gimag (gel (x, 2));
700
701 arb_set_GEN (acb_realref (y), re, prec);
702 arb_set_GEN (acb_imagref (y), im, prec);
703
704 avma = av;
705 }
706 }
707 else
708 {
709 arb_zero(acb_imagref(y));
710 arb_set_GEN(acb_realref(y), x, prec);
711 }
712 }
713
714 GEN
acb_get_GEN(const acb_t x,slong prec)715 acb_get_GEN(const acb_t x, slong prec)
716 {
717 GEN z, m, r;
718
719 z = cgetg(3, t_VEC);
720 gel(z, 1) = m = cgetg(3, t_COMPLEX);
721 gel(z, 2) = r = cgetg(3, t_COMPLEX);
722
723 gel(m, 1) = arf_get_GEN(arb_midref(acb_realref(x)), prec);
724 gel(m, 2) = arf_get_GEN(arb_midref(acb_imagref(x)), prec);
725 gel(r, 1) = mag_get_GEN(arb_radref(acb_realref(x)));
726 gel(r, 2) = mag_get_GEN(arb_radref(acb_imagref(x)));
727
728 return z;
729 }
730 #endif
731
732