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