/src/gmpy_context.c
C | 1210 lines | 1056 code | 105 blank | 49 comment | 192 complexity | b6d49f7521d13f2626efc8d864dc6753 MD5 | raw file
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 * gmpy_context.c * 3 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 4 * Python interface to the GMP or MPIR, MPFR, and MPC multiple precision * 5 * libraries. * 6 * * 7 * Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * 8 * 2008, 2009 Alex Martelli * 9 * * 10 * Copyright 2008, 2009, 2010, 2011, 2012, 2013 Case Van Horsen * 11 * * 12 * This file is part of GMPY2. * 13 * * 14 * GMPY2 is free software: you can redistribute it and/or modify it under * 15 * the terms of the GNU Lesser General Public License as published by the * 16 * Free Software Foundation, either version 3 of the License, or (at your * 17 * option) any later version. * 18 * * 19 * GMPY2 is distributed in the hope that it will be useful, but WITHOUT * 20 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * 21 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * 22 * License for more details. * 23 * * 24 * You should have received a copy of the GNU Lesser General Public * 25 * License along with GMPY2; if not, see <http://www.gnu.org/licenses/> * 26 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 27 28/* A GMPyContextObject contains an instance of the C struct gmpy_context 29 * and a PyObject* used to reference the enclosing instance when used as a 30 * context manager in Python. 31 * 32 * gmpy2 uses a global pointer "context" to refer to the active 33 * GMPyContextObject. 34 * 35 * WARNING: The context manager is not thread-safe. This may be fixed in a 36 * future version. 37 */ 38 39/* Create and delete Context objects. */ 40 41static PyObject * 42GMPyContext_new(void) 43{ 44 GMPyContextObject *result; 45 46 if ((result = PyObject_New(GMPyContextObject, &GMPyContext_Type))) { 47 result->ctx.mpfr_prec = DBL_MANT_DIG; 48 result->ctx.mpfr_round = MPFR_RNDN; 49 result->ctx.emax = MPFR_EMAX_DEFAULT; 50 result->ctx.emin = MPFR_EMIN_DEFAULT; 51 result->ctx.subnormalize = 0; 52 result->ctx.underflow = 0; 53 result->ctx.overflow = 0; 54 result->ctx.inexact = 0; 55 result->ctx.invalid = 0; 56 result->ctx.erange = 0; 57 result->ctx.divzero = 0; 58 result->ctx.trap_underflow = 0; 59 result->ctx.trap_overflow = 0; 60 result->ctx.trap_inexact = 0; 61 result->ctx.trap_invalid = 0; 62 result->ctx.trap_erange = 0; 63 result->ctx.trap_divzero = 0; 64 result->ctx.trap_expbound = 0; 65 66#ifdef WITHMPC 67 result->ctx.real_prec = -1; 68 result->ctx.imag_prec = -1; 69 result->ctx.real_round = -1; 70 result->ctx.imag_round = -1; 71 result->ctx.allow_complex = 0; 72#endif 73 } 74 return (PyObject*)result; 75}; 76 77static void 78GMPyContext_dealloc(GMPyContextObject *self) 79{ 80 PyObject_Del(self); 81}; 82 83PyDoc_STRVAR(doc_context_ieee, 84"ieee(bitwidth) -> context\n\n" 85"Return a new context corresponding to a standard IEEE floating point\n" 86"format. The currently supported precisions are 32, 64, and 128 bits."); 87 88static PyObject * 89GMPyContext_ieee(PyObject *self, PyObject *other) 90{ 91 long bitwidth; 92 GMPyContextObject *result; 93 94 bitwidth = PyIntOrLong_AsLong(other); 95 if (bitwidth == -1 && PyErr_Occurred()) { 96 TYPE_ERROR("ieee() requires 'int' argument"); 97 return NULL; 98 } 99 100 if (bitwidth == 32) { 101 result = (GMPyContextObject*)GMPyContext_new(); 102 if (result) { 103 result->ctx.subnormalize = 1; 104 result->ctx.mpfr_prec = 24; 105 result->ctx.emax = 128; 106 result->ctx.emin = -148; 107 } 108 return (PyObject*)result; 109 } 110 else if (bitwidth == 64) { 111 result = (GMPyContextObject*)GMPyContext_new(); 112 if (result) { 113 result->ctx.subnormalize = 1; 114 result->ctx.mpfr_prec = 53; 115 result->ctx.emax = 1024; 116 result->ctx.emin = -1073; 117 } 118 return (PyObject*)result; 119 } 120 else if (bitwidth == 128) { 121 result = (GMPyContextObject*)GMPyContext_new(); 122 if (result) { 123 result->ctx.subnormalize = 1; 124 result->ctx.mpfr_prec = 113; 125 result->ctx.emax = 16384; 126 result->ctx.emin = -16493; 127 } 128 return (PyObject*)result; 129 } 130 else { 131 VALUE_ERROR("bitwidth must be 32, 64, or 128"); 132 return NULL; 133 } 134} 135 136/* Create and delete ContextManager objects. */ 137 138static PyObject * 139GMPyContextManager_new(void) 140{ 141 return (PyObject*)PyObject_New(GMPyContextManagerObject, 142 &GMPyContextManager_Type); 143}; 144 145static void 146GMPyContextManager_dealloc(GMPyContextManagerObject *self) 147{ 148 PyObject_Del(self); 149}; 150 151/* Helper function to convert to convert a rounding mode to a string. */ 152 153static PyObject * 154_round_to_name(int val) 155{ 156 if (val == MPFR_RNDN) return Py2or3String_FromString("RoundToNearest"); 157 if (val == MPFR_RNDZ) return Py2or3String_FromString("RoundToZero"); 158 if (val == MPFR_RNDU) return Py2or3String_FromString("RoundUp"); 159 if (val == MPFR_RNDD) return Py2or3String_FromString("RoundDown"); 160 if (val == MPFR_RNDA) return Py2or3String_FromString("RoundAwayZero"); 161 if (val == GMPY_DEFAULT) return Py2or3String_FromString("Default"); 162 return NULL; 163}; 164 165static PyObject * 166GMPyContext_repr(GMPyContextObject *self) 167{ 168 PyObject *format; 169 PyObject *tuple; 170 PyObject *result = NULL; 171 int i = 0; 172 173#ifdef WITHMPC 174 tuple = PyTuple_New(23); 175#else 176 tuple = PyTuple_New(18); 177#endif 178 if (!tuple) return NULL; 179 180#ifdef WITHMPC 181 format = Py2or3String_FromString( 182 "context(precision=%s, real_prec=%s, imag_prec=%s,\n" 183 " round=%s, real_round=%s, imag_round=%s,\n" 184 " emax=%s, emin=%s,\n" 185 " subnormalize=%s,\n" 186 " trap_underflow=%s, underflow=%s,\n" 187 " trap_overflow=%s, overflow=%s,\n" 188 " trap_inexact=%s, inexact=%s,\n" 189 " trap_invalid=%s, invalid=%s,\n" 190 " trap_erange=%s, erange=%s,\n" 191 " trap_divzero=%s, divzero=%s,\n" 192 " trap_expbound=%s,\n" 193 " allow_complex=%s)" 194 ); 195#else 196 format = Py2or3String_FromString( 197 "context(precision=%s,\n" 198 " round=%s,\n" 199 " emax=%s, emin=%s,\n" 200 " subnormalize=%s,\n" 201 " trap_underflow=%s, underflow=%s,\n" 202 " trap_overflow=%s, overflow=%s,\n" 203 " trap_inexact=%s, inexact=%s,\n" 204 " trap_invalid=%s, invalid=%s,\n" 205 " trap_erange=%s, erange=%s,\n" 206 " trap_divzero=%s, divzero=%s,\n" 207 " trap_expbound=%s)" 208 ); 209#endif 210 if (!format) { 211 Py_DECREF(tuple); 212 return NULL; 213 } 214 215 PyTuple_SET_ITEM(tuple, i++, PyIntOrLong_FromLong(self->ctx.mpfr_prec)); 216#ifdef WITHMPC 217 if (self->ctx.real_prec == GMPY_DEFAULT) 218 PyTuple_SET_ITEM(tuple, i++, Py2or3String_FromString("Default")); 219 else 220 PyTuple_SET_ITEM(tuple, i++, PyIntOrLong_FromLong(self->ctx.real_prec)); 221 if (self->ctx.imag_prec == GMPY_DEFAULT) 222 PyTuple_SET_ITEM(tuple, i++, Py2or3String_FromString("Default")); 223 else 224 PyTuple_SET_ITEM(tuple, i++, PyIntOrLong_FromLong(self->ctx.imag_prec)); 225#endif 226 PyTuple_SET_ITEM(tuple, i++, _round_to_name(self->ctx.mpfr_round)); 227#ifdef WITHMPC 228 PyTuple_SET_ITEM(tuple, i++, _round_to_name(self->ctx.real_round)); 229 PyTuple_SET_ITEM(tuple, i++, _round_to_name(self->ctx.imag_round)); 230#endif 231 PyTuple_SET_ITEM(tuple, i++, PyIntOrLong_FromLong(self->ctx.emax)); 232 PyTuple_SET_ITEM(tuple, i++, PyIntOrLong_FromLong(self->ctx.emin)); 233 PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.subnormalize)); 234 PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_underflow)); 235 PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.underflow)); 236 PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_overflow)); 237 PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.overflow)); 238 PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_inexact)); 239 PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.inexact)); 240 PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_invalid)); 241 PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.invalid)); 242 PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_erange)); 243 PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.erange)); 244 PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_divzero)); 245 PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.divzero)); 246 PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_expbound)); 247#ifdef WITHMPC 248 PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.allow_complex)); 249#endif 250 251 if (!PyErr_Occurred()) 252 result = Py2or3String_Format(format, tuple); 253 else 254 SYSTEM_ERROR("internal error in GMPyContext_repr"); 255 256 Py_DECREF(format); 257 Py_DECREF(tuple); 258 return result; 259}; 260 261static PyObject * 262GMPyContextManager_repr(GMPyContextManagerObject *self) 263{ 264 return Py_BuildValue("s", "<gmpy2.ContextManagerObject>"); 265} 266 267PyDoc_STRVAR(doc_get_context, 268"get_context() -> gmpy2 context\n\n" 269"Return a reference to the current context."); 270 271static PyObject * 272GMPyContext_get_context(PyObject *self, PyObject *args) 273{ 274 Py_INCREF((PyObject*)context); 275 return (PyObject*)context; 276} 277 278PyDoc_STRVAR(doc_context_copy, 279"context.copy() -> gmpy2 context\n\n" 280"Return a copy of a context."); 281 282static PyObject * 283GMPyContext_context_copy(PyObject *self, PyObject *other) 284{ 285 GMPyContextObject *result; 286 287 result = (GMPyContextObject*)GMPyContext_new(); 288 result->ctx = ((GMPyContextObject*)self)->ctx; 289 return (PyObject*)result; 290} 291 292PyDoc_STRVAR(doc_local_context, 293"local_context([context[,keywords]]) -> context manager\n\n" 294"Create a context manager object that will restore the current context\n" 295"when the 'with ...' block terminates. The temporary context for the\n" 296"'with ...' block is based on the current context if no context is\n" 297"specified. Keyword arguments are supported and will modify the\n" 298"temporary new context."); 299 300static PyObject * 301GMPyContext_local_context(PyObject *self, PyObject *args, PyObject *kwargs) 302{ 303 GMPyContextManagerObject *result; 304 PyObject *local_args = args; 305 int arg_context = 0; 306 307#ifdef WITHMPC 308 static char *kwlist[] = { 309 "precision", "real_prec", "imag_prec", "round", 310 "real_round", "imag_round", "emax", "emin", "subnormalize", 311 "trap_underflow", "trap_overflow", "trap_inexact", 312 "trap_invalid", "trap_erange", "trap_divzero", 313 "trap_expbound", "allow_complex", NULL }; 314#else 315 static char *kwlist[] = { 316 "precision", "round", "emax", "emin", "subnormalize", 317 "trap_underflow", "trap_overflow", "trap_inexact", 318 "trap_invalid", "trap_erange", "trap_divzero", "trap_expbound", 319 NULL }; 320#endif 321 322 if (PyTuple_GET_SIZE(args) == 1 && GMPyContext_Check(PyTuple_GET_ITEM(args, 0))) { 323 arg_context = 1; 324 if (!(local_args = PyTuple_New(0))) 325 return NULL; 326 } 327 else if (PyTuple_GET_SIZE(args)) { 328 VALUE_ERROR("local_context() only supports [context[,keyword]] arguments"); 329 return NULL; 330 } 331 332 if (!(result = (GMPyContextManagerObject*)GMPyContextManager_new())) 333 return NULL; 334 335 if (arg_context) { 336 result->new_ctx = ((GMPyContextObject*)PyTuple_GET_ITEM(args, 0))->ctx; 337 } 338 else { 339 result->new_ctx = context->ctx; 340 } 341 result->old_ctx = context->ctx; 342 343#ifdef WITHMPC 344 if (!(PyArg_ParseTupleAndKeywords(local_args, kwargs, 345 "|llliiilliiiiiiiii", kwlist, 346 &result->new_ctx.mpfr_prec, 347 &result->new_ctx.real_prec, 348 &result->new_ctx.imag_prec, 349 &result->new_ctx.mpfr_round, 350 &result->new_ctx.real_round, 351 &result->new_ctx.imag_round, 352 &result->new_ctx.emax, 353 &result->new_ctx.emin, 354 &result->new_ctx.subnormalize, 355 &result->new_ctx.trap_underflow, 356 &result->new_ctx.trap_overflow, 357 &result->new_ctx.trap_inexact, 358 &result->new_ctx.trap_invalid, 359 &result->new_ctx.trap_erange, 360 &result->new_ctx.trap_divzero, 361 &result->new_ctx.trap_expbound, 362 &result->new_ctx.allow_complex))) { 363#else 364 if (!(PyArg_ParseTupleAndKeywords(local_args, kwargs, 365 "|lilliiiiiiii", kwlist, 366 &result->new_ctx.mpfr_prec, 367 &result->new_ctx.mpfr_round, 368 &result->new_ctx.emax, 369 &result->new_ctx.emin, 370 &result->new_ctx.subnormalize, 371 &result->new_ctx.trap_underflow, 372 &result->new_ctx.trap_overflow, 373 &result->new_ctx.trap_inexact, 374 &result->new_ctx.trap_invalid, 375 &result->new_ctx.trap_erange, 376 &result->new_ctx.trap_divzero, 377 &result->new_ctx.trap_expbound))) { 378#endif 379 VALUE_ERROR("invalid keyword arguments in local_context()"); 380 goto error; 381 } 382 383 /* Sanity check for values. */ 384 if (result->new_ctx.mpfr_prec < MPFR_PREC_MIN || 385 result->new_ctx.mpfr_prec > MPFR_PREC_MAX) { 386 VALUE_ERROR("invalid value for precision"); 387 goto error; 388 } 389 390#ifdef WITHMPC 391 if (!(result->new_ctx.real_prec == GMPY_DEFAULT || 392 (result->new_ctx.real_prec >= MPFR_PREC_MIN && 393 result->new_ctx.real_prec <= MPFR_PREC_MAX))) { 394 VALUE_ERROR("invalid value for real_prec"); 395 goto error; 396 } 397 if (!(result->new_ctx.imag_prec == GMPY_DEFAULT || 398 (result->new_ctx.imag_prec >= MPFR_PREC_MIN && 399 result->new_ctx.imag_prec <= MPFR_PREC_MAX))) { 400 VALUE_ERROR("invalid value for imag_prec"); 401 goto error; 402 } 403#endif 404 405 if (!(result->new_ctx.mpfr_round == MPFR_RNDN || 406 result->new_ctx.mpfr_round == MPFR_RNDZ || 407 result->new_ctx.mpfr_round == MPFR_RNDU || 408 result->new_ctx.mpfr_round == MPFR_RNDD || 409 result->new_ctx.mpfr_round == MPFR_RNDA)) { 410 VALUE_ERROR("invalid value for round"); 411 goto error; 412 } 413 414#ifdef WITHMPC 415 if (result->new_ctx.mpfr_round == MPFR_RNDA) { 416 /* Since RNDA is not supported for MPC, set the MPC rounding modes 417 * to MPFR_RNDN. 418 */ 419 result->new_ctx.real_round = MPFR_RNDN; 420 result->new_ctx.imag_round = MPFR_RNDN; 421 } 422 if (!(result->new_ctx.real_round == MPFR_RNDN || 423 result->new_ctx.real_round == MPFR_RNDZ || 424 result->new_ctx.real_round == MPFR_RNDU || 425 result->new_ctx.real_round == MPFR_RNDD || 426 result->new_ctx.real_round == GMPY_DEFAULT)) { 427 VALUE_ERROR("invalid value for real_round"); 428 goto error; 429 } 430 if (!(result->new_ctx.imag_round == MPFR_RNDN || 431 result->new_ctx.imag_round == MPFR_RNDZ || 432 result->new_ctx.imag_round == MPFR_RNDU || 433 result->new_ctx.imag_round == MPFR_RNDD || 434 result->new_ctx.imag_round == GMPY_DEFAULT)) { 435 VALUE_ERROR("invalid value for imag_round"); 436 goto error; 437 } 438#endif 439 440 if (!(result->new_ctx.emin < 0 && result->new_ctx.emax > 0)) { 441 VALUE_ERROR("invalid values for emin and/or emax"); 442 goto error; 443 } 444 445 if (mpfr_set_emin(result->new_ctx.emin)) { 446 VALUE_ERROR("invalid value for emin"); 447 goto error; 448 } 449 if (mpfr_set_emax(result->new_ctx.emax)) { 450 VALUE_ERROR("invalid value for emax"); 451 goto error; 452 } 453 454 if (arg_context) { 455 Py_DECREF(local_args); 456 } 457 return (PyObject*)result; 458 459 error: 460 if (arg_context) { 461 Py_DECREF(local_args); 462 } 463 Py_DECREF((PyObject*)result); 464 return NULL; 465} 466 467#ifdef WITHMPC 468 469PyDoc_STRVAR(doc_context, 470"context() -> context manager\n\n" 471"Return a new context for controlling MPFR and MPC arithmetic. To load\n" 472"the new context, use set_context(). Options can only be specified as\n" 473"keyword arguments. \n\n" 474" precision: precision, in bits, of an MPFR result\n" 475" real_prec: precision, in bits, of Re(MPC)\n" 476" -1 implies use mpfr_prec\n" 477" imag_prec: precision, in bits, of Im(MPC)\n" 478" -1 implies use real_prec\n" 479" round: rounding mode for MPFR\n" 480" real_round: rounding mode for Re(MPC)\n" 481" -1 implies use mpfr_round\n" 482" imag_round: rounding mode for Im(MPC)\n" 483" -1 implies use real_round\n" 484" e_max: maximum allowed exponent\n" 485" e_min: minimum allowed exponent\n" 486" subnormalize: if True, subnormalized results can be returned\n" 487" trap_underflow: if True, raise exception for underflow\n" 488" if False, set underflow flag\n" 489" trap_overflow: if True, raise exception for overflow\n" 490" if False, set overflow flag and return Inf or -Inf\n" 491" trap_inexact: if True, raise exception for inexact result\n" 492" if False, set inexact flag\n" 493" trap_invalid: if True, raise exception for invalid operation\n" 494" if False, set invalid flag and return NaN\n" 495" trap_erange: if True, raise exception for range error\n" 496" if False, set erange flag\n" 497" trap_divzero: if True, raise exception for division by zero\n" 498" if False, set divzero flag and return Inf or -Inf\n" 499" trap_expbound: if True, raise exception when mpfr/mpc exponent\n" 500" no longer valid in current context\n" 501" if False, mpfr/mpc with exponent out-of-bounds\n" 502" will be coerced to either 0 or Infinity\n" 503" allow_complex: if True, allow mpfr functions to return mpc\n" 504" if False, mpfr functions cannot return an mpc\n"); 505 506#else 507 508PyDoc_STRVAR(doc_context, 509"context() -> context\n\n" 510"Return a new context for controlling MPFR arithmetic. To load the\n" 511"new context, use set_context(). Options can only be specified as\n" 512"keyword arguments. \n\n" 513" precision: precision, in bits, of an MPFR result\n" 514" round: rounding mode for MPFR\n" 515" e_max: maximum allowed exponent\n" 516" e_min: minimum allowed exponent\n" 517" subnormalize: if True, subnormalized results can be returned\n" 518" trap_underflow: if True, raise exception for underflow\n" 519" if False, set underflow flag\n" 520" trap_overflow: if True, raise exception for overflow\n" 521" if False, set overflow flag and return Inf or -Inf\n" 522" trap_inexact: if True, raise exception for inexact result\n" 523" if False, set inexact flag\n" 524" trap_invalid: if True, raise exception for invalid operation\n" 525" if False, set invalid flag and return NaN\n" 526" trap_erange: if True, raise exception for range error\n" 527" if False, set erange flag\n" 528" trap_divzero: if True, raise exception for division by zero\n" 529" if False, set divzero flag and return Inf or -Inf\n" 530" trap_expbound: if True, raise exception when mpfr/mpc exponent\n" 531" no longer valid in current context\n" 532" if False, mpfr/mpc with exponent out-of-bounds will\n" 533" coerced to either 0 or Infinity\n"); 534 535#endif 536 537static PyObject * 538GMPyContext_context(PyObject *self, PyObject *args, PyObject *kwargs) 539{ 540 GMPyContextObject *result; 541 542#ifdef WITHMPC 543 static char *kwlist[] = { 544 "precision", "real_prec", "imag_prec", "round", 545 "real_round", "imag_round", "emax", "emin", "subnormalize", 546 "trap_underflow", "trap_overflow", "trap_inexact", 547 "trap_invalid", "trap_erange", "trap_divzero", "trap_expbound", 548 "allow_complex", NULL }; 549#else 550 static char *kwlist[] = { 551 "precision", "round", "emax", "emin", "subnormalize", 552 "trap_underflow", "trap_overflow", "trap_inexact", 553 "trap_invalid", "trap_erange", "trap_divzero", 554 "trap_expbound", NULL }; 555#endif 556 557 if (PyTuple_GET_SIZE(args)) { 558 VALUE_ERROR("context() only supports keyword arguments"); 559 return NULL; 560 } 561 562 if (!(result = (GMPyContextObject*)GMPyContext_new())) 563 return NULL; 564 565#ifdef WITHMPC 566 if (!(PyArg_ParseTupleAndKeywords(args, kwargs, 567 "|llliiilliiiiiiiii", kwlist, 568 &result->ctx.mpfr_prec, 569 &result->ctx.real_prec, 570 &result->ctx.imag_prec, 571 &result->ctx.mpfr_round, 572 &result->ctx.real_round, 573 &result->ctx.imag_round, 574 &result->ctx.emax, 575 &result->ctx.emin, 576 &result->ctx.subnormalize, 577 &result->ctx.trap_underflow, 578 &result->ctx.trap_overflow, 579 &result->ctx.trap_inexact, 580 &result->ctx.trap_invalid, 581 &result->ctx.trap_erange, 582 &result->ctx.trap_divzero, 583 &result->ctx.trap_expbound, 584 &result->ctx.allow_complex))) { 585#else 586 if (!(PyArg_ParseTupleAndKeywords(args, kwargs, 587 "|lilliiiiiiii", kwlist, 588 &result->ctx.mpfr_prec, 589 &result->ctx.mpfr_round, 590 &result->ctx.emax, 591 &result->ctx.emin, 592 &result->ctx.subnormalize, 593 &result->ctx.trap_underflow, 594 &result->ctx.trap_overflow, 595 &result->ctx.trap_inexact, 596 &result->ctx.trap_invalid, 597 &result->ctx.trap_erange, 598 &result->ctx.trap_divzero, 599 &result->ctx.trap_expbound))) { 600#endif 601 VALUE_ERROR("invalid keyword arguments in context()"); 602 return NULL; 603 } 604 605 /* Sanity check for values. */ 606 if (result->ctx.mpfr_prec < MPFR_PREC_MIN || 607 result->ctx.mpfr_prec > MPFR_PREC_MAX) { 608 Py_DECREF((PyObject*)result); 609 VALUE_ERROR("invalid value for precision"); 610 return NULL; 611 } 612 613#ifdef WITHMPC 614 if (!(result->ctx.real_prec == GMPY_DEFAULT || 615 (result->ctx.real_prec >= MPFR_PREC_MIN && 616 result->ctx.real_prec <= MPFR_PREC_MAX))) { 617 Py_DECREF((PyObject*)result); 618 VALUE_ERROR("invalid value for real_prec"); 619 return NULL; 620 } 621 if (!(result->ctx.imag_prec == GMPY_DEFAULT || 622 (result->ctx.imag_prec >= MPFR_PREC_MIN && 623 result->ctx.imag_prec <= MPFR_PREC_MAX))) { 624 Py_DECREF((PyObject*)result); 625 VALUE_ERROR("invalid value for imag_prec"); 626 return NULL; 627 } 628#endif 629 630 if (!(result->ctx.mpfr_round == MPFR_RNDN || 631 result->ctx.mpfr_round == MPFR_RNDZ || 632 result->ctx.mpfr_round == MPFR_RNDU || 633 result->ctx.mpfr_round == MPFR_RNDD || 634 result->ctx.mpfr_round == MPFR_RNDA)) { 635 Py_DECREF((PyObject*)result); 636 VALUE_ERROR("invalid value for round"); 637 return NULL; 638 } 639 640#ifdef WITHMPC 641 if (result->ctx.mpfr_round == MPFR_RNDA) { 642 /* Since RNDA is not supported for MPC, set the MPC rounding modes 643 to MPFR_RNDN. */ 644 result->ctx.real_round = MPFR_RNDN; 645 result->ctx.imag_round = MPFR_RNDN; 646 } 647 if (!(result->ctx.real_round == MPFR_RNDN || 648 result->ctx.real_round == MPFR_RNDZ || 649 result->ctx.real_round == MPFR_RNDU || 650 result->ctx.real_round == MPFR_RNDD || 651 result->ctx.real_round == GMPY_DEFAULT)) { 652 Py_DECREF((PyObject*)result); 653 VALUE_ERROR("invalid value for real_round"); 654 return NULL; 655 } 656 if (!(result->ctx.imag_round == MPFR_RNDN || 657 result->ctx.imag_round == MPFR_RNDZ || 658 result->ctx.imag_round == MPFR_RNDU || 659 result->ctx.imag_round == MPFR_RNDD || 660 result->ctx.imag_round == GMPY_DEFAULT)) { 661 Py_DECREF((PyObject*)result); 662 VALUE_ERROR("invalid value for imag_round"); 663 return NULL; 664 } 665#endif 666 667 if (!(result->ctx.emin < 0 && result->ctx.emax > 0)) { 668 VALUE_ERROR("invalid values for emin and/or emax"); 669 Py_DECREF((PyObject*)result); 670 return NULL; 671 } 672 673 if (mpfr_set_emin(result->ctx.emin)) { 674 VALUE_ERROR("invalid value for emin"); 675 Py_DECREF((PyObject*)result); 676 return NULL; 677 } 678 if (mpfr_set_emax(result->ctx.emax)) { 679 VALUE_ERROR("invalid value for emax"); 680 Py_DECREF((PyObject*)result); 681 return NULL; 682 } 683 684 result->ctx.underflow = 0; 685 result->ctx.overflow = 0; 686 result->ctx.inexact = 0; 687 result->ctx.invalid = 0; 688 result->ctx.erange = 0; 689 result->ctx.divzero = 0; 690 return (PyObject*)result; 691} 692 693PyDoc_STRVAR(doc_set_context, 694"set_context(context)\n\n" 695"Activate a context object controlling MPFR and MPC arithmetic.\n"); 696 697static PyObject * 698GMPyContext_set_context(PyObject *self, PyObject *other) 699{ 700 if (GMPyContext_Check(other)) { 701 Py_INCREF((PyObject*)other); 702 Py_DECREF((PyObject*)context); 703 context = (GMPyContextObject*)other; 704 mpfr_set_emin(context->ctx.emin); 705 mpfr_set_emax(context->ctx.emax); 706 Py_RETURN_NONE; 707 } 708 else { 709 VALUE_ERROR("set_context() requires a context argument"); 710 return NULL; 711 } 712} 713 714static PyObject * 715GMPyContextManager_enter(PyObject *self, PyObject *args) 716{ 717 GMPyContextObject *result; 718 719 if (!(result = (GMPyContextObject*)GMPyContext_new())) 720 return NULL; 721 722 result->ctx = ((GMPyContextManagerObject*)self)->new_ctx; 723 Py_DECREF((PyObject*)context); 724 context = (GMPyContextObject*)result; 725 Py_INCREF((PyObject*)context); 726 mpfr_set_emin(context->ctx.emin); 727 mpfr_set_emax(context->ctx.emax); 728 return (PyObject*)result; 729} 730 731static PyObject * 732GMPyContextManager_exit(PyObject *self, PyObject *args) 733{ 734 GMPyContextObject *result; 735 736 if (!(result = (GMPyContextObject*)GMPyContext_new())) 737 return NULL; 738 739 result->ctx = ((GMPyContextManagerObject*)self)->old_ctx; 740 Py_DECREF((PyObject*)context); 741 context = (GMPyContextObject*)result; 742 mpfr_set_emin(context->ctx.emin); 743 mpfr_set_emax(context->ctx.emax); 744 Py_RETURN_NONE; 745} 746 747static PyObject * 748GMPyContext_enter(PyObject *self, PyObject *args) 749{ 750 GMPyContextObject *result; 751 752 if (!(result = (GMPyContextObject*)GMPyContext_new())) 753 return NULL; 754 755 result->ctx = ((GMPyContextObject*)self)->ctx; 756 Py_DECREF((PyObject*)context); 757 context = (GMPyContextObject*)result; 758 Py_INCREF((PyObject*)context); 759 mpfr_set_emin(context->ctx.emin); 760 mpfr_set_emax(context->ctx.emax); 761 return (PyObject*)result; 762} 763 764static PyObject * 765GMPyContext_exit(PyObject *self, PyObject *args) 766{ 767 Py_DECREF((PyObject*)context); 768 context = (GMPyContextObject*)self; 769 Py_INCREF((PyObject*)context); 770 mpfr_set_emin(context->ctx.emin); 771 mpfr_set_emax(context->ctx.emax); 772 Py_RETURN_NONE; 773} 774 775PyDoc_STRVAR(doc_context_clear_flags, 776"clear_flags()\n\n" 777"Clear all MPFR exception flags."); 778static PyObject * 779GMPyContext_clear_flags(PyObject *self, PyObject *args) 780{ 781 ((GMPyContextObject*)self)->ctx.underflow = 0; 782 ((GMPyContextObject*)self)->ctx.overflow = 0; 783 ((GMPyContextObject*)self)->ctx.inexact = 0; 784 ((GMPyContextObject*)self)->ctx.invalid = 0; 785 ((GMPyContextObject*)self)->ctx.erange = 0; 786 ((GMPyContextObject*)self)->ctx.divzero = 0; 787 Py_RETURN_NONE; 788} 789 790/* Define the get/set functions. */ 791 792#define GETSET_BOOLEAN(NAME) \ 793static PyObject * \ 794GMPyContext_get_##NAME(GMPyContextObject *self, void *closure) \ 795{ \ 796 return PyBool_FromLong(self->ctx.NAME); \ 797}; \ 798static int \ 799GMPyContext_set_##NAME(GMPyContextObject *self, PyObject *value, void *closure) \ 800{ \ 801 if (!(PyBool_Check(value))) { \ 802 TYPE_ERROR(#NAME " must be True or False"); \ 803 return -1; \ 804 } \ 805 self->ctx.NAME = (value == Py_True) ? 1 : 0; \ 806 return 0; \ 807} 808 809GETSET_BOOLEAN(subnormalize); 810GETSET_BOOLEAN(underflow); 811GETSET_BOOLEAN(overflow); 812GETSET_BOOLEAN(inexact); 813GETSET_BOOLEAN(invalid); 814GETSET_BOOLEAN(erange); 815GETSET_BOOLEAN(divzero); 816GETSET_BOOLEAN(trap_underflow); 817GETSET_BOOLEAN(trap_overflow); 818GETSET_BOOLEAN(trap_inexact); 819GETSET_BOOLEAN(trap_invalid); 820GETSET_BOOLEAN(trap_erange); 821GETSET_BOOLEAN(trap_divzero); 822GETSET_BOOLEAN(trap_expbound); 823#ifdef WITHMPC 824GETSET_BOOLEAN(allow_complex) 825#endif 826 827static PyObject * 828GMPyContext_get_precision(GMPyContextObject *self, void *closure) 829{ 830 return PyIntOrLong_FromSsize_t((Py_ssize_t)(self->ctx.mpfr_prec)); 831} 832 833static int 834GMPyContext_set_precision(GMPyContextObject *self, PyObject *value, void *closure) 835{ 836 Py_ssize_t temp; 837 838 if (!(PyIntOrLong_Check(value))) { 839 TYPE_ERROR("precision must be Python integer"); 840 return -1; 841 } 842 temp = PyIntOrLong_AsSsize_t(value); 843 if (temp < MPFR_PREC_MIN || temp > MPFR_PREC_MAX || PyErr_Occurred()) { 844 VALUE_ERROR("invalid value for precision"); 845 return -1; 846 } 847 self->ctx.mpfr_prec = (mpfr_prec_t)temp; 848 return 0; 849} 850 851#ifdef WITHMPC 852static PyObject * 853GMPyContext_get_real_prec(GMPyContextObject *self, void *closure) 854{ 855 return PyIntOrLong_FromSsize_t((Py_ssize_t)(GET_REAL_PREC(self))); 856} 857 858static int 859GMPyContext_set_real_prec(GMPyContextObject *self, PyObject *value, void *closure) 860{ 861 Py_ssize_t temp; 862 863 if (!(PyIntOrLong_Check(value))) { 864 TYPE_ERROR("real_prec must be Python integer"); 865 return -1; 866 } 867 temp = PyIntOrLong_AsSsize_t(value); 868 if (temp == -1) { 869 if (PyErr_Occurred()) { 870 VALUE_ERROR("invalid value for real_prec"); 871 return -1; 872 } 873 } 874 else if (temp < MPFR_PREC_MIN || temp > MPFR_PREC_MAX) { 875 VALUE_ERROR("invalid value for real_prec"); 876 return -1; 877 } 878 self->ctx.real_prec = (mpfr_prec_t)temp; 879 return 0; 880} 881 882static PyObject * 883GMPyContext_get_imag_prec(GMPyContextObject *self, void *closure) 884{ 885 return PyIntOrLong_FromSsize_t((Py_ssize_t)(GET_IMAG_PREC(self))); 886} 887 888static int 889GMPyContext_set_imag_prec(GMPyContextObject *self, PyObject *value, void *closure) 890{ 891 Py_ssize_t temp; 892 893 if (!(PyIntOrLong_Check(value))) { 894 TYPE_ERROR("imag_prec must be Python integer"); 895 return -1; 896 } 897 temp = PyIntOrLong_AsSsize_t(value); 898 if (temp == -1) { 899 if (PyErr_Occurred()) { 900 VALUE_ERROR("invalid value for imag_prec"); 901 return -1; 902 } 903 } 904 else if (temp < MPFR_PREC_MIN || temp > MPFR_PREC_MAX) { 905 VALUE_ERROR("invalid value for imag_prec"); 906 return -1; 907 } 908 self->ctx.imag_prec = (mpfr_prec_t)temp; 909 return 0; 910} 911#endif 912 913static PyObject * 914GMPyContext_get_round(GMPyContextObject *self, void *closure) 915{ 916 return PyIntOrLong_FromLong((long)(self->ctx.mpfr_round)); 917} 918 919static int 920GMPyContext_set_round(GMPyContextObject *self, PyObject *value, void *closure) 921{ 922 long temp; 923 924 if (!(PyIntOrLong_Check(value))) { 925 TYPE_ERROR("round mode must be Python integer"); 926 return -1; 927 } 928 temp = PyIntOrLong_AsLong(value); 929 if (temp == -1 && PyErr_Occurred()) { 930 VALUE_ERROR("invalid value for round mode"); 931 return -1; 932 } 933 if (temp == MPFR_RNDN) 934 self->ctx.mpfr_round = MPFR_RNDN; 935 else if (temp == MPFR_RNDZ) 936 self->ctx.mpfr_round = MPFR_RNDZ; 937 else if (temp == MPFR_RNDU) 938 self->ctx.mpfr_round = MPFR_RNDU; 939 else if (temp == MPFR_RNDD) 940 self->ctx.mpfr_round = MPFR_RNDD; 941 else if (temp == MPFR_RNDA) { 942 self->ctx.mpfr_round = MPFR_RNDA; 943#ifdef WITHMPC 944 /* Since RNDA is not supported for MPC, set the MPC rounding modes 945 to MPFR_RNDN. */ 946 self->ctx.real_round = MPFR_RNDN; 947 self->ctx.imag_round = MPFR_RNDN; 948#endif 949 } 950 else { 951 VALUE_ERROR("invalid value for round mode"); 952 return -1; 953 } 954 return 0; 955} 956 957#ifdef WITHMPC 958static PyObject * 959GMPyContext_get_real_round(GMPyContextObject *self, void *closure) 960{ 961 return PyIntOrLong_FromLong((long)GET_REAL_ROUND(self)); 962} 963 964static int 965GMPyContext_set_real_round(GMPyContextObject *self, PyObject *value, void *closure) 966{ 967 long temp; 968 969 if (!(PyIntOrLong_Check(value))) { 970 TYPE_ERROR("round mode must be Python integer"); 971 return -1; 972 } 973 temp = PyIntOrLong_AsLong(value); 974 if (temp == -1 && PyErr_Occurred()) { 975 VALUE_ERROR("invalid value for round mode"); 976 return -1; 977 } 978 if (temp == GMPY_DEFAULT || temp == MPFR_RNDN || temp == MPFR_RNDZ || 979 temp == MPFR_RNDU || temp == MPFR_RNDD) { 980 self->ctx.real_round = (int)temp; 981 } 982 else { 983 VALUE_ERROR("invalid value for round mode"); 984 return -1; 985 } 986 return 0; 987} 988 989static PyObject * 990GMPyContext_get_imag_round(GMPyContextObject *self, void *closure) 991{ 992 return PyIntOrLong_FromLong((long)GET_IMAG_ROUND(self)); 993} 994 995static int 996GMPyContext_set_imag_round(GMPyContextObject *self, PyObject *value, void *closure) 997{ 998 long temp; 999 1000 if (!(PyIntOrLong_Check(value))) { 1001 TYPE_ERROR("round mode must be Python integer"); 1002 return -1; 1003 } 1004 temp = PyIntOrLong_AsLong(value); 1005 if (temp == -1 && PyErr_Occurred()) { 1006 VALUE_ERROR("invalid value for round mode"); 1007 return -1; 1008 } 1009 if (temp == GMPY_DEFAULT || temp == MPFR_RNDN || temp == MPFR_RNDZ || 1010 temp == MPFR_RNDU || temp == MPFR_RNDD) { 1011 self->ctx.imag_round = (int)temp; 1012 } 1013 else { 1014 VALUE_ERROR("invalid value for round mode"); 1015 return -1; 1016 } 1017 return 0; 1018} 1019#endif 1020 1021static PyObject * 1022GMPyContext_get_emin(GMPyContextObject *self, void *closure) 1023{ 1024 return PyIntOrLong_FromLong(self->ctx.emin); 1025} 1026 1027static int 1028GMPyContext_set_emin(GMPyContextObject *self, PyObject *value, void *closure) 1029{ 1030 long exp; 1031 1032 if (!(PyIntOrLong_Check(value))) { 1033 TYPE_ERROR("emin must be Python integer"); 1034 return -1; 1035 } 1036 exp = PyIntOrLong_AsLong(value); 1037 if (exp == -1 && PyErr_Occurred()) { 1038 VALUE_ERROR("requested minimum exponent is invalid"); 1039 return -1; 1040 } 1041 if (mpfr_set_emin((mpfr_prec_t)exp)) { 1042 VALUE_ERROR("requested minimum exponent is invalid"); 1043 return -1; 1044 } 1045 self->ctx.emin = exp; 1046 mpfr_set_emin(exp); 1047 return 0; 1048} 1049 1050static PyObject * 1051GMPyContext_get_emax(GMPyContextObject *self, void *closure) 1052{ 1053 return PyIntOrLong_FromLong(self->ctx.emax); 1054} 1055 1056static int 1057GMPyContext_set_emax(GMPyContextObject *self, PyObject *value, void *closure) 1058{ 1059 long exp; 1060 1061 if (!(PyIntOrLong_Check(value))) { 1062 TYPE_ERROR("emax must be Python integer"); 1063 return -1; 1064 } 1065 exp = PyIntOrLong_AsLong(value); 1066 if (exp == -1 && PyErr_Occurred()) { 1067 VALUE_ERROR("requested maximum exponent is invalid"); 1068 return -1; 1069 } 1070 if (mpfr_set_emax((mpfr_prec_t)exp)) { 1071 VALUE_ERROR("requested maximum exponent is invalid"); 1072 return -1; 1073 } 1074 self->ctx.emax = exp; 1075 mpfr_set_emax(exp); 1076 return 0; 1077} 1078 1079#define ADD_GETSET(NAME) \ 1080 {#NAME, \ 1081 (getter)GMPyContext_get_##NAME, \ 1082 (setter)GMPyContext_set_##NAME, NULL, NULL} 1083 1084static PyGetSetDef GMPyContext_getseters[] = { 1085 ADD_GETSET(precision), 1086#ifdef WITHMPC 1087 ADD_GETSET(real_prec), 1088 ADD_GETSET(imag_prec), 1089#endif 1090 ADD_GETSET(round), 1091#ifdef WITHMPC 1092 ADD_GETSET(real_round), 1093 ADD_GETSET(imag_round), 1094#endif 1095 ADD_GETSET(emax), 1096 ADD_GETSET(emin), 1097 ADD_GETSET(subnormalize), 1098 ADD_GETSET(underflow), 1099 ADD_GETSET(overflow), 1100 ADD_GETSET(inexact), 1101 ADD_GETSET(invalid), 1102 ADD_GETSET(erange), 1103 ADD_GETSET(divzero), 1104 ADD_GETSET(trap_underflow), 1105 ADD_GETSET(trap_overflow), 1106 ADD_GETSET(trap_inexact), 1107 ADD_GETSET(trap_invalid), 1108 ADD_GETSET(trap_erange), 1109 ADD_GETSET(trap_divzero), 1110 ADD_GETSET(trap_expbound), 1111#ifdef WITHMPC 1112 ADD_GETSET(allow_complex), 1113#endif 1114 {NULL} 1115}; 1116 1117static PyMethodDef GMPyContext_methods[] = 1118{ 1119 { "clear_flags", GMPyContext_clear_flags, METH_NOARGS, 1120 doc_context_clear_flags }, 1121 { "copy", GMPyContext_context_copy, METH_NOARGS, doc_context_copy }, 1122 { "__enter__", GMPyContext_enter, METH_NOARGS, NULL }, 1123 { "__exit__", GMPyContext_exit, METH_VARARGS, NULL }, 1124 { NULL, NULL, 1 } 1125}; 1126 1127static PyTypeObject GMPyContext_Type = 1128{ 1129#ifdef PY3 1130 PyVarObject_HEAD_INIT(0, 0) 1131#else 1132 PyObject_HEAD_INIT(0) 1133 0, /* ob_size */ 1134#endif 1135 "gmpy2 context", /* tp_name */ 1136 sizeof(GMPyContextObject), /* tp_basicsize */ 1137 0, /* tp_itemsize */ 1138 (destructor) GMPyContext_dealloc, /* tp_dealloc */ 1139 0, /* tp_print */ 1140 0, /* tp_getattr */ 1141 0, /* tp_setattr */ 1142 0, /* tp_reserved */ 1143 (reprfunc) GMPyContext_repr, /* tp_repr */ 1144 0, /* tp_as_number */ 1145 0, /* tp_as_sequence */ 1146 0, /* tp_as_mapping */ 1147 0, /* tp_hash */ 1148 0, /* tp_call */ 1149 0, /* tp_str */ 1150 0, /* tp_getattro */ 1151 0, /* tp_setattro */ 1152 0, /* tp_as_buffer */ 1153 Py_TPFLAGS_DEFAULT, /* tp_flags */ 1154 "GMPY2 Context Object", /* tp_doc */ 1155 0, /* tp_traverse */ 1156 0, /* tp_clear */ 1157 0, /* tp_richcompare */ 1158 0, /* tp_weaklistoffset*/ 1159 0, /* tp_iter */ 1160 0, /* tp_iternext */ 1161 GMPyContext_methods, /* tp_methods */ 1162 0, /* tp_members */ 1163 GMPyContext_getseters, /* tp_getset */ 1164}; 1165 1166static PyMethodDef GMPyContextManager_methods[] = 1167{ 1168 { "__enter__", GMPyContextManager_enter, METH_NOARGS, NULL }, 1169 { "__exit__", GMPyContextManager_exit, METH_VARARGS, NULL }, 1170 { NULL, NULL, 1 } 1171}; 1172 1173static PyTypeObject GMPyContextManager_Type = 1174{ 1175#ifdef PY3 1176 PyVarObject_HEAD_INIT(0, 0) 1177#else 1178 PyObject_HEAD_INIT(0) 1179 0, /* ob_size */ 1180#endif 1181 "gmpy2 context", /* tp_name */ 1182 sizeof(GMPyContextManagerObject), /* tp_basicsize */ 1183 0, /* tp_itemsize */ 1184 (destructor) GMPyContextManager_dealloc, /* tp_dealloc */ 1185 0, /* tp_print */ 1186 0, /* tp_getattr */ 1187 0, /* tp_setattr */ 1188 0, /* tp_reserved */ 1189 (reprfunc) GMPyContextManager_repr, /* tp_repr */ 1190 0, /* tp_as_number */ 1191 0, /* tp_as_sequence */ 1192 0, /* tp_as_mapping */ 1193 0, /* tp_hash */ 1194 0, /* tp_call */ 1195 0, /* tp_str */ 1196 0, /* tp_getattro */ 1197 0, /* tp_setattro */ 1198 0, /* tp_as_buffer */ 1199 Py_TPFLAGS_DEFAULT, /* tp_flags */ 1200 "GMPY2 Context manager", /* tp_doc */ 1201 0, /* tp_traverse */ 1202 0, /* tp_clear */ 1203 0, /* tp_richcompare */ 1204 0, /* tp_weaklistoffset*/ 1205 0, /* tp_iter */ 1206 0, /* tp_iternext */ 1207 GMPyContextManager_methods, /* tp_methods */ 1208 0, /* tp_members */ 1209 0, /* tp_getset */ 1210};