1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * gmpy2_convert_mpc.c                                                     *
3  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
4  * Python interface to the GMP or MPIR, MPFR, and MPC multiple precision   *
5  * libraries.                                                              *
6  *                                                                         *
7  * Copyright 2000 - 2009 Alex Martelli                                     *
8  *                                                                         *
9  * Copyright 2008 - 2021 Case Van Horsen                                   *
10  *                                                                         *
11  * This file is part of GMPY2.                                             *
12  *                                                                         *
13  * GMPY2 is free software: you can redistribute it and/or modify it under  *
14  * the terms of the GNU Lesser General Public License as published by the  *
15  * Free Software Foundation, either version 3 of the License, or (at your  *
16  * option) any later version.                                              *
17  *                                                                         *
18  * GMPY2 is distributed in the hope that it will be useful, but WITHOUT    *
19  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or   *
20  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public    *
21  * License for more details.                                               *
22  *                                                                         *
23  * You should have received a copy of the GNU Lesser General Public        *
24  * License along with GMPY2; if not, see <http://www.gnu.org/licenses/>    *
25  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
26 
27 /* Please see the documentation for GMPy_MPFR_From_MPFR for detailed
28  * description of this function.
29  */
30 
31 
32 static MPC_Object *
GMPy_MPC_From_MPC(MPC_Object * obj,mpfr_prec_t rprec,mpfr_prec_t iprec,CTXT_Object * context)33 GMPy_MPC_From_MPC(MPC_Object *obj, mpfr_prec_t rprec, mpfr_prec_t iprec,
34                   CTXT_Object *context)
35 {
36     MPC_Object *result = NULL;
37 
38     /* Optimize the critical case when prec==1 or obj is NaN or Inf. */
39 
40     if ((rprec == 1 && iprec == 1) ||
41         (!mpfr_number_p(mpc_realref(obj->c)) &&
42         !mpfr_number_p(mpc_imagref(obj->c)))) {
43         Py_INCREF((PyObject*)obj);
44         return obj;
45     }
46 
47     CHECK_CONTEXT(context);
48 
49     if (rprec == 0)
50         rprec = GET_REAL_PREC(context);
51     else if (rprec == 1)
52         rprec = mpfr_get_prec(mpc_realref(obj->c));
53 
54     if (iprec == 0)
55         iprec = GET_IMAG_PREC(context);
56     else if (iprec == 1)
57         iprec = mpfr_get_prec(mpc_imagref(obj->c));
58 
59     /* Try to identify when an additional reference to existing instance can
60      * be returned. It is possible when (1) the precision matches, (2) the
61      * exponent is valid and not in the range that might require subnormal-
62      * ization, and (3) subnormalize is not enabled.
63      */
64 
65     if ((rprec == mpfr_get_prec(mpc_realref(obj->c))) &&
66         (iprec == mpfr_get_prec(mpc_imagref(obj->c))) &&
67         (!context->ctx.subnormalize) &&
68         (mpc_realref(obj->c)->_mpfr_exp >= (context->ctx.emin + mpfr_get_prec(mpc_realref(obj->c)) - 1)) &&
69         (mpc_realref(obj->c)->_mpfr_exp <= context->ctx.emax) &&
70         (mpc_imagref(obj->c)->_mpfr_exp >= (context->ctx.emin + mpfr_get_prec(mpc_imagref(obj->c)) - 1)) &&
71         (mpc_imagref(obj->c)->_mpfr_exp <= context->ctx.emax)
72         ) {
73 
74         Py_INCREF((PyObject*)obj);
75         return obj;
76     }
77 
78     if ((result = GMPy_MPC_New(rprec, iprec, context))) {
79         result->rc = mpc_set(result->c, obj->c, GET_MPC_ROUND(context));
80         _GMPy_MPC_Cleanup(&result, context);
81     }
82     return result;
83 }
84 
85 static MPC_Object *
GMPy_MPC_From_PyComplex(PyObject * obj,mpfr_prec_t rprec,mpfr_prec_t iprec,CTXT_Object * context)86 GMPy_MPC_From_PyComplex(PyObject *obj, mpfr_prec_t rprec, mpfr_prec_t iprec,
87                         CTXT_Object *context)
88 {
89     MPC_Object *result;
90 
91     CHECK_CONTEXT(context);
92 
93     if (rprec == 0)
94         rprec = GET_REAL_PREC(context);
95     else if (rprec == 1)
96         rprec = DBL_MANT_DIG;
97 
98     if (iprec == 0)
99         iprec = GET_IMAG_PREC(context);
100     else if (iprec == 1)
101         rprec = DBL_MANT_DIG;
102 
103     if ((result = GMPy_MPC_New(rprec, iprec, context))) {
104         result->rc = mpc_set_d_d(result->c, PyComplex_RealAsDouble(obj),
105                                  PyComplex_ImagAsDouble(obj), GET_MPC_ROUND(context));
106         if (rprec != 1 || iprec != 1) {
107             GMPY_MPC_CHECK_RANGE(result, context);
108         }
109         GMPY_MPC_SUBNORMALIZE(result, context);
110         GMPY_MPC_EXCEPTIONS(result, context);
111     }
112     return result;
113 }
114 
115 static MPC_Object *
GMPy_MPC_From_MPFR(MPFR_Object * obj,mpfr_prec_t rprec,mpfr_prec_t iprec,CTXT_Object * context)116 GMPy_MPC_From_MPFR(MPFR_Object *obj, mpfr_prec_t rprec, mpfr_prec_t iprec,
117                    CTXT_Object *context)
118 {
119     MPC_Object *result;
120 
121     CHECK_CONTEXT(context);
122 
123     if (rprec == 0)
124         rprec = GET_REAL_PREC(context);
125     else if (rprec == 1)
126         rprec = mpfr_get_prec(obj->f);
127 
128     if (iprec == 0)
129         iprec = GET_IMAG_PREC(context);
130     else if (iprec == 1)
131         rprec = mpfr_get_prec(obj->f);
132 
133     if ((result = GMPy_MPC_New(rprec, iprec, context))) {
134         result->rc = mpc_set_fr(result->c, obj->f, GET_MPC_ROUND(context));
135         if (rprec != 1) {
136             GMPY_MPC_CHECK_RANGE(result, context);
137         }
138         GMPY_MPC_SUBNORMALIZE(result, context);
139         GMPY_MPC_EXCEPTIONS(result, context);
140     }
141     return result;
142 }
143 
144 static MPC_Object *
GMPy_MPC_From_PyFloat(PyObject * obj,mpfr_prec_t rprec,mpfr_prec_t iprec,CTXT_Object * context)145 GMPy_MPC_From_PyFloat(PyObject *obj, mpfr_prec_t rprec, mpfr_prec_t iprec,
146                    CTXT_Object *context)
147 {
148     MPC_Object *result;
149 
150     CHECK_CONTEXT(context);
151 
152     if (rprec == 0)
153         rprec = GET_REAL_PREC(context);
154     else if (rprec == 1)
155         rprec = DBL_MANT_DIG;
156 
157     if (iprec == 0)
158         iprec = GET_IMAG_PREC(context);
159     else if (iprec == 1)
160         rprec = DBL_MANT_DIG;
161 
162     if ((result = GMPy_MPC_New(rprec, iprec, context))) {
163         result->rc = mpc_set_d(result->c, PyFloat_AS_DOUBLE(obj),
164                                GET_MPC_ROUND(context));
165         if (rprec != 1) {
166             GMPY_MPC_CHECK_RANGE(result, context);
167         }
168         GMPY_MPC_SUBNORMALIZE(result, context);
169         GMPY_MPC_EXCEPTIONS(result, context);
170     }
171     return result;
172 }
173 
174 static MPC_Object *
GMPy_MPC_From_MPZ(MPZ_Object * obj,mpfr_prec_t rprec,mpfr_prec_t iprec,CTXT_Object * context)175 GMPy_MPC_From_MPZ(MPZ_Object *obj, mpfr_prec_t rprec, mpfr_prec_t iprec,
176                   CTXT_Object *context)
177 {
178     MPC_Object *result = NULL;
179 
180     CHECK_CONTEXT(context);
181 
182     if (rprec < 2) {
183         rprec = GET_REAL_PREC(context);
184     }
185 
186     if (iprec < 2) {
187         iprec = GET_IMAG_PREC(context);
188     }
189 
190     if ((result = GMPy_MPC_New(rprec, iprec, context))) {
191         result->rc = mpc_set_z(result->c, obj->z, GET_MPC_ROUND(context));
192         if (rprec != 1) {
193             GMPY_MPC_CHECK_RANGE(result, context);
194         }
195         GMPY_MPC_SUBNORMALIZE(result, context);
196         GMPY_MPC_EXCEPTIONS(result, context);
197     }
198     return result;
199 }
200 
201 static MPC_Object *
GMPy_MPC_From_MPQ(MPQ_Object * obj,mpfr_prec_t rprec,mpfr_prec_t iprec,CTXT_Object * context)202 GMPy_MPC_From_MPQ(MPQ_Object *obj, mpfr_prec_t rprec, mpfr_prec_t iprec,
203                   CTXT_Object *context)
204 {
205     MPC_Object *result = NULL;
206 
207     CHECK_CONTEXT(context);
208 
209     if (rprec < 2) {
210         rprec = GET_REAL_PREC(context);
211     }
212 
213     if (iprec < 2) {
214         iprec = GET_IMAG_PREC(context);
215     }
216 
217     if ((result = GMPy_MPC_New(rprec, iprec, context))) {
218         result->rc = mpc_set_q(result->c, obj->q, GET_MPC_ROUND(context));
219         if (rprec != 1) {
220             GMPY_MPC_CHECK_RANGE(result, context);
221         }
222         GMPY_MPC_SUBNORMALIZE(result, context);
223         GMPY_MPC_EXCEPTIONS(result, context);
224     }
225     return result;
226 }
227 
228 static MPC_Object *
GMPy_MPC_From_Fraction(PyObject * obj,mpfr_prec_t rprec,mpfr_prec_t iprec,CTXT_Object * context)229 GMPy_MPC_From_Fraction(PyObject *obj, mpfr_prec_t rprec, mpfr_prec_t iprec,
230                        CTXT_Object *context)
231 {
232     MPC_Object *result = NULL;
233     MPQ_Object *tempq;
234 
235     CHECK_CONTEXT(context);
236 
237     if ((tempq = GMPy_MPQ_From_Fraction(obj, context))) {
238         result = GMPy_MPC_From_MPQ(tempq, rprec, iprec, context);
239         Py_DECREF((PyObject*)tempq);
240     }
241     return result;
242 }
243 
244 static MPC_Object *
GMPy_MPC_From_PyIntOrLong(PyObject * obj,mpfr_prec_t rprec,mpfr_prec_t iprec,CTXT_Object * context)245 GMPy_MPC_From_PyIntOrLong(PyObject *obj, mpfr_prec_t rprec, mpfr_prec_t iprec,
246                           CTXT_Object *context)
247 {
248     MPC_Object *result = NULL;
249     MPZ_Object *tempz;
250 
251     CHECK_CONTEXT(context);
252 
253     if ((tempz = GMPy_MPZ_From_PyIntOrLong(obj, context))) {
254         result = GMPy_MPC_From_MPZ(tempz, rprec, iprec, context);
255         Py_DECREF((PyObject*)tempz);
256     }
257 
258     return result;
259 }
260 
261 /* Python's string representation of a complex number differs from the format
262  * used by MPC. Both MPC and Python surround the complex number with '(' and
263  * ')' but Python adds a 'j' after the imaginary component and MPC requires a
264  * space between the real and imaginery components. GMPy_MPC_From_PyStr tries
265  * to work around the differences as by reading two MPFR-compatible numbers
266  * from the string and storing into the real and imaginary components
267  * respectively.
268  */
269 
270 static MPC_Object *
GMPy_MPC_From_PyStr(PyObject * s,int base,mpfr_prec_t rprec,mpfr_prec_t iprec,CTXT_Object * context)271 GMPy_MPC_From_PyStr(PyObject *s, int base, mpfr_prec_t rprec, mpfr_prec_t iprec,
272                     CTXT_Object *context)
273 {
274     MPC_Object *result;
275     Py_ssize_t len;
276     char *cp, *unwind, *tempchar, *lastchar;
277     int firstp = 0, lastp = 0, real_rc = 0, imag_rc = 0;
278     PyObject *ascii_str = ascii_str = GMPy_RemoveUnderscoreASCII(s);
279 
280     if (!ascii_str) return NULL;
281 
282     len = PyBytes_Size(ascii_str);
283     cp = (char*)PyBytes_AsString(ascii_str);
284 
285     CHECK_CONTEXT(context);
286 
287     if (!(result = GMPy_MPC_New(rprec, iprec, context))) {
288         Py_XDECREF(ascii_str);
289         return NULL;
290     }
291 
292     /* Get a pointer to the last valid character (ignoring trailing
293      * whitespace.) */
294     lastchar = cp + len - 1;
295     while (isspace(*lastchar))
296         lastchar--;
297 
298     /* Skip trailing ). */
299     if (*lastchar == ')') {
300         lastp = 1;
301         lastchar--;
302     }
303 
304     /* Skip trailing j. */
305     if (*lastchar == 'j')
306         lastchar--;
307 
308     /* Skip leading whitespace. */
309     while (isspace(*cp))
310         cp++;
311 
312     /* Skip a leading (. */
313     if (*cp == '(') {
314         firstp = 1;
315         cp++;
316     }
317 
318     if (firstp != lastp) goto invalid_string;
319 
320     /* Read the real component first. */
321     unwind = cp;
322     real_rc = mpfr_strtofr(mpc_realref(result->c), cp, &tempchar, base,
323                            GET_REAL_ROUND(context));
324 
325     /* Verify that at least one valid character was read. */
326     if (cp == tempchar) goto invalid_string;
327 
328     /* If the next character is a j, then the real component is 0 and
329      * we just read the imaginary componenet.
330      */
331     if (*tempchar == 'j') {
332         mpfr_set_zero(mpc_realref(result->c), MPFR_RNDN);
333         cp = unwind;
334     }
335     else {
336         /* Read the imaginary component next. */
337         cp = tempchar;
338     }
339 
340     imag_rc = mpfr_strtofr(mpc_imagref(result->c), cp, &tempchar, base,
341                            GET_IMAG_ROUND(context));
342 
343     if (cp == tempchar && tempchar > lastchar)
344         goto valid_string;
345 
346     if (*tempchar != 'j' && *cp != ' ')
347         goto invalid_string;
348 
349     if (tempchar <= lastchar)
350         goto invalid_string;
351 
352   valid_string:
353     Py_XDECREF(ascii_str);
354     result->rc = MPC_INEX(real_rc, imag_rc);
355 
356     if (rprec != 1 || iprec != 1) {
357         GMPY_MPC_CHECK_RANGE(result, context);
358     }
359     GMPY_MPC_SUBNORMALIZE(result, context);
360     GMPY_MPC_EXCEPTIONS(result, context);
361 
362     return result;
363 
364   invalid_string:
365     VALUE_ERROR("invalid string in mpc()");
366     Py_DECREF((PyObject*)result);
367     Py_XDECREF(ascii_str);
368     return NULL;
369 }
370 
371 /* See the comments for GMPy_MPFR_From_Real_Temp. */
372 
373 static MPC_Object *
GMPy_MPC_From_ComplexWithType(PyObject * obj,int xtype,mp_prec_t rprec,mp_prec_t iprec,CTXT_Object * context)374 GMPy_MPC_From_ComplexWithType(PyObject* obj, int xtype, mp_prec_t rprec,
375                               mp_prec_t iprec, CTXT_Object *context)
376 {
377     CHECK_CONTEXT(context);
378 
379     if (IS_TYPE_MPC(xtype))
380         return GMPy_MPC_From_MPC((MPC_Object*)obj, rprec, iprec, context);
381 
382     if (IS_TYPE_MPFR(xtype))
383         return GMPy_MPC_From_MPFR((MPFR_Object*)obj, rprec, iprec, context);
384 
385     if (IS_TYPE_PyFloat(xtype))
386         return GMPy_MPC_From_PyFloat(obj, rprec, iprec, context);
387 
388     if (IS_TYPE_PyComplex(xtype))
389         return GMPy_MPC_From_PyComplex(obj, rprec, iprec, context);
390 
391     if (IS_TYPE_MPQ(xtype))
392         return GMPy_MPC_From_MPQ((MPQ_Object*)obj, rprec, iprec, context);
393 
394     if (IS_TYPE_MPZANY(xtype))
395         return GMPy_MPC_From_MPZ((MPZ_Object*)obj, rprec, iprec, context);
396 
397     if (IS_TYPE_PyInteger(xtype))
398         return GMPy_MPC_From_PyIntOrLong(obj, rprec, iprec, context);
399 
400     if (IS_TYPE_PyFraction(xtype))
401         return GMPy_MPC_From_Fraction(obj, rprec, iprec, context);
402 
403     if (IS_TYPE_HAS_MPC(xtype)) {
404         MPC_Object * res = (MPC_Object *) PyObject_CallMethod(obj, "__mpc__", NULL);
405 
406         if (res != NULL && MPC_Check(res)) {
407             return res;
408         }
409         else {
410             Py_XDECREF((PyObject*)res);
411             goto error;
412         }
413     }
414 
415     if (IS_TYPE_HAS_MPFR(xtype)) {
416         MPFR_Object * res = (MPFR_Object *) PyObject_CallMethod(obj, "__mpfr__", NULL);
417 
418         if (res != NULL && MPFR_Check(res)) {
419             MPC_Object * temp = GMPy_MPC_From_MPFR(res, rprec, iprec, context);
420             Py_DECREF(res);
421             return temp;
422         }
423         else {
424             Py_XDECREF((PyObject*)res);
425             goto error;
426         }
427     }
428 
429     if (IS_TYPE_HAS_MPQ(xtype)) {
430         MPQ_Object * res = (MPQ_Object *) PyObject_CallMethod(obj, "__mpq__", NULL);
431 
432         if (res != NULL && MPQ_Check(res)) {
433             MPC_Object * temp = GMPy_MPC_From_MPQ(res, rprec, iprec, context);
434             Py_DECREF(res);
435             return temp;
436         }
437         else {
438             Py_XDECREF((PyObject*)res);
439             goto error;
440         }
441     }
442 
443     if (IS_TYPE_HAS_MPZ(xtype)) {
444         MPZ_Object * res = (MPZ_Object *) PyObject_CallMethod(obj, "__mpz__", NULL);
445 
446         if (res != NULL && MPZ_Check(res)) {
447             MPC_Object * temp = GMPy_MPC_From_MPZ(res, rprec, iprec, context);
448             Py_DECREF(res);
449             return temp;
450         }
451         else {
452             Py_XDECREF((PyObject*)res);
453             goto error;
454         }
455     }
456 
457   error:
458     TYPE_ERROR("object could not be converted to 'mpc'");
459     return NULL;
460 }
461 
462 static MPC_Object *
GMPy_MPC_From_Complex(PyObject * obj,mp_prec_t rprec,mp_prec_t iprec,CTXT_Object * context)463 GMPy_MPC_From_Complex(PyObject* obj, mp_prec_t rprec, mp_prec_t iprec,
464                            CTXT_Object *context)
465 {
466     return GMPy_MPC_From_ComplexWithType(obj, GMPy_ObjectType(obj),
467                                          rprec, iprec, context);
468 }
469 
470 static MPC_Object *
GMPy_MPC_From_ComplexWithTypeAndCopy(PyObject * obj,int xtype,mp_prec_t rprec,mp_prec_t iprec,CTXT_Object * context)471 GMPy_MPC_From_ComplexWithTypeAndCopy(PyObject* obj, int xtype, mp_prec_t rprec,
472                                      mp_prec_t iprec, CTXT_Object *context)
473 {
474     MPC_Object *result = NULL, *temp = NULL;
475 
476     result = GMPy_MPC_From_ComplexWithType(obj, xtype, rprec, iprec, context);
477 
478     if (result == NULL)
479         return result;
480 
481     if (Py_REFCNT(result) == 1)
482         return result;
483 
484     if (!(temp = GMPy_MPC_New(rprec = mpfr_get_prec(mpc_realref(result->c)),
485                               iprec = mpfr_get_prec(mpc_imagref(result->c)),
486                               context))) {
487         /* LCOV_EXCL_START */
488         Py_DECREF(result);
489         return NULL;
490         /* LCOV_EXCL_STOP */
491     }
492 
493     /* Since the precision of temp is the same as the precision of result,
494      * there shouldn't be any rounding.
495      */
496 
497     mpc_set(temp->c, result->c, MPFR_RNDN);
498     Py_DECREF((PyObject*)result);
499     return temp;
500 }
501 
502 static PyObject *
GMPy_PyStr_From_MPC(MPC_Object * self,int base,int digits,CTXT_Object * context)503 GMPy_PyStr_From_MPC(MPC_Object *self, int base, int digits, CTXT_Object *context)
504 {
505     PyObject *tempreal = 0, *tempimag = 0, *result;
506 
507     CHECK_CONTEXT(context);
508 
509     if (!((base >= 2) && (base <= 62))) {
510         VALUE_ERROR("base must be in the interval [2,62]");
511         return NULL;
512     }
513     if ((digits < 0) || (digits == 1)) {
514         VALUE_ERROR("digits must be 0 or >= 2");
515         return NULL;
516     }
517 
518     tempreal = mpfr_ascii(mpc_realref(self->c), base, digits,
519                           MPC_RND_RE(GET_MPC_ROUND(context)));
520     tempimag = mpfr_ascii(mpc_imagref(self->c), base, digits,
521                           MPC_RND_IM(GET_MPC_ROUND(context)));
522 
523     if (!tempreal || !tempimag) {
524         Py_XDECREF(tempreal);
525         Py_XDECREF(tempimag);
526         return NULL;
527     }
528 
529     result = Py_BuildValue("(NN)", tempreal, tempimag);
530     if (!result) {
531         Py_DECREF(tempreal);
532         Py_DECREF(tempimag);
533     }
534     return result;
535 }
536 
537 static PyObject *
GMPy_MPC_Float_Slot(PyObject * self)538 GMPy_MPC_Float_Slot(PyObject *self)
539 {
540     TYPE_ERROR("can't covert 'mpc' to 'float'");
541     return NULL;
542 }
543 
544 PyDoc_STRVAR(GMPy_doc_mpc_complex, "Convert 'mpc' to 'complex'.");
545 
546 static PyObject *
GMPy_PyComplex_From_MPC(PyObject * self,PyObject * other)547 GMPy_PyComplex_From_MPC(PyObject *self, PyObject *other)
548 {
549     CTXT_Object *context = NULL;
550     double real, imag;
551 
552     CHECK_CONTEXT(context);
553 
554     real = mpfr_get_d(mpc_realref(MPC(self)), GET_REAL_ROUND(context));
555     imag = mpfr_get_d(mpc_imagref(MPC(self)), GET_IMAG_ROUND(context));
556 
557     return PyComplex_FromDoubles(real, imag);
558 }
559 
560 #ifdef PY2
561 static PyObject *
GMPy_MPC_Long_Slot(PyObject * self)562 GMPy_MPC_Long_Slot(PyObject *self)
563 {
564     TYPE_ERROR("can't covert mpc to long");
565     return NULL;
566 }
567 #endif
568 
569 static PyObject *
GMPy_MPC_Int_Slot(PyObject * self)570 GMPy_MPC_Int_Slot(PyObject *self)
571 {
572     TYPE_ERROR("can't covert mpc to int");
573     return NULL;
574 }
575 
576 #ifdef SHARED
577 /*
578  * coerce any number to a mpc
579  */
580 
581 int
GMPy_MPC_ConvertArg(PyObject * arg,PyObject ** ptr)582 GMPy_MPC_ConvertArg(PyObject *arg, PyObject **ptr)
583 {
584     MPC_Object *newob = GMPy_MPC_From_Complex(arg, 0, 0, NULL);
585 
586     if (newob) {
587         *ptr = (PyObject*)newob;
588         return 1;
589     }
590     else {
591         TYPE_ERROR("can't convert argument to 'mpc'");
592         return 0;
593     }
594 }
595 #endif
596 
597 /* str and repr implementations for mpc */
598 static PyObject *
GMPy_MPC_Str_Slot(MPC_Object * self)599 GMPy_MPC_Str_Slot(MPC_Object *self)
600 {
601     PyObject *result, *temp;
602     mpfr_prec_t rbits, ibits;
603     long rprec, iprec;
604     char fmtstr[60];
605 
606     mpc_get_prec2(&rbits, &ibits, MPC(self));
607     rprec = (long)(log10(2) * (double)rbits) + 2;
608     iprec = (long)(log10(2) * (double)ibits) + 2;
609 
610     sprintf(fmtstr, "{0:.%ld.%ldg}", rprec, iprec);
611 
612     temp = Py_BuildValue("s", fmtstr);
613     if (!temp)
614         return NULL;
615     result = PyObject_CallMethod(temp, "format", "O", self);
616     Py_DECREF(temp);
617     return result;
618 }
619 
620 static PyObject *
GMPy_MPC_Repr_Slot(MPC_Object * self)621 GMPy_MPC_Repr_Slot(MPC_Object *self)
622 {
623     PyObject *result, *temp;
624     mpfr_prec_t rbits, ibits;
625     long rprec, iprec;
626     char fmtstr[60];
627 
628     mpc_get_prec2(&rbits, &ibits, MPC(self));
629     rprec = (long)(log10(2) * (double)rbits) + 2;
630     iprec = (long)(log10(2) * (double)ibits) + 2;
631 
632     if (rbits != DBL_MANT_DIG || ibits !=DBL_MANT_DIG)
633         sprintf(fmtstr, "mpc('{0:.%ld.%ldg}',(%ld,%ld))",
634                 rprec, iprec, rbits, ibits);
635     else
636         sprintf(fmtstr, "mpc('{0:.%ld.%ldg}')", rprec, iprec);
637 
638     temp = Py_BuildValue("s", fmtstr);
639     if (!temp)
640         return NULL;
641     result = PyObject_CallMethod(temp, "format", "O", self);
642     Py_DECREF(temp);
643     return result;
644 }
645 
646 
647 
648