/ src / gmpy2_mpfr_misc.c
gmpy2_mpfr_misc.c
  1  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2   * gmpy2_mpfr_misc.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  PyDoc_STRVAR(GMPy_doc_function_f2q,
 28  "f2q(x,[err]) -> mpq\n\n"
 29  "Return the 'best' mpq approximating x to within relative error 'err'.\n"
 30  "Default is the precision of x. Uses Stern-Brocot tree to find the\n"
 31  "'best' approximation. An 'mpz' is returned if the the denominator\n"
 32  "is 1. If 'err'<0, relative error is 2.0 ** err.");
 33  
 34  static PyObject *
 35  GMPy_Real_F2Q(PyObject *x, PyObject *y, CTXT_Object *context)
 36  {
 37      MPFR_Object *tempx, *tempy = NULL;
 38      PyObject *result;
 39  
 40      CHECK_CONTEXT(context);
 41  
 42      if (y) {
 43          if (!(tempy = GMPy_MPFR_From_Real(y, 1, context))) {
 44              /* LCOV_EXCL_START */
 45              return NULL;
 46              /* LCOV_EXCL_STOP */
 47          }
 48      }
 49  
 50      if (!(tempx = GMPy_MPFR_From_Real(x, 1, context))) {
 51          /* LCOV_EXCL_START */
 52          Py_XDECREF((PyObject*)tempy);
 53          return NULL;
 54          /* LCOV_EXCL_STOP */
 55      }
 56  
 57      /* See gmpy2_convert_mpfr for stern_brocot(). */
 58  
 59      result = stern_brocot(tempx, tempy, 0, 1, context);
 60      Py_DECREF((PyObject*)tempx);
 61      Py_XDECREF((PyObject*)tempy);
 62      return result;
 63  }
 64  
 65  static PyObject *
 66  GMPy_Number_F2Q(PyObject *x, PyObject *y, CTXT_Object *context)
 67  {
 68      if (IS_REAL(x) && (!y || IS_REAL(y)))
 69          return GMPy_Real_F2Q(x, y, context);
 70  
 71      TYPE_ERROR("f2q() argument types not supported");
 72      return NULL;
 73  }
 74  
 75  static PyObject *
 76  GMPy_Context_F2Q(PyObject *self, PyObject *args)
 77  {
 78      CTXT_Object *context = NULL;
 79  
 80      if (PyTuple_GET_SIZE(args) < 1 || PyTuple_GET_SIZE(args) > 2) {
 81          TYPE_ERROR("f2q() requires 1 or 2 arguments");
 82          return NULL;
 83      }
 84  
 85      if (self && CTXT_Check(self)) {
 86          /* LCOV_EXCL_START */
 87          context = (CTXT_Object*)self;
 88          /* LCOV_EXCL_STOP */
 89      }
 90      else {
 91          CHECK_CONTEXT(context);
 92      }
 93  
 94      if (PyTuple_GET_SIZE(args) == 1) {
 95          return GMPy_Number_F2Q(PyTuple_GET_ITEM(args, 0), NULL, context);
 96      }
 97      else {
 98          return GMPy_Number_F2Q(PyTuple_GET_ITEM(args, 0), PyTuple_GET_ITEM(args, 1), context);
 99      }
100  }
101  
102  PyDoc_STRVAR(GMPy_doc_mpfr_free_cache,
103  "free_cache()\n\n"
104  "Free the internal cache of constants maintained by MPFR.");
105  
106  static PyObject *
107  GMPy_MPFR_Free_Cache(PyObject *self, PyObject *args)
108  {
109      mpfr_free_cache();
110      Py_RETURN_NONE;
111  }
112  
113  PyDoc_STRVAR(GMPy_doc_mpfr_can_round,
114  "can_round(b, err, rnd1, rnd2, prec)\n\n"
115  "Let b be an approximation to an unknown number x that is rounded\n"
116  "according to rnd1. Assume the b has an error at most two to the power\n"
117  "of E(b)-err where E(b) is the exponent of b. Then return true if x\n"
118  "can be rounded correctly to prec bits with rounding mode rnd2.");
119  
120  static PyObject *
121  GMPy_MPFR_Can_Round(PyObject *self, PyObject *args)
122  {
123      int rnd1, rnd2;
124      long err, prec;
125      PyObject *b;
126  
127      if (!PyArg_ParseTuple(args, "O!liil", &MPFR_Type, &b, &err, &rnd1, &rnd2, &prec)) {
128          return NULL;
129      }
130  
131      if (!(rnd1 == MPFR_RNDN || rnd1 == MPFR_RNDZ ||
132            rnd1 == MPFR_RNDU || rnd1 == MPFR_RNDD ||
133            rnd1 == MPFR_RNDA)) {
134          VALUE_ERROR("invalid value for rounding mode");
135          return NULL;
136      }
137  
138      if (!(rnd2 == MPFR_RNDN || rnd2 == MPFR_RNDZ ||
139            rnd2 == MPFR_RNDU || rnd2 == MPFR_RNDD ||
140            rnd2 == MPFR_RNDA)) {
141          VALUE_ERROR("invalid value for rounding mode");
142          return NULL;
143      }
144  
145      if (prec < MPFR_PREC_MIN || prec > MPFR_PREC_MAX) {
146          VALUE_ERROR("invalid value for precision");
147          return NULL;
148      }
149  
150      if (mpfr_can_round(MPFR(b), err, rnd1, rnd2, prec))
151          Py_RETURN_TRUE;
152      else
153          Py_RETURN_FALSE;
154  }
155  
156  PyDoc_STRVAR(GMPy_doc_mpfr_get_emin_min,
157  "get_emin_min() -> integer\n\n"
158  "Return the minimum possible exponent that can be set for 'mpfr'.");
159  
160  static PyObject *
161  GMPy_MPFR_get_emin_min(PyObject *self, PyObject *args)
162  {
163      return PyIntOrLong_FromSsize_t((Py_ssize_t)mpfr_get_emin_min());
164  }
165  
166  PyDoc_STRVAR(GMPy_doc_mpfr_get_emax_max,
167  "get_emax_max() -> integer\n\n"
168  "Return the maximum possible exponent that can be set for 'mpfr'.");
169  
170  static PyObject *
171  GMPy_MPFR_get_emax_max(PyObject *self, PyObject *args)
172  {
173      return PyIntOrLong_FromSsize_t((Py_ssize_t)mpfr_get_emax_max());
174  }
175  
176  PyDoc_STRVAR(GMPy_doc_mpfr_get_max_precision,
177  "get_max_precision() -> integer\n\n"
178  "Return the maximum bits of precision that can be used for calculations.\n"
179  "Note: to allow extra precision for intermediate calculations, avoid\n"
180  "setting precision close the maximum precision.");
181  
182  static PyObject *
183  GMPy_MPFR_get_max_precision(PyObject *self, PyObject *args)
184  {
185      return PyIntOrLong_FromSsize_t((Py_ssize_t)MPFR_PREC_MAX);
186  }
187  
188  PyDoc_STRVAR(GMPy_doc_mpfr_get_exp,
189  "get_exp(mpfr) -> integer\n\n"
190  "Return the exponent of an mpfr. Returns 0 for NaN or Infinity and\n"
191  "sets the erange flag and will raise an exception if trap_erange\n"
192  "is set.");
193  
194  static PyObject *
195  GMPy_MPFR_get_exp(PyObject *self, PyObject *other)
196  {
197      PyObject *result = NULL;
198      Py_ssize_t exp;
199      CTXT_Object *context = NULL;
200  
201      CHECK_CONTEXT(context);
202  
203      if (!(MPFR_Check(other))) {
204          TYPE_ERROR("get_exp() requires 'mpfr' argument");
205          return NULL;
206      }
207  
208      if (mpfr_regular_p(MPFR(other))) {
209          exp = (Py_ssize_t)mpfr_get_exp(MPFR(other));
210          result = PyIntOrLong_FromSsize_t(exp);
211      }
212      else if (mpfr_zero_p(MPFR(other))) {
213          result = PyIntOrLong_FromSsize_t(0);
214      }
215      else {
216          context->ctx.erange = 1;
217          if (context->ctx.traps & TRAP_ERANGE) {
218              GMPY_ERANGE("Can not get exponent from NaN or Infinity.");
219          }
220          else {
221              result = PyIntOrLong_FromSsize_t(0);
222          }
223      }
224      return result;
225  }
226  
227  PyDoc_STRVAR(GMPy_doc_mpfr_set_exp,
228  "set_exp(mpfr, n) -> mpfr\n\n"
229  "Set the exponent of an mpfr to n. If n is outside the range of\n"
230  "valid exponents, set_exp() will set the erange flag and either\n"
231  "return the original value or raise an exception if trap_erange\n"
232  "is set.");
233  
234  static PyObject *
235  GMPy_MPFR_set_exp(PyObject *self, PyObject *args)
236  {
237      MPFR_Object *result;
238      PyObject *temp;
239      mpfr_exp_t _oldemin, _oldemax, exp;
240      CTXT_Object *context = NULL;
241  
242      CHECK_CONTEXT(context);
243  
244      if (PyTuple_GET_SIZE(args) != 2 ||
245          !MPFR_Check(PyTuple_GET_ITEM(args, 0)) ||
246          !PyIntOrLong_Check(PyTuple_GET_ITEM(args, 1))) {
247          TYPE_ERROR("set_exp() requires 'mpfr', 'integer' arguments");
248          return NULL;
249      }
250  
251      temp = PyTuple_GET_ITEM(args, 0);
252      exp = (mpfr_exp_t)PyIntOrLong_AsLong(PyTuple_GET_ITEM(args, 1));
253      if (exp == -1 && PyErr_Occurred()) {
254          VALUE_ERROR("exponent too large");
255          return NULL;
256      }
257  
258      if (!(result = GMPy_MPFR_New(mpfr_get_prec(MPFR(temp)), context))) {
259          return NULL;
260      }
261  
262      _oldemin = mpfr_get_emin();
263      _oldemax = mpfr_get_emax();
264      mpfr_set_emin(context->ctx.emin);
265      mpfr_set_emax(context->ctx.emax);
266  
267      mpfr_set(MPFR(result), MPFR(temp), GET_MPFR_ROUND(context));
268      result->rc = mpfr_set_exp(MPFR(result), exp);
269  
270      mpfr_set_emin(_oldemin);
271      mpfr_set_emax(_oldemax);
272  
273      if (result->rc) {
274          context->ctx.erange = 1;
275          if (context->ctx.traps & TRAP_ERANGE) {
276              GMPY_ERANGE("new exponent is out-of-bounds");
277              Py_DECREF((PyObject*)result);
278              return NULL;
279          }
280      }
281  
282      return (PyObject*)result;
283  }
284  
285  PyDoc_STRVAR(GMPy_doc_mpfr_set_sign,
286  "set_sign(mpfr, bool) -> mpfr\n\n"
287  "If 'bool' is True, then return an 'mpfr' with the sign bit set.");
288  
289  static PyObject *
290  GMPy_MPFR_set_sign(PyObject *self, PyObject *args)
291  {
292      MPFR_Object *result;
293      CTXT_Object *context = NULL;
294  
295      CHECK_CONTEXT(context);
296  
297      if (PyTuple_GET_SIZE(args) != 2 ||
298          !MPFR_Check(PyTuple_GET_ITEM(args, 0)) ||
299          !PyIntOrLong_Check(PyTuple_GET_ITEM(args, 1))) {
300          TYPE_ERROR("set_sign() requires 'mpfr', 'boolean' arguments");
301          return NULL;
302      }
303  
304      if (!(result = GMPy_MPFR_New(0, context))) {
305          return NULL;
306      }
307  
308      result->rc = mpfr_setsign(MPFR(result), MPFR(PyTuple_GET_ITEM(args, 0)),
309                                PyObject_IsTrue(PyTuple_GET_ITEM(args, 1)),
310                                GET_MPFR_ROUND(context));
311  
312      return (PyObject*)result;
313  }
314  
315  PyDoc_STRVAR(GMPy_doc_mpfr_copy_sign,
316  "copy_sign(mpfr, mpfr) -> mpfr\n\n"
317  "Return an 'mpfr' composed of the first argument with the sign of the\n"
318  "second argument.");
319  
320  static PyObject *
321  GMPy_MPFR_copy_sign(PyObject *self, PyObject *args)
322  {
323      MPFR_Object *result;
324      CTXT_Object *context = NULL;
325  
326      CHECK_CONTEXT(context);
327  
328      if (PyTuple_GET_SIZE(args) != 2 ||
329          !MPFR_Check(PyTuple_GET_ITEM(args, 0)) ||
330          !MPFR_Check(PyTuple_GET_ITEM(args, 1))) {
331          TYPE_ERROR("copy_sign() requires 'mpfr', 'mpfr' arguments");
332          return NULL;
333      }
334  
335      if (!(result = GMPy_MPFR_New(0, context))) {
336          return NULL;
337      }
338  
339      result->rc = mpfr_copysign(MPFR(result), MPFR(PyTuple_GET_ITEM(args, 0)),
340                                 MPFR(PyTuple_GET_ITEM(args, 1)),
341                                 GET_MPFR_ROUND(context));
342  
343      return (PyObject*)result;
344  }
345  
346  PyDoc_STRVAR(GMPy_doc_mpfr_set_nan,
347  "nan() -> mpfr\n\n"
348  "Return an 'mpfr' initialized to NaN (Not-A-Number).");
349  
350  static PyObject *
351  GMPy_MPFR_set_nan(PyObject *self, PyObject *other)
352  {
353      MPFR_Object *result;
354      CTXT_Object *context = NULL;
355  
356      CHECK_CONTEXT(context);
357  
358      if ((result = GMPy_MPFR_New(0, context))) {
359          mpfr_set_nan(result->f);
360      }
361      return (PyObject*)result;
362  }
363  
364  PyDoc_STRVAR(GMPy_doc_mpfr_set_inf,
365  "inf(n) -> mpfr\n\n"
366  "Return an 'mpfr' initialized to Infinity with the same sign as n.\n"
367  "If n is not given, +Infinity is returned.");
368  
369  static PyObject *
370  GMPy_MPFR_set_inf(PyObject *self, PyObject *args)
371  {
372      MPFR_Object *result;
373      long s = 1;
374      CTXT_Object *context = NULL;
375  
376      CHECK_CONTEXT(context);
377  
378      if (PyTuple_Size(args) == 1) {
379          s = c_long_From_Integer(PyTuple_GET_ITEM(args, 0));
380          if (s == -1 && PyErr_Occurred()) {
381              return NULL;
382          }
383      }
384  
385      if ((result = GMPy_MPFR_New(0, context))) {
386          mpfr_set_inf(result->f, s < 0 ? -1 : 1);
387      }
388      return (PyObject*)result;
389  }
390  
391  PyDoc_STRVAR(GMPy_doc_mpfr_set_zero,
392  "zero(n) -> mpfr\n\n"
393  "Return an 'mpfr' inialized to 0.0 with the same sign as n.\n"
394  "If n is not given, +0.0 is returned.");
395  
396  static PyObject *
397  GMPy_MPFR_set_zero(PyObject *self, PyObject *args)
398  {
399      MPFR_Object *result;
400      long s = 1;
401      CTXT_Object *context = NULL;
402  
403      CHECK_CONTEXT(context);
404  
405      if (PyTuple_Size(args) == 1) {
406          s = c_long_From_Integer(PyTuple_GET_ITEM(args, 0));
407          if (s == -1 && PyErr_Occurred()) {
408              return NULL;
409          }
410      }
411  
412      if ((result = GMPy_MPFR_New(0, context))) {
413          mpfr_set_zero(result->f, s < 0 ? -1 : 1);
414      }
415      return (PyObject*)result;
416  }
417  
418  PyDoc_STRVAR(GMPy_doc_method_integer_ratio,
419  "x.as_integer_ratio() -> (num, den)\n\n"
420  "Return the exact rational equivalent of an mpfr. Value is a tuple\n"
421  "for compatibility with Python's float.as_integer_ratio().");
422  
423  /* Note: almost identical code exists in gmpy2_convert_mpfr.c as the
424   * function GMPy_MPQ_From_MPFR. They should be refactored.
425   */
426  
427  static PyObject *
428  GMPy_MPFR_Integer_Ratio_Method(PyObject *self, PyObject *args)
429  {
430      MPZ_Object *num, *den;
431      mpfr_exp_t temp, twocount;
432      PyObject *result;
433      CTXT_Object *context = NULL;
434  
435      CHECK_CONTEXT(context);
436  
437      if (mpfr_nan_p(MPFR(self))) {
438          VALUE_ERROR("Cannot pass NaN to mpfr.as_integer_ratio.");
439          return NULL;
440      }
441  
442      if (mpfr_inf_p(MPFR(self))) {
443          OVERFLOW_ERROR("Cannot pass Infinity to mpfr.as_integer_ratio.");
444          return NULL;
445      }
446  
447      num = GMPy_MPZ_New(context);
448      den = GMPy_MPZ_New(context);
449      if (!num || !den) {
450          Py_XDECREF((PyObject*)num);
451          Py_XDECREF((PyObject*)den);
452          return NULL;
453      }
454  
455      if (mpfr_zero_p(MPFR(self))) {
456          mpz_set_ui(num->z, 0);
457          mpz_set_ui(den->z, 1);
458      }
459      else {
460          temp = mpfr_get_z_2exp(num->z, MPFR(self));
461          twocount = (mpfr_exp_t)mpz_scan1(num->z, 0);
462          if (twocount) {
463              temp += twocount;
464              mpz_div_2exp(num->z, num->z, twocount);
465          }
466          mpz_set_ui(den->z, 1);
467          if (temp > 0)
468              mpz_mul_2exp(num->z, num->z, temp);
469          else if (temp < 0)
470              mpz_mul_2exp(den->z, den->z, -temp);
471      }
472      result = Py_BuildValue("(NN)", (PyObject*)num, (PyObject*)den);
473      if (!result) {
474          Py_DECREF((PyObject*)num);
475          Py_DECREF((PyObject*)den);
476      }
477      return result;
478  }
479  
480  PyDoc_STRVAR(GMPy_doc_method_mantissa_exp,
481  "x.as_mantissa_exp() -> (mantissa,exponent)\n\n"
482  "Return the mantissa and exponent of an mpfr.");
483  
484  static PyObject *
485  GMPy_MPFR_Mantissa_Exp_Method(PyObject *self, PyObject *args)
486  {
487      MPZ_Object *mantissa , *exponent;
488      mpfr_exp_t temp;
489      PyObject *result;
490      CTXT_Object *context = NULL;
491  
492      CHECK_CONTEXT(context);
493  
494      if (mpfr_nan_p(MPFR(self))) {
495          VALUE_ERROR("Cannot pass NaN to mpfr.as_mantissa_exp.");
496          return NULL;
497      }
498  
499      if (mpfr_inf_p(MPFR(self))) {
500          OVERFLOW_ERROR("Cannot pass Infinity to mpfr.as_mantissa_exp.");
501          return NULL;
502      }
503  
504      mantissa = GMPy_MPZ_New(context);
505      exponent = GMPy_MPZ_New(context);
506      if (!mantissa || !exponent) {
507          Py_XDECREF((PyObject*)mantissa);
508          Py_XDECREF((PyObject*)exponent);
509          return NULL;
510      }
511  
512      if (mpfr_zero_p(MPFR(self))) {
513          mpz_set_ui(mantissa->z, 0);
514          mpz_set_ui(exponent->z, 1);
515      }
516      else {
517          temp = mpfr_get_z_2exp(mantissa->z, MPFR(self));
518          mpz_set_si(exponent->z, temp);
519      }
520      result = Py_BuildValue("(NN)", (PyObject*)mantissa, (PyObject*)exponent);
521      if (!result) {
522          Py_DECREF((PyObject*)mantissa);
523          Py_DECREF((PyObject*)exponent);
524      }
525      return result;
526  }
527  
528  PyDoc_STRVAR(GMPy_doc_method_simple_fraction,
529  "x.as_simple_fraction([precision=0]) -> mpq\n\n"
530  "Return a simple rational approximation to x. The result will be\n"
531  "accurate to 'precision' bits. If 'precision' is 0, the precision\n"
532  "of 'x' will be used.");
533  
534  static PyObject *
535  GMPy_MPFR_Simple_Fraction_Method(PyObject *self, PyObject *args, PyObject *keywds)
536  {
537      mpfr_prec_t prec = 0;
538      static char *kwlist[] = {"precision", NULL};
539      CTXT_Object *context = NULL;
540  
541      if (!PyArg_ParseTupleAndKeywords(args, keywds, "|l", kwlist, &prec)) {
542          return NULL;
543      }
544  
545      return (PyObject*)stern_brocot((MPFR_Object*)self, 0, prec, 0, context);
546  }
547  
548  /* Implement the .precision attribute of an mpfr. */
549  
550  static PyObject *
551  GMPy_MPFR_GetPrec_Attrib(MPFR_Object *self, void *closure)
552  {
553      return PyIntOrLong_FromSsize_t((Py_ssize_t)mpfr_get_prec(self->f));
554  }
555  
556  /* Implement the .rc attribute of an mpfr. */
557  
558  static PyObject *
559  GMPy_MPFR_GetRc_Attrib(MPFR_Object *self, void *closure)
560  {
561      return PyIntOrLong_FromLong((long)self->rc);
562  }
563  
564  /* Implement the .imag attribute of an mpfr. */
565  
566  static PyObject *
567  GMPy_MPFR_GetImag_Attrib(MPFR_Object *self, void *closure)
568  {
569      MPFR_Object *result;
570      CTXT_Object *context = NULL;
571  
572      CHECK_CONTEXT(context);
573  
574      if ((result = GMPy_MPFR_New(0, context)))
575          mpfr_set_zero(result->f, 1);
576      return (PyObject*)result;
577  }
578  
579  /* Implement the .real attribute of an mpfr. */
580  
581  static PyObject *
582  GMPy_MPFR_GetReal_Attrib(MPFR_Object *self, void *closure)
583  {
584      Py_INCREF((PyObject*)self);
585      return (PyObject*)self;
586  }
587  
588  /* Implement the nb_bool slot. */
589  
590  static int
591  GMPy_MPFR_NonZero_Slot(MPFR_Object *self)
592  {
593      return !mpfr_zero_p(self->f);
594  }
595  
596  PyDoc_STRVAR(GMPy_doc_function_check_range,
597  "check_range(x) -> mpfr\n\n"
598  "Return a new 'mpfr' with exponent that lies within the current range\n"
599  "of emin and emax.");
600  
601  PyDoc_STRVAR(GMPy_doc_context_check_range,
602  "context.check_range(x) -> mpfr\n\n"
603  "Return a new 'mpfr' with exponent that lies within the range of emin\n"
604  "and emax specified by context.");
605  
606  static PyObject *
607  GMPy_MPFR_CheckRange(PyObject *x, CTXT_Object *context)
608  {
609      MPFR_Object *result;
610  
611      CHECK_CONTEXT(context);
612  
613      if ((result = GMPy_MPFR_New(mpfr_get_prec(MPFR(x)), context))) {
614          mpfr_set(result->f, MPFR(x), GET_MPFR_ROUND(context));
615          mpfr_clear_flags();
616          _GMPy_MPFR_Cleanup(&result, context);
617      }
618      return (PyObject*)result;
619  }
620  
621  static PyObject *
622  GMPy_Number_CheckRange(PyObject *x, CTXT_Object *context)
623  {
624      if (MPFR_Check(x))
625          return GMPy_MPFR_CheckRange(x, context);
626  
627      TYPE_ERROR("check_range() argument types not supported");
628      return NULL;
629  }
630  
631  static PyObject *
632  GMPy_Context_CheckRange(PyObject *self, PyObject *other)
633  {
634      CTXT_Object *context = NULL;
635  
636      if (self && CTXT_Check(self)) {
637          context = (CTXT_Object*)self;
638      }
639      else {
640          CHECK_CONTEXT(context);
641      }
642  
643      return GMPy_Number_CheckRange(other, context);
644  }
645  
646  PyDoc_STRVAR(GMPy_doc_mpfr_sizeof_method,
647  "x.__sizeof__()\n\n"
648  "Returns the amount of memory consumed by x.");
649  
650  static PyObject *
651  GMPy_MPFR_SizeOf_Method(PyObject *self, PyObject *other)
652  {
653      return PyIntOrLong_FromSize_t(sizeof(MPFR_Object) + \
654          (((MPFR(self))->_mpfr_prec + mp_bits_per_limb - 1) / \
655          mp_bits_per_limb) * sizeof(mp_limb_t));
656  }
657  
658  PyDoc_STRVAR(GMPy_doc_method_round10,
659  "__round__(x[, n = 0]) -> mpfr\n\n"
660  "Return x rounded to n decimal digits before (n < 0) or after (n > 0)\n"
661  "the decimal point. Rounds to an integer if n is not specified.");
662  
663  static PyObject *
664  GMPy_MPFR_Method_Round10(PyObject *self, PyObject *args)
665  {
666      long digits = 0;
667      mpz_t temp;
668      MPFR_Object *resultf = 0;
669      MPZ_Object *resultz;
670      CTXT_Object *context = NULL;
671  
672      CHECK_CONTEXT(context);
673  
674      /* If the size of args is 0, we just return an mpz. */
675  
676      if (PyTuple_GET_SIZE(args) == 0) {
677          if ((resultz = GMPy_MPZ_New(context))) {
678              if (mpfr_nan_p(MPFR(self))) {
679                  Py_DECREF((PyObject*)resultz);
680                  VALUE_ERROR("'mpz' does not support NaN");
681                  return NULL;
682              }
683              if (mpfr_inf_p(MPFR(self))) {
684                  Py_DECREF((PyObject*)resultz);
685                  OVERFLOW_ERROR("'mpz' does not support Infinity");
686                  return NULL;
687              }
688              /* return code is ignored */
689              mpfr_get_z(resultz->z, MPFR(self), MPFR_RNDN);
690          }
691          return (PyObject*)resultz;
692      }
693  
694      /* Now we need to return an mpfr, so handle the simple cases. */
695  
696      if (!mpfr_regular_p(MPFR(self))) {
697          Py_INCREF(self);
698          return self;
699      }
700  
701      if (PyTuple_GET_SIZE(args) > 1) {
702          TYPE_ERROR("__round__() requires 0 or 1 argument");
703          return NULL;
704      }
705  
706      if (PyTuple_GET_SIZE(args) == 1) {
707          digits = PyIntOrLong_AsLong(PyTuple_GET_ITEM(args, 0));
708          if (digits == -1 && PyErr_Occurred()) {
709              TYPE_ERROR("__round__() requires 'int' argument");
710              return NULL;
711          }
712      }
713  
714      /* TODO: better error analysis, or else convert the mpfr to an exact
715       * fraction, round the fraction, and then convert back to an mpfr.
716       */
717  
718      if (!(resultf = GMPy_MPFR_New(mpfr_get_prec(MPFR(self))+100, context))) {
719          return NULL;
720      }
721  
722      mpz_init(temp);
723      mpz_ui_pow_ui(temp, 10, digits > 0 ? digits : -digits);
724      if (digits >= 0) {
725          mpfr_mul_z(resultf->f, MPFR(self), temp, MPFR_RNDN);
726      }
727      else {
728          mpfr_div_z(resultf->f, MPFR(self), temp, MPFR_RNDN);
729      }
730  
731      mpfr_rint(resultf->f, resultf->f, MPFR_RNDN);
732  
733      if (digits >= 0) {
734          mpfr_div_z(resultf->f, resultf->f, temp, MPFR_RNDN);
735      }
736      else {
737          mpfr_mul_z(resultf->f, resultf->f, temp, MPFR_RNDN);
738      }
739      mpfr_prec_round(resultf->f, mpfr_get_prec(MPFR(self)), MPFR_RNDN);
740  
741      mpz_clear(temp);
742      return((PyObject*)resultf);
743  }
744