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